Atlas › Test

extHostMcp.test|title=ExtHostMcp IAuthMetadata properties should allow undefined scopes|occurrence=1

Exact test identity: mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostMcp.test|title=ExtHostMcp IAuthMetadata properties should allow undefined scopes|occurrence=1

Package
mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common
Suite / test hierarchy
extHostMcp.test|title=ExtHostMcp IAuthMetadata properties should allow undefined scopes|occurrence=1
Test
extHostMcp.test|title=ExtHostMcp IAuthMetadata properties should allow undefined scopes|occurrence=1
Introduced at
extHostMcp.ts ×1 Frontier kind: Joint frontier
Covered ranges
5939
Covered lines
83693
Covered files
310

Co-introduced tests

1 other test enter at the same concept.

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/workbench/api/common/extHost.protocol.ts 4196 covered LOC · 3 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHost.protocol.ts
2 > * Copyright (c) Microsoft 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 { IRemoteConsoleLog } from '../../../base/common/console.js';
9 > import { SerializedError } from '../../../base/common/errors.js';
10 > import { IRelativePattern } from '../../../base/common/glob.js';
11 > import { IMarkdownString } from '../../../base/common/htmlContent.js';
12 > import { IJSONSchema } from '../../../base/common/jsonSchema.js';
13 > import { IDisposable } from '../../../base/common/lifecycle.js';
14 > import { IAuthorizationProtectedResourceMetadata, IAuthorizationServerMetadata, IAuthorizationTokenResponse } from '../../../base/common/oauth.js';
15 > import * as performance from '../../../base/common/performance.js';
16 > import Severity from '../../../base/common/severity.js';
17 > import { ThemeColor, ThemeIcon } from '../../../base/common/themables.js';
18 > import { URI, UriComponents, UriDto } from '../../../base/common/uri.js';
19 > import { RenderLineNumbersType, TextEditorCursorStyle } from '../../../editor/common/config/editorOptions.js';
20 > import { ISingleEditOperation } from '../../../editor/common/core/editOperation.js';
21 > import { IPosition } from '../../../editor/common/core/position.js';
22 > import { IRange } from '../../../editor/common/core/range.js';
23 > import { ISelection, Selection } from '../../../editor/common/core/selection.js';
24 > import { IChange } from '../../../editor/common/diff/legacyLinesDiffComputer.js';
25 > import * as editorCommon from '../../../editor/common/editorCommon.js';
26 > import { StandardTokenType } from '../../../editor/common/encodedTokenAttributes.js';
27 > import * as languages from '../../../editor/common/languages.js';
28 > import { CompletionItemLabel } from '../../../editor/common/languages.js';
29 > import { CharacterPair, CommentRule, EnterAction } from '../../../editor/common/languages/languageConfiguration.js';
30 > import { EndOfLineSequence } from '../../../editor/common/model.js';
31 > import { EditSuggestionId } from '../../../editor/common/textModelEditSource.js';
32 > import { ISerializedModelContentChangedEvent } from '../../../editor/common/textModelEvents.js';
33 > import { IAccessibilityInformation } from '../../../platform/accessibility/common/accessibility.js';
34 > import { ILocalizedString } from '../../../platform/action/common/action.js';
35 > import { ConfigurationTarget, IConfigurationChange, IConfigurationData, IConfigurationOverrides } from '../../../platform/configuration/common/configuration.js';
36 > import { ConfigurationScope } from '../../../platform/configuration/common/configurationRegistry.js';
37 > import { IEditorOptions } from '../../../platform/editor/common/editor.js';
38 > import { IExtensionIdWithVersion } from '../../../platform/extensionManagement/common/extensionStorage.js';
39 > import { ExtensionIdentifier, IExtensionDescription } from '../../../platform/extensions/common/extensions.js';
40 > import * as files from '../../../platform/files/common/files.js';
41 > import { ResourceLabelFormatter } from '../../../platform/label/common/label.js';
42 > import { ILoggerOptions, ILoggerResource, LogLevel } from '../../../platform/log/common/log.js';
43 > import { IMarkerData } from '../../../platform/markers/common/markers.js';
44 > import { IProgressOptions, IProgressStep } from '../../../platform/progress/common/progress.js';
45 > import * as quickInput from '../../../platform/quickinput/common/quickInput.js';
46 > import { IRemoteConnectionData, TunnelDescription } from '../../../platform/remote/common/remoteAuthorityResolver.js';
47 > import { AuthInfo, Credentials } from '../../../platform/request/common/request.js';
48 > import { ClassifiedEvent, IGDPRProperty, OmitMetadata, StrictPropertyCheck } from '../../../platform/telemetry/common/gdprTypings.js';
49 > import { TelemetryLevel } from '../../../platform/telemetry/common/telemetry.js';
50 > import { ISerializableEnvironmentDescriptionMap, ISerializableEnvironmentVariableCollection } from '../../../platform/terminal/common/environmentVariable.js';
51 > import { ICreateContributedTerminalProfileOptions, IProcessProperty, IProcessReadyWindowsPty, IShellLaunchConfigDto, ITerminalEnvironment, ITerminalLaunchError, ITerminalProfile, TerminalExitReason, TerminalLocation, TerminalShellType } from '../../../platform/terminal/common/terminal.js';
52 > import { ProvidedPortAttributes, TunnelCreationOptions, TunnelOptions, TunnelPrivacyId, TunnelProviderFeatures } from '../../../platform/tunnel/common/tunnel.js';
53 > import { ITunnelProxyInfo } from '../../../platform/tunnel/common/tunnelProxy.js';
54 > import { EditSessionIdentityMatch } from '../../../platform/workspace/common/editSessions.js';
55 > import { WorkspaceTrustRequestOptions } from '../../../platform/workspace/common/workspaceTrust.js';
56 > import { SaveReason } from '../../common/editor.js';
57 > import { IRevealOptions, ITreeItem, IViewBadge } from '../../common/views.js';
58 > import { CallHierarchyItem } from '../../contrib/callHierarchy/common/callHierarchy.js';
59 > import { IChatAgentMetadata, IChatAgentRequest, IChatAgentResult, UserSelectedTools } from '../../contrib/chat/common/participants/chatAgents.js';
60 > import { ICodeMapperRequest, ICodeMapperResult } from '../../contrib/chat/common/editing/chatCodeMapperService.js';
61 > import { IChatContextItem } from '../../contrib/chat/common/contextContrib/chatContext.js';
62 > import { IChatProgressHistoryResponseContent, IChatRequestModeInstructions, IChatRequestVariableData } from '../../contrib/chat/common/model/chatModel.js';
63 > import { ChatResponseClearToPreviousToolInvocationReason, IChatContentInlineReference, IChatExternalEditsDto, IChatFollowup, IChatMultiDiffData, IChatMultiDiffDataSerialized, IChatNotebookEdit, IChatProgress, IChatTask, IChatTaskDto, IChatUserActionEvent, IChatVoteAction } from '../../contrib/chat/common/chatService/chatService.js';
64 > import { IChatSessionItem, IChatSessionProviderOptionGroup, IChatSessionProviderOptionItem } from '../../contrib/chat/common/chatSessionsService.js';
65 > import { IChatRequestVariableValue } from '../../contrib/chat/common/attachments/chatVariables.js';
66 > import { ChatAgentLocation } from '../../contrib/chat/common/constants.js';
67 > import { IChatMessage, IChatResponsePart, ILanguageModelChatInfoOptions, ILanguageModelChatMetadataAndIdentifier, ILanguageModelChatRequestOptions, ILanguageModelChatSelector } from '../../contrib/chat/common/languageModels.js';
68 > import { IPreparedToolInvocation, IStreamedToolInvocation, IToolInvocation, IToolInvocationPreparationContext, IToolInvocationStreamContext, IToolProgressStep, IToolResult, ToolDataSource } from '../../contrib/chat/common/tools/languageModelToolsService.js';
69 > import { IPromptFileContext, IPromptFileResource } from '../../contrib/chat/common/promptSyntax/service/promptsService.js';
70 > import { DebugConfigurationProviderTriggerKind, IAdapterDescriptor, IConfig, IDebugSessionReplMode, IDebugTestRunReference, IDebugVisualization, IDebugVisualizationContext, IDebugVisualizationTreeItem, MainThreadDebugVisualization } from '../../contrib/debug/common/debug.js';
71 > import { McpCollectionDefinition, McpConnectionState, McpServerDefinition, McpServerLaunch } from '../../contrib/mcp/common/mcpTypes.js';
72 > import * as notebookCommon from '../../contrib/notebook/common/notebookCommon.js';
73 > import { CellExecutionUpdateType } from '../../contrib/notebook/common/notebookExecutionService.js';
74 > import { ICellExecutionComplete, ICellExecutionStateUpdate } from '../../contrib/notebook/common/notebookExecutionStateService.js';
75 > import { ICellRange } from '../../contrib/notebook/common/notebookRange.js';
76 > import { ISCMHistoryOptions } from '../../contrib/scm/common/history.js';
77 > import { InputValidationType } from '../../contrib/scm/common/scm.js';
78 > import { IWorkspaceSymbol, NotebookPriorityInfo } from '../../contrib/search/common/search.js';
79 > import { IRawClosedNotebookFileMatch } from '../../contrib/search/common/searchNotebookHelpers.js';
80 > import { IKeywordRecognitionEvent, ISpeechProviderMetadata, ISpeechToTextEvent, ITextToSpeechEvent } from '../../contrib/speech/common/speechService.js';
81 > import { CoverageDetails, ExtensionRunTestsRequest, ICallProfileRunHandler, IFileCoverage, ISerializedTestResults, IStartControllerTests, ITestItem, ITestMessage, ITestRunProfile, ITestRunTask, ResolvedTestRunRequest, TestControllerCapability, TestMessageFollowupRequest, TestMessageFollowupResponse, TestResultState, TestsDiffOp } from '../../contrib/testing/common/testTypes.js';
82 > import { Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor } from '../../contrib/timeline/common/timeline.js';
83 > import { TypeHierarchyItem } from '../../contrib/typeHierarchy/common/typeHierarchy.js';
84 > import { RelatedInformationResult, RelatedInformationType } from '../../services/aiRelatedInformation/common/aiRelatedInformation.js';
85 > import { AiSettingsSearchProviderOptions, AiSettingsSearchResult } from '../../services/aiSettingsSearch/common/aiSettingsSearch.js';
86 > import { AuthenticationSession, AuthenticationSessionAccount, AuthenticationSessionsChangeEvent, IAuthenticationConstraint, IAuthenticationCreateSessionOptions, IAuthenticationGetSessionsOptions, IAuthenticationWwwAuthenticateRequest } from '../../services/authentication/common/authentication.js';
87 > import { EditorGroupColumn } from '../../services/editor/common/editorGroupColumn.js';
88 > import { IExtensionDescriptionDelta, IStaticWorkspaceData } from '../../services/extensions/common/extensionHostProtocol.js';
89 > import { IResolveAuthorityResult } from '../../services/extensions/common/extensionHostProxy.js';
90 > import { ActivationKind, ExtensionActivationReason, MissingExtensionDependency } from '../../services/extensions/common/extensions.js';
91 > import { Dto, IRPCProtocol, SerializableObjectWithBuffers, createProxyIdentifier } from '../../services/extensions/common/proxyIdentifier.js';
92 > import { IInlineCompletionsUnificationState } from '../../services/inlineCompletions/common/inlineCompletionsUnification.js';
93 > import { ILanguageStatus } from '../../services/languageStatus/common/languageStatusService.js';
94 > import { OutputChannelUpdateMode } from '../../services/output/common/output.js';
95 > import { CandidatePort } from '../../services/remote/common/tunnelModel.js';
96 > import { IFileQueryBuilderOptions, ITextQueryBuilderOptions } from '../../services/search/common/queryBuilder.js';
97 > import * as search from '../../services/search/common/search.js';
98 > import { AISearchKeyword, TextSearchCompleteMessage } from '../../services/search/common/searchExtTypes.js';
99 > import { ISaveProfileResult } from '../../services/userDataProfile/common/userDataProfile.js';
100 > import { IExtHostDocumentSaveDelegate } from './extHostDocumentData.js';
101 > import { TerminalShellExecutionCommandLineConfidence } from './extHostTypes.js';
102 > import * as tasks from './shared/tasks.js';
103 > import { PromptsType } from '../../contrib/chat/common/promptSyntax/promptTypes.js';
104 > import { CDPEvent, CDPRequest, CDPResponse } from '../../../platform/browserView/common/cdp/types.js';
105 >
106 > export type IconPathDto =
107 > | UriComponents
108 > | { light: UriComponents; dark: UriComponents }
109 > | ThemeIcon;
110 >
111 > export interface IWorkspaceData extends IStaticWorkspaceData {
112 > folders: { uri: UriComponents; name: string; index: number }[];
113 > }
114 >
115 > export interface IConfigurationInitData extends IConfigurationData {
116 > configurationScopes: [string, ConfigurationScope | undefined][];
117 > }
118 >
119 > export interface IMainContext extends IRPCProtocol {
120 > }
121 >
122 > // --- main thread
123 >
124 > export interface MainThreadGitExtensionShape extends IDisposable {
125 > $onDidChangeRepository(handle: number): Promise<void>;
126 > }
127 >
128 > export interface MainThreadClipboardShape extends IDisposable {
129 > $readText(): Promise<string>;
130 > $writeText(value: string): Promise<void>;
131 > }
132 >
133 > export interface MainThreadCommandsShape extends IDisposable {
134 > $registerCommand(id: string): void;
135 > $unregisterCommand(id: string): void;
136 > $fireCommandActivationEvent(id: string): void;
137 > $executeCommand(id: string, args: unknown[] | SerializableObjectWithBuffers<unknown[]>, retry: boolean): Promise<unknown | undefined>;
138 > $getCommands(): Promise<string[]>;
139 > }
140 >
141 > export interface CommentProviderFeatures {
142 > reactionGroup?: languages.CommentReaction[];
143 > reactionHandler?: boolean;
144 > options?: languages.CommentOptions;
145 > }
146 >
147 > export interface CommentChanges {
148 > readonly uniqueIdInThread: number;
149 > readonly body: string | IMarkdownString;
150 > readonly userName: string;
151 > readonly userIconPath?: UriComponents;
152 > readonly contextValue?: string;
153 > readonly commentReactions?: languages.CommentReaction[];
154 > readonly label?: string;
155 > readonly mode?: languages.CommentMode;
156 > readonly state?: languages.CommentState;
157 > readonly timestamp?: string;
158 > }
159 >
160 > export type CommentThreadChanges<T = IRange> = Partial<{
161 > range: T | undefined;
162 > label: string;
163 > contextValue: string | null;
164 > comments: CommentChanges[];
165 > collapseState: languages.CommentThreadCollapsibleState;
166 > canReply: boolean | languages.CommentAuthorInformation;
167 > state: languages.CommentThreadState;
168 > applicability: languages.CommentThreadApplicability;
169 > isTemplate: boolean;
170 > }>;
171 >
172 > export interface MainThreadCommentsShape extends IDisposable {
173 > $registerCommentController(handle: number, id: string, label: string, extensionId: string): void;
174 > $unregisterCommentController(handle: number): void;
175 > $updateCommentControllerFeatures(handle: number, features: CommentProviderFeatures): void;
176 > $createCommentThread(handle: number, commentThreadHandle: number, threadId: string, resource: UriComponents, range: IRange | ICellRange | undefined, comments: languages.Comment[], extensionId: ExtensionIdentifier, isTemplate: boolean, editorId?: string): languages.CommentThread<IRange | ICellRange> | undefined;
177 > $updateCommentThread(handle: number, commentThreadHandle: number, threadId: string, resource: UriComponents, changes: CommentThreadChanges): void;
178 > $deleteCommentThread(handle: number, commentThreadHandle: number): void;
179 > $updateCommentingRanges(handle: number, resourceHints?: languages.CommentingRangeResourceHint): void;
180 > $revealCommentThread(handle: number, commentThreadHandle: number, commentUniqueIdInThread: number, options: languages.CommentThreadRevealOptions): Promise<void>;
181 > $hideCommentThread(handle: number, commentThreadHandle: number): void;
182 > }
183 >
184 > export interface AuthenticationForceNewSessionOptions {
185 > detail?: string;
186 > sessionToRecreate?: AuthenticationSession;
187 > }
188 >
189 > export interface AuthenticationInteractiveOptions {
190 > detail?: string;
191 > learnMore?: UriComponents;
192 > sessionToRecreate?: AuthenticationSession;
193 > }
194 >
195 > export interface AuthenticationGetSessionOptions {
196 > clearSessionPreference?: boolean;
197 > createIfNone?: boolean | AuthenticationInteractiveOptions;
198 > forceNewSession?: boolean | AuthenticationInteractiveOptions;
199 > silent?: boolean;
200 > account?: AuthenticationSessionAccount;
201 > }
202 > export interface IRegisterAuthenticationProviderDetails {
203 > id: string;
204 > label: string;
205 > supportsMultipleAccounts: boolean;
206 > supportedAuthorizationServers?: UriComponents[];
207 > supportsChallenges?: boolean;
208 > resourceServer?: UriComponents;
209 > }
210 >
211 > export interface IRegisterDynamicAuthenticationProviderDetails extends IRegisterAuthenticationProviderDetails {
212 > clientId: string;
213 > clientSecret?: string;
214 > authorizationServer: UriComponents;
215 > }
216 >
217 > export interface IXaaProviderDiscovery {
218 > issuer: UriComponents;
219 > serverMetadata: IAuthorizationServerMetadata;
220 > clientId?: string;
221 > }
222 >
223 > export interface MainThreadAuthenticationShape extends IDisposable {
224 > $registerAuthenticationProvider(details: IRegisterAuthenticationProviderDetails): Promise<void>;
225 > $unregisterAuthenticationProvider(id: string): Promise<void>;
226 > $ensureProvider(id: string): Promise<void>;
227 > $sendDidChangeSessions(providerId: string, event: AuthenticationSessionsChangeEvent): Promise<void>;
228 > $getSession(providerId: string, scopeListOrRequest: ReadonlyArray<string> | IAuthenticationWwwAuthenticateRequest, extensionId: string, extensionName: string, options: AuthenticationGetSessionOptions): Promise<AuthenticationSession | undefined>;
229 > $getAccounts(providerId: string): Promise<ReadonlyArray<AuthenticationSessionAccount>>;
230 > $removeSession(providerId: string, sessionId: string): Promise<void>;
231 > $waitForUriHandler(expectedUri: UriComponents): Promise<UriComponents>;
232 > $showContinueNotification(message: string): Promise<boolean>;
233 > $showDeviceCodeModal(userCode: string, verificationUri: string): Promise<boolean>;
234 > $promptForClientRegistration(authorizationServerUrl: string): Promise<{ clientId: string; clientSecret?: string } | undefined>;
235 > $promptForResourceClientSecret(resourceClientId: string, resource: string): Promise<string | undefined>;
236 > $registerDynamicAuthenticationProvider(details: IRegisterDynamicAuthenticationProviderDetails): Promise<void>;
237 > $setSessionsForDynamicAuthProvider(authProviderId: string, clientId: string, sessions: (IAuthorizationTokenResponse & { created_at: number })[]): Promise<void>;
238 > $sendDidChangeDynamicProviderInfo({ providerId, clientId, authorizationServer, label, clientSecret }: { providerId: string; clientId?: string; authorizationServer?: UriComponents; label?: string; clientSecret?: string }): Promise<void>;
239 > }
240 >
241 > export interface MainThreadSecretStateShape extends IDisposable {
242 > $getPassword(extensionId: string, key: string): Promise<string | undefined>;
243 > $setPassword(extensionId: string, key: string, value: string): Promise<void>;
244 > $deletePassword(extensionId: string, key: string): Promise<void>;
245 > $getKeys(extensionId: string): Promise<string[]>;
246 > }
247 >
248 > export interface MainThreadConfigurationShape extends IDisposable {
249 > $updateConfigurationOption(target: ConfigurationTarget | null, key: string, value: unknown, overrides: IConfigurationOverrides | undefined, scopeToLanguage: boolean | undefined): Promise<void>;
250 > $removeConfigurationOption(target: ConfigurationTarget | null, key: string, overrides: IConfigurationOverrides | undefined, scopeToLanguage: boolean | undefined): Promise<void>;
251 > }
252 >
253 > export interface MainThreadDiagnosticsShape extends IDisposable {
254 > $changeMany(owner: string, entries: [UriComponents, IMarkerData[] | undefined][]): void;
255 > $clear(owner: string): void;
256 > }
257 >
258 > export interface MainThreadDialogOpenOptions {
259 > defaultUri?: UriComponents;
260 > openLabel?: string;
261 > canSelectFiles?: boolean;
262 > canSelectFolders?: boolean;
263 > canSelectMany?: boolean;
264 > filters?: { [name: string]: string[] };
265 > title?: string;
266 > allowUIResources?: boolean;
267 > }
268 >
269 > export interface MainThreadDialogSaveOptions {
270 > defaultUri?: UriComponents;
271 > saveLabel?: string;
272 > filters?: { [name: string]: string[] };
273 > title?: string;
274 > }
275 >
276 > export interface MainThreadDiaglogsShape extends IDisposable {
277 > $showOpenDialog(options?: MainThreadDialogOpenOptions): Promise<UriComponents[] | undefined>;
278 > $showSaveDialog(options?: MainThreadDialogSaveOptions): Promise<UriComponents | undefined>;
279 > }
280 >
281 > export interface MainThreadDecorationsShape extends IDisposable {
282 > $registerDecorationProvider(handle: number, label: string): void;
283 > $unregisterDecorationProvider(handle: number): void;
284 > $onDidChange(handle: number, resources: UriComponents[] | null): void;
285 > }
286 >
287 > export interface MainThreadDocumentContentProvidersShape extends IDisposable {
288 > $registerTextContentProvider(handle: number, scheme: string): void;
289 > $unregisterTextContentProvider(handle: number): void;
290 > $onVirtualDocumentChange(uri: UriComponents, value: string): Promise<void>;
291 > }
292 >
293 > export interface MainThreadDocumentsShape extends IDisposable, IExtHostDocumentSaveDelegate {
294 > $tryCreateDocument(options?: { language?: string; content?: string; encoding?: string }): Promise<UriComponents>;
295 > $tryOpenDocument(uri: UriComponents, options?: { encoding?: string }): Promise<UriComponents>;
296 > $trySaveDocument(uri: UriComponents): Promise<boolean>;
297 > }
298 >
299 > export interface ITextEditorConfigurationUpdate {
300 > tabSize?: number | 'auto';
301 > indentSize?: number | 'tabSize';
302 > insertSpaces?: boolean | 'auto';
303 > cursorStyle?: TextEditorCursorStyle;
304 > lineNumbers?: RenderLineNumbersType;
305 > }
306 >
307 > export interface IResolvedTextEditorConfiguration {
308 > tabSize: number;
309 > indentSize: number;
310 > originalIndentSize: number | 'tabSize';
311 > insertSpaces: boolean;
312 > cursorStyle: TextEditorCursorStyle;
313 > lineNumbers: RenderLineNumbersType;
314 > }
315 >
316 > export enum TextEditorRevealType {
317 > Default = 0,
318 > InCenter = 1,
319 > InCenterIfOutsideViewport = 2,
320 > AtTop = 3
321 > }
322 >
323 > export interface IUndoStopOptions {
324 > undoStopBefore: boolean;
325 > undoStopAfter: boolean;
326 > }
327 >
328 > export interface IApplyEditsOptions extends IUndoStopOptions {
329 > setEndOfLine?: EndOfLineSequence;
330 > }
331 >
332 > export interface ISnippetOptions extends IUndoStopOptions {
333 > keepWhitespace?: boolean;
334 > }
335 > export interface ITextDocumentShowOptions {
336 > position?: EditorGroupColumn;
337 > preserveFocus?: boolean;
338 > pinned?: boolean;
339 > selection?: IRange;
340 > }
341 >
342 > export interface MainThreadBulkEditsShape extends IDisposable {
343 > $tryApplyWorkspaceEdit(workspaceEditDto: SerializableObjectWithBuffers<IWorkspaceEditDto>, undoRedoGroupId?: number, respectAutoSaveConfig?: boolean): Promise<boolean>;
344 > }
345 >
346 > export interface MainThreadTextEditorsShape extends IDisposable {
347 > $tryShowTextDocument(resource: UriComponents, options: ITextDocumentShowOptions): Promise<string | undefined>;
348 > $registerTextEditorDecorationType(extensionId: ExtensionIdentifier, key: string, options: editorCommon.IDecorationRenderOptions): void;
349 > $removeTextEditorDecorationType(key: string): void;
350 > $tryShowEditor(id: string, position: EditorGroupColumn): Promise<void>;
351 > $tryHideEditor(id: string): Promise<void>;
352 > $trySetOptions(id: string, options: ITextEditorConfigurationUpdate): Promise<void>;
353 > $trySetDecorations(id: string, key: string, ranges: editorCommon.IDecorationOptions[]): Promise<void>;
354 > $trySetDecorationsFast(id: string, key: string, ranges: number[]): Promise<void>;
355 > $tryRevealRange(id: string, range: IRange, revealType: TextEditorRevealType): Promise<void>;
356 > $trySetSelections(id: string, selections: ISelection[]): Promise<void>;
357 > $tryApplyEdits(id: string, modelVersionId: number, edits: ISingleEditOperation[], opts: IApplyEditsOptions): Promise<boolean>;
358 > $tryInsertSnippet(id: string, modelVersionId: number, template: string, selections: readonly IRange[], opts: IUndoStopOptions): Promise<boolean>;
359 > $getDiffInformation(id: string): Promise<IChange[]>;
360 > }
361 >
362 > export interface MainThreadTreeViewsShape extends IDisposable {
363 > $registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean; canSelectMany: boolean; dropMimeTypes: readonly string[]; dragMimeTypes: readonly string[]; hasHandleDrag: boolean; hasHandleDrop: boolean; manuallyManageCheckboxes: boolean }): Promise<void>;
364 > $refresh(treeViewId: string, itemsToRefresh?: { [treeItemHandle: string]: ITreeItem }): Promise<void>;
365 > $reveal(treeViewId: string, itemInfo: { item: ITreeItem; parentChain: ITreeItem[] } | undefined, options: IRevealOptions): Promise<void>;
366 > $setMessage(treeViewId: string, message: string | IMarkdownString): void;
367 > $setTitle(treeViewId: string, title: string, description: string | undefined): void;
368 > $setBadge(treeViewId: string, badge: IViewBadge | undefined): void;
369 > $resolveDropFileData(destinationViewId: string, requestId: number, dataItemId: string): Promise<VSBuffer>;
370 > $disposeTree(treeViewId: string): Promise<void>;
371 > $logResolveTreeNodeFailure(extensionId: string): void;
372 > }
373 >
374 > export interface MainThreadDownloadServiceShape extends IDisposable {
375 > $download(uri: UriComponents, to: UriComponents): Promise<void>;
376 > }
377 >
378 > export interface MainThreadErrorsShape extends IDisposable {
379 > $onUnexpectedError(err: any | SerializedError): void;
380 > }
381 >
382 > export interface MainThreadConsoleShape extends IDisposable {
383 > $logExtensionHostMessage(msg: IRemoteConsoleLog): void;
384 > }
385 >
386 > export interface IRegExpDto {
387 > pattern: string;
388 > flags?: string;
389 > }
390 > export interface IIndentationRuleDto {
391 > decreaseIndentPattern: IRegExpDto;
392 > increaseIndentPattern: IRegExpDto;
393 > indentNextLinePattern?: IRegExpDto;
394 > unIndentedLinePattern?: IRegExpDto;
395 > }
396 > export interface IOnEnterRuleDto {
397 > beforeText: IRegExpDto;
398 > afterText?: IRegExpDto;
399 > previousLineText?: IRegExpDto;
400 > action: EnterAction;
401 > }
402 > export interface ILanguageConfigurationDto {
403 > comments?: CommentRule;
404 > brackets?: CharacterPair[];
405 > wordPattern?: IRegExpDto;
406 > indentationRules?: IIndentationRuleDto;
407 > onEnterRules?: IOnEnterRuleDto[];
408 > __electricCharacterSupport?: {
409 > brackets?: any;
410 > docComment?: {
411 > scope: string;
412 > open: string;
413 > lineStart: string;
414 > close?: string;
415 > };
416 > };
417 > __characterPairSupport?: {
418 > autoClosingPairs: {
419 > open: string;
420 > close: string;
421 > notIn?: string[];
422 > }[];
423 > };
424 > autoClosingPairs?: {
425 > open: string;
426 > close: string;
427 > notIn?: string[];
428 > }[];
429 > }
430 >
431 > export type GlobPattern = string | IRelativePattern;
432 >
433 > export interface IRelativePatternDto extends IRelativePattern {
434 > baseUri: UriComponents;
435 > }
436 >
437 > export interface IDocumentFilterDto {
438 > $serialized: true;
439 > language?: string;
440 > scheme?: string;
441 > pattern?: string | IRelativePattern;
442 > exclusive?: boolean;
443 > notebookType?: string;
444 > isBuiltin?: boolean;
445 > }
446 >
447 > export type ITabSelectorDto = { uri: IDocumentFilterDto[] } | { viewType: string };
448 >
449 > export interface IShareableItemDto {
450 > resourceUri: UriComponents;
451 > selection?: IRange;
452 > }
453 >
454 > export interface IDocumentContextItemDto {
455 > readonly uri: UriComponents;
456 > readonly version: number;
457 > readonly ranges: IRange[];
458 > }
459 >
460 > export interface IConversationItemDto {
461 > readonly type: 'request' | 'response';
462 > readonly message: string;
463 > readonly references?: IDocumentContextItemDto[];
464 > }
465 >
466 > export interface IMappedEditsContextDto {
467 > documents: IDocumentContextItemDto[][];
468 > conversation?: IConversationItemDto[];
469 > }
470 >
471 > export interface ICodeBlockDto {
472 > code: string;
473 > resource: UriComponents;
474 > }
475 >
476 > export interface IMappedEditsRequestDto {
477 > readonly codeBlocks: ICodeBlockDto[];
478 > readonly conversation?: IConversationItemDto[];
479 > }
480 >
481 > export interface IMappedEditsResultDto {
482 > readonly errorMessage?: string;
483 > }
484 >
485 > export interface ISignatureHelpProviderMetadataDto {
486 > readonly triggerCharacters: readonly string[];
487 > readonly retriggerCharacters: readonly string[];
488 > }
489 >
490 > export interface IdentifiableInlineCompletions extends languages.InlineCompletions<IdentifiableInlineCompletion> {
491 > pid: number;
492 > languageId: string;
493 > }
494 >
495 > export interface IdentifiableInlineCompletion extends languages.InlineCompletion {
496 > pid: number;
497 > idx: number;
498 > suggestionId: EditSuggestionId | undefined;
499 > }
500 >
501 > export interface IInlineCompletionModelDto {
502 > readonly id: string;
503 > readonly name: string;
504 > }
505 >
506 > export interface IInlineCompletionModelInfoDto {
507 > readonly models: IInlineCompletionModelDto[];
508 > readonly currentModelId: string;
509 > }
510 >
511 > export interface IInlineCompletionProviderOptionValueDto {
512 > readonly id: string;
513 > readonly label: string;
514 > }
515 >
516 > export interface IInlineCompletionProviderOptionDto {
517 > readonly id: string;
518 > readonly label: string;
519 > readonly values: readonly IInlineCompletionProviderOptionValueDto[];
520 > readonly currentValueId: string;
521 > }
522 >
523 > export interface IInlineCompletionChangeHintDto {
524 > readonly data?: unknown;
525 > }
526 >
527 > export interface MainThreadLanguageFeaturesShape extends IDisposable {
528 > $unregister(handle: number): void;
529 > $registerDocumentSymbolProvider(handle: number, selector: IDocumentFilterDto[], label: string): void;
530 > $registerCodeLensSupport(handle: number, selector: IDocumentFilterDto[], eventHandle: number | undefined): void;
531 > $emitCodeLensEvent(eventHandle: number, event?: any): void;
532 > $registerDefinitionSupport(handle: number, selector: IDocumentFilterDto[]): void;
533 > $registerDeclarationSupport(handle: number, selector: IDocumentFilterDto[]): void;
534 > $registerImplementationSupport(handle: number, selector: IDocumentFilterDto[]): void;
535 > $registerTypeDefinitionSupport(handle: number, selector: IDocumentFilterDto[]): void;
536 > $registerHoverProvider(handle: number, selector: IDocumentFilterDto[]): void;
537 > $registerEvaluatableExpressionProvider(handle: number, selector: IDocumentFilterDto[]): void;
538 > $registerInlineValuesProvider(handle: number, selector: IDocumentFilterDto[], eventHandle: number | undefined): void;
539 > $emitInlineValuesEvent(eventHandle: number, event?: any): void;
540 > $registerDocumentHighlightProvider(handle: number, selector: IDocumentFilterDto[]): void;
541 > $registerMultiDocumentHighlightProvider(handle: number, selector: IDocumentFilterDto[]): void;
542 > $registerLinkedEditingRangeProvider(handle: number, selector: IDocumentFilterDto[]): void;
543 > $registerReferenceSupport(handle: number, selector: IDocumentFilterDto[]): void;
544 > $registerCodeActionSupport(handle: number, selector: IDocumentFilterDto[], metadata: ICodeActionProviderMetadataDto, displayName: string, extensionID: string, supportsResolve: boolean): void;
545 > $registerPasteEditProvider(handle: number, selector: IDocumentFilterDto[], metadata: IPasteEditProviderMetadataDto): void;
546 > $registerDocumentFormattingSupport(handle: number, selector: IDocumentFilterDto[], extensionId: ExtensionIdentifier, displayName: string): void;
547 > $registerRangeFormattingSupport(handle: number, selector: IDocumentFilterDto[], extensionId: ExtensionIdentifier, displayName: string, supportRanges: boolean): void;
548 > $registerOnTypeFormattingSupport(handle: number, selector: IDocumentFilterDto[], autoFormatTriggerCharacters: string[], extensionId: ExtensionIdentifier): void;
549 > $registerNavigateTypeSupport(handle: number, supportsResolve: boolean): void;
550 > $registerRenameSupport(handle: number, selector: IDocumentFilterDto[], supportsResolveInitialValues: boolean): void;
551 > $registerNewSymbolNamesProvider(handle: number, selector: IDocumentFilterDto[]): void;
552 > $registerDocumentSemanticTokensProvider(handle: number, selector: IDocumentFilterDto[], legend: languages.SemanticTokensLegend, eventHandle: number | undefined): void;
553 > $emitDocumentSemanticTokensEvent(eventHandle: number): void;
554 > $registerDocumentRangeSemanticTokensProvider(handle: number, selector: IDocumentFilterDto[], legend: languages.SemanticTokensLegend, eventHandle: number | undefined): void;
555 > $emitDocumentRangeSemanticTokensEvent(eventHandle: number): void;
556 > $registerCompletionsProvider(handle: number, selector: IDocumentFilterDto[], triggerCharacters: string[], supportsResolveDetails: boolean, extensionId: ExtensionIdentifier): void;
557 > $registerInlineCompletionsSupport(
558 > handle: number,
559 > selector: IDocumentFilterDto[],
560 > supportsHandleEvents: boolean,
561 > extensionId: string,
562 > extensionVersion: string,
563 > groupId: string | undefined,
564 > yieldsToExtensionIds: string[],
565 > displayName: string | undefined,
566 > debounceDelayMs: number | undefined,
567 > excludesExtensionIds: string[],
568 > supportsSetModelId: boolean,
569 > supportsOnDidChange: boolean,
570 > initialModelInfo: IInlineCompletionModelInfoDto | undefined,
571 > supportsOnDidChangeModelInfo: boolean,
572 > supportsSetProviderOption: boolean,
573 > initialProviderOptions: readonly IInlineCompletionProviderOptionDto[] | undefined,
574 > supportsOnDidChangeProviderOptions: boolean,
575 > ): void;
576 > $emitInlineCompletionsChange(handle: number, changeHint: IInlineCompletionChangeHintDto | undefined): void;
577 > $emitInlineCompletionModelInfoChange(handle: number, data: IInlineCompletionModelInfoDto | undefined): void;
578 > $emitInlineCompletionProviderOptionsChange(handle: number, data: readonly IInlineCompletionProviderOptionDto[] | undefined): void;
579 > $registerSignatureHelpProvider(handle: number, selector: IDocumentFilterDto[], metadata: ISignatureHelpProviderMetadataDto): void;
580 > $registerInlayHintsProvider(handle: number, selector: IDocumentFilterDto[], supportsResolve: boolean, eventHandle: number | undefined, displayName: string | undefined): void;
581 > $emitInlayHintsEvent(eventHandle: number): void;
582 > $registerDocumentLinkProvider(handle: number, selector: IDocumentFilterDto[], supportsResolve: boolean): void;
583 > $registerDocumentColorProvider(handle: number, selector: IDocumentFilterDto[]): void;
584 > $registerFoldingRangeProvider(handle: number, selector: IDocumentFilterDto[], extensionId: ExtensionIdentifier, eventHandle: number | undefined): void;
585 > $emitFoldingRangeEvent(eventHandle: number, event?: any): void;
586 > $registerSelectionRangeProvider(handle: number, selector: IDocumentFilterDto[]): void;
587 > $registerCallHierarchyProvider(handle: number, selector: IDocumentFilterDto[]): void;
588 > $registerTypeHierarchyProvider(handle: number, selector: IDocumentFilterDto[]): void;
589 > $registerDocumentOnDropEditProvider(handle: number, selector: IDocumentFilterDto[], metadata?: IDocumentDropEditProviderMetadata): void;
590 > $resolvePasteFileData(handle: number, requestId: number, dataId: string): Promise<VSBuffer>;
591 > $resolveDocumentOnDropFileData(handle: number, requestId: number, dataId: string): Promise<VSBuffer>;
592 > $setLanguageConfiguration(handle: number, languageId: string, configuration: ILanguageConfigurationDto): void;
593 > }
594 >
595 > export interface MainThreadLanguagesShape extends IDisposable {
596 > $changeLanguage(resource: UriComponents, languageId: string): Promise<void>;
597 > $tokensAtPosition(resource: UriComponents, position: IPosition): Promise<undefined | { type: StandardTokenType; range: IRange }>;
598 > $computeFullSyntaxHighlighting(source: string, languageId: string): Promise<ISyntaxHighlightingResultDto>;
599 > $setLanguageStatus(handle: number, status: ILanguageStatus): void;
600 > $removeLanguageStatus(handle: number): void;
601 > }
602 >
603 > export interface ISyntaxHighlightingTokenDto {
604 > readonly length: number;
605 > readonly foreground: number;
606 > readonly fontStyle: number;
607 > }
608 >
609 > export interface ISyntaxHighlightingResultDto {
610 > readonly tokens: ISyntaxHighlightingTokenDto[];
611 > readonly colorMap: string[];
612 > }
613 >
614 > export interface MainThreadMessageOptions {
615 > source?: { identifier: ExtensionIdentifier; label: string };
616 > modal?: boolean;
617 > detail?: string;
618 > useCustom?: boolean;
619 > }
620 >
621 > export interface MainThreadMessageServiceShape extends IDisposable {
622 > $showMessage(severity: Severity, message: string, options: MainThreadMessageOptions, commands: { title: string; isCloseAffordance: boolean; handle: number }[]): Promise<number | undefined>;
623 > }
624 >
625 > export interface MainThreadOutputServiceShape extends IDisposable {
626 > $register(label: string, file: UriComponents, languageId: string | undefined, extensionId: string): Promise<string>;
627 > $update(channelId: string, mode: OutputChannelUpdateMode, till?: number): Promise<void>;
628 > $reveal(channelId: string, preserveFocus: boolean): Promise<void>;
629 > $close(channelId: string): Promise<void>;
630 > $dispose(channelId: string): Promise<void>;
631 > }
632 >
633 > export interface MainThreadProgressShape extends IDisposable {
634 >
635 > $startProgress(handle: number, options: IProgressOptions, extensionId?: string): Promise<void>;
636 > $progressReport(handle: number, message: IProgressStep): void;
637 > $progressEnd(handle: number): void;
638 > }
639 >
640 > /**
641 > * A terminal that is created on the extension host side is temporarily assigned
642 > * a UUID by the extension host that created it. Once the renderer side has assigned
643 > * a real numeric id, the numeric id will be used.
644 > *
645 > * All other terminals (that are not created on the extension host side) always
646 > * use the numeric id.
647 > */
648 > export type ExtHostTerminalIdentifier = number | string;
649 >
650 > export interface TerminalLaunchConfig {
651 > name?: string;
652 > shellPath?: string;
653 > shellArgs?: string[] | string;
654 > cwd?: string | UriComponents;
655 > env?: ITerminalEnvironment;
656 > icon?: URI | { light: URI; dark: URI } | ThemeIcon;
657 > color?: string;
658 > initialText?: string;
659 > waitOnExit?: boolean;
660 > strictEnv?: boolean;
661 > hideFromUser?: boolean;
662 > isExtensionCustomPtyTerminal?: boolean;
663 > forceShellIntegration?: boolean;
664 > isFeatureTerminal?: boolean;
665 > isExtensionOwnedTerminal?: boolean;
666 > useShellEnvironment?: boolean;
667 > location?: TerminalLocation | { viewColumn: number; preserveFocus?: boolean } | { parentTerminal: ExtHostTerminalIdentifier } | { splitActiveTerminal: boolean };
668 > isTransient?: boolean;
669 > shellIntegrationNonce?: string;
670 > titleTemplate?: string;
671 > }
672 >
673 >
674 > export interface MainThreadTerminalServiceShape extends IDisposable {
675 > $createTerminal(extHostTerminalId: string, config: TerminalLaunchConfig): Promise<void>;
676 > $dispose(id: ExtHostTerminalIdentifier): void;
677 > $hide(id: ExtHostTerminalIdentifier): void;
678 > $sendText(id: ExtHostTerminalIdentifier, text: string, shouldExecute: boolean): void;
679 > $show(id: ExtHostTerminalIdentifier, preserveFocus: boolean): void;
680 > $registerProcessSupport(isSupported: boolean): void;
681 > $registerProfileProvider(id: string, extensionIdentifier: string): void;
682 > $unregisterProfileProvider(id: string): void;
683 > $registerCompletionProvider(id: string, extensionIdentifier: string, ...triggerCharacters: string[]): void;
684 > $unregisterCompletionProvider(id: string): void;
685 > $registerQuickFixProvider(id: string, extensionIdentifier: string): void;
686 > $unregisterQuickFixProvider(id: string): void;
687 > $setEnvironmentVariableCollection(extensionIdentifier: string, persistent: boolean, collection: ISerializableEnvironmentVariableCollection | undefined, descriptionMap: ISerializableEnvironmentDescriptionMap): void;
688 >
689 > // Optional event toggles
690 > $startSendingDataEvents(): void;
691 > $stopSendingDataEvents(): void;
692 > $startSendingCommandEvents(): void;
693 > $stopSendingCommandEvents(): void;
694 > $startLinkProvider(): void;
695 > $stopLinkProvider(): void;
696 >
697 > // Process
698 > $sendProcessData(terminalId: number, data: string): void;
699 > $sendProcessReady(terminalId: number, pid: number, cwd: string, windowsPty: IProcessReadyWindowsPty | undefined): void;
700 > $sendProcessProperty(terminalId: number, property: IProcessProperty<any>): void;
701 > $sendProcessExit(terminalId: number, exitCode: number | undefined): void;
702 > }
703 >
704 > export interface MainThreadTerminalShellIntegrationShape extends IDisposable {
705 > $executeCommand(terminalId: number, commandLine: string): void;
706 > }
707 >
708 > export type TransferQuickPickItemOrSeparator = TransferQuickPickItem | quickInput.IQuickPickSeparator;
709 > export interface TransferQuickPickItem {
710 > handle: number;
711 >
712 > // shared properties from IQuickPickItem
713 > type?: 'item';
714 > label: string;
715 > iconPathDto?: IconPathDto;
716 > description?: string;
717 > detail?: string;
718 > picked?: boolean;
719 > alwaysShow?: boolean;
720 > buttons?: TransferQuickInputButton[];
721 > resourceUri?: UriComponents;
722 >
723 > // TODO: These properties are not used for transfer (iconPathDto is used instead) but they cannot be removed
724 > // because this type is used as IQuickPickItem on the main thread. Ideally IQuickPickItem should also use IconPath.
725 > iconPath?: { light?: URI; dark: URI };
726 > iconClass?: string;
727 > }
728 >
729 > export interface TransferQuickInputButton extends quickInput.IQuickInputButton {
730 > handle: number;
731 > iconPathDto: IconPathDto;
732 > toggle?: { checked: boolean };
733 >
734 > // TODO: These properties are not used for transfer (iconPathDto is used instead) but they cannot be removed
735 > // because this type is used as IQuickInputButton on the main thread. Ideally IQuickInputButton should also use IconPath.
736 > iconPath?: { light?: URI; dark: URI };
737 > iconClass?: string;
738 > }
739 >
740 > export type TransferQuickInput = TransferQuickPick | TransferInputBox;
741 >
742 > export interface BaseTransferQuickInput {
743 >
744 > [key: string]: any;
745 >
746 > id: number;
747 >
748 > title?: string;
749 >
750 > type?: 'quickPick' | 'inputBox';
751 >
752 > enabled?: boolean;
753 >
754 > busy?: boolean;
755 >
756 > visible?: boolean;
757 > }
758 >
759 > export interface TransferQuickPick extends BaseTransferQuickInput {
760 >
761 > type?: 'quickPick';
762 >
763 > value?: string;
764 >
765 > placeholder?: string;
766 >
767 > prompt?: string;
768 >
769 > buttons?: TransferQuickInputButton[];
770 >
771 > items?: TransferQuickPickItemOrSeparator[];
772 >
773 > activeItems?: number[];
774 >
775 > selectedItems?: number[];
776 >
777 > canSelectMany?: boolean;
778 >
779 > ignoreFocusOut?: boolean;
780 >
781 > matchOnDescription?: boolean;
782 >
783 > matchOnDetail?: boolean;
784 >
785 > sortByLabel?: boolean;
786 > }
787 >
788 > export interface TransferInputBox extends BaseTransferQuickInput {
789 >
790 > type?: 'inputBox';
791 >
792 > value?: string;
793 >
794 > valueSelection?: Readonly<[number, number]>;
795 >
796 > placeholder?: string;
797 >
798 > password?: boolean;
799 >
800 > buttons?: TransferQuickInputButton[];
801 >
802 > prompt?: string;
803 >
804 > validationMessage?: string;
805 > }
806 >
807 > export interface IInputBoxOptions {
808 > title?: string;
809 > value?: string;
810 > valueSelection?: Readonly<[number, number]>;
811 > prompt?: string;
812 > placeHolder?: string;
813 > password?: boolean;
814 > ignoreFocusOut?: boolean;
815 > }
816 >
817 > export interface MainThreadQuickOpenShape extends IDisposable {
818 > $show(instance: number, options: quickInput.IPickOptions<TransferQuickPickItem>, token: CancellationToken): Promise<number | number[] | undefined>;
819 > $setItems(instance: number, items: TransferQuickPickItemOrSeparator[]): Promise<void>;
820 > $setError(instance: number, error: Error): Promise<void>;
821 > $input(options: IInputBoxOptions | undefined, validateInput: boolean, token: CancellationToken): Promise<string | undefined>;
822 > $createOrUpdate(params: TransferQuickInput): Promise<void>;
823 > $dispose(id: number): Promise<void>;
824 > }
825 >
826 > export interface MainThreadStatusBarShape extends IDisposable {
827 > $setEntry(id: string, statusId: string, extensionId: string | undefined, statusName: string, text: string, tooltip: IMarkdownString | string | undefined, hasTooltipProvider: boolean, command: ICommandDto | undefined, color: string | ThemeColor | undefined, backgroundColor: string | ThemeColor | undefined, alignLeft: boolean, priority: number | undefined, accessibilityInformation: IAccessibilityInformation | undefined): void;
828 > $disposeEntry(id: string): void;
829 > }
830 >
831 > export type StatusBarItemDto = {
832 > entryId: string;
833 > alignLeft: boolean;
834 > priority?: number;
835 > name: string;
836 > text: string;
837 > tooltip?: string;
838 > command?: string;
839 > accessibilityInformation?: IAccessibilityInformation;
840 > };
841 >
842 > export interface ExtHostStatusBarShape {
843 > $acceptStaticEntries(added?: StatusBarItemDto[]): void;
844 > $provideTooltip(entryId: string, cancellation: CancellationToken): Promise<string | IMarkdownString | undefined>;
845 > }
846 >
847 > export interface MainThreadStorageShape extends IDisposable {
848 > $initializeExtensionStorage(shared: boolean, extensionId: string): Promise<string | undefined>;
849 > $setValue(shared: boolean, extensionId: string, value: object): Promise<void>;
850 > $registerExtensionStorageKeysToSync(extension: IExtensionIdWithVersion, keys: string[]): void;
851 > }
852 >
853 > export interface MainThreadTelemetryShape extends IDisposable {
854 > $publicLog(eventName: string, data?: any): void;
855 > $publicLog2<E extends ClassifiedEvent<OmitMetadata<T>> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck<T, E>): void;
856 > }
857 >
858 > export interface MainThreadEditorInsetsShape extends IDisposable {
859 > $createEditorInset(handle: number, id: string, uri: UriComponents, line: number, height: number, options: IWebviewContentOptions, extensionId: ExtensionIdentifier, extensionLocation: UriComponents): Promise<void>;
860 > $disposeEditorInset(handle: number): void;
861 >
862 > $setHtml(handle: number, value: string): void;
863 > $setOptions(handle: number, options: IWebviewContentOptions): void;
864 > $postMessage(handle: number, value: any): Promise<boolean>;
865 > }
866 >
867 > export interface ExtHostEditorInsetsShape {
868 > $onDidDispose(handle: number): void;
869 > $onDidReceiveMessage(handle: number, message: any): void;
870 > }
871 >
872 > //#region --- tabs model
873 >
874 > export const enum TabInputKind {
875 > UnknownInput,
876 > TextInput,
877 > TextDiffInput,
878 > TextMergeInput,
879 > NotebookInput,
880 > NotebookDiffInput,
881 > CustomEditorInput,
882 > WebviewEditorInput,
883 > TerminalEditorInput,
884 > InteractiveEditorInput,
885 > ChatEditorInput,
886 > MultiDiffEditorInput
887 > }
888 >
889 > export const enum TabModelOperationKind {
890 > TAB_OPEN,
891 > TAB_CLOSE,
892 > TAB_UPDATE,
893 > TAB_MOVE
894 > }
895 >
896 > export interface UnknownInputDto {
897 > kind: TabInputKind.UnknownInput;
898 > }
899 >
900 > export interface TextInputDto {
901 > kind: TabInputKind.TextInput;
902 > uri: UriComponents;
903 > }
904 >
905 > export interface TextDiffInputDto {
906 > kind: TabInputKind.TextDiffInput;
907 > original: UriComponents;
908 > modified: UriComponents;
909 > }
910 >
911 > export interface TextMergeInputDto {
912 > kind: TabInputKind.TextMergeInput;
913 > base: UriComponents;
914 > input1: UriComponents;
915 > input2: UriComponents;
916 > result: UriComponents;
917 > }
918 >
919 > export interface NotebookInputDto {
920 > kind: TabInputKind.NotebookInput;
921 > notebookType: string;
922 > uri: UriComponents;
923 > }
924 >
925 > export interface NotebookDiffInputDto {
926 > kind: TabInputKind.NotebookDiffInput;
927 > notebookType: string;
928 > original: UriComponents;
929 > modified: UriComponents;
930 > }
931 >
932 > export interface CustomInputDto {
933 > kind: TabInputKind.CustomEditorInput;
934 > viewType: string;
935 > uri: UriComponents;
936 > }
937 >
938 > export interface WebviewInputDto {
939 > kind: TabInputKind.WebviewEditorInput;
940 > viewType: string;
941 > }
942 >
943 > export interface InteractiveEditorInputDto {
944 > kind: TabInputKind.InteractiveEditorInput;
945 > uri: UriComponents;
946 > inputBoxUri: UriComponents;
947 > }
948 >
949 > export interface ChatEditorInputDto {
950 > kind: TabInputKind.ChatEditorInput;
951 > }
952 >
953 > export interface MultiDiffEditorInputDto {
954 > kind: TabInputKind.MultiDiffEditorInput;
955 > diffEditors: TextDiffInputDto[];
956 > }
957 >
958 > export interface TabInputDto {
959 > kind: TabInputKind.TerminalEditorInput;
960 > }
961 >
962 > export type AnyInputDto = UnknownInputDto | TextInputDto | TextDiffInputDto | MultiDiffEditorInputDto | TextMergeInputDto | NotebookInputDto | NotebookDiffInputDto | CustomInputDto | WebviewInputDto | InteractiveEditorInputDto | ChatEditorInputDto | TabInputDto;
963 >
964 > export interface MainThreadEditorTabsShape extends IDisposable {
965 > // manage tabs: move, close, rearrange etc
966 > $moveTab(tabId: string, index: number, viewColumn: EditorGroupColumn, preserveFocus?: boolean): void;
967 > $closeTab(tabIds: string[], preserveFocus?: boolean): Promise<boolean>;
968 > $closeGroup(groupIds: number[], preservceFocus?: boolean): Promise<boolean>;
969 > }
970 >
971 > export interface IEditorTabGroupDto {
972 > isActive: boolean;
973 > viewColumn: EditorGroupColumn;
974 > // Decided not to go with simple index here due to opening and closing causing index shifts
975 > // This allows us to patch the model without having to do full rebuilds
976 > tabs: IEditorTabDto[];
977 > groupId: number;
978 > }
979 >
980 > export interface TabOperation {
981 > readonly kind: TabModelOperationKind.TAB_OPEN | TabModelOperationKind.TAB_CLOSE | TabModelOperationKind.TAB_UPDATE | TabModelOperationKind.TAB_MOVE;
982 > // TODO @lramos15 Possibly get rid of index for tab update, it's only needed for open and close
983 > readonly index: number;
984 > readonly tabDto: IEditorTabDto;
985 > readonly groupId: number;
986 > readonly oldIndex?: number;
987 > }
988 >
989 > export interface IEditorTabDto {
990 > id: string;
991 > label: string;
992 > input: AnyInputDto;
993 > editorId?: string;
994 > isActive: boolean;
995 > isPinned: boolean;
996 > isPreview: boolean;
997 > isDirty: boolean;
998 > }
999 >
1000 > export interface IExtHostEditorTabsShape {
1001 > // Accepts a whole new model
1002 > $acceptEditorTabModel(tabGroups: IEditorTabGroupDto[]): void;
1003 > // Only when group property changes (not the tabs inside)
1004 > $acceptTabGroupUpdate(groupDto: IEditorTabGroupDto): void;
1005 > // When a tab is added, removed, or updated
1006 > $acceptTabOperation(operation: TabOperation): void;
1007 > }
1008 >
1009 > //#endregion
1010 >
1011 > export type WebviewHandle = string;
1012 >
1013 > export interface WebviewPanelShowOptions {
1014 > readonly viewColumn?: EditorGroupColumn;
1015 > readonly preserveFocus?: boolean;
1016 > }
1017 >
1018 > export interface WebviewExtensionDescription {
1019 > readonly id: ExtensionIdentifier;
1020 > readonly location: UriComponents;
1021 > }
1022 >
1023 > export enum WebviewEditorCapabilities {
1024 > Editable,
1025 > SupportsHotExit,
1026 > }
1027 >
1028 > export interface IWebviewPortMapping {
1029 > readonly webviewPort: number;
1030 > readonly extensionHostPort: number;
1031 > }
1032 >
1033 > export interface IWebviewContentOptions {
1034 > readonly enableScripts?: boolean;
1035 > readonly enableForms?: boolean;
1036 > readonly enableCommandUris?: boolean | readonly string[];
1037 > readonly localResourceRoots?: readonly UriComponents[];
1038 > readonly portMapping?: readonly IWebviewPortMapping[];
1039 > }
1040 >
1041 > export interface IWebviewPanelOptions {
1042 > readonly enableFindWidget?: boolean;
1043 > readonly retainContextWhenHidden?: boolean;
1044 > }
1045 >
1046 > export interface CustomEditorProviderCapabilities {
1047 > readonly supportsMove?: boolean;
1048 > readonly supportsInlineDiff?: boolean;
1049 > readonly supportsSideBySideDiff?: boolean;
1050 > }
1051 >
1052 > export interface CustomEditorDiffInitData {
1053 > readonly title: string;
1054 > readonly contentOptions: IWebviewContentOptions;
1055 > readonly options: IWebviewPanelOptions;
1056 > readonly active: boolean;
1057 > }
1058 >
1059 > export interface CustomEditorSideBySideDiffWebviewHandles {
1060 > readonly original: WebviewHandle;
1061 > readonly modified: WebviewHandle;
1062 > }
1063 >
1064 > export interface CustomEditorSideBySideDiffInitData {
1065 > readonly original: CustomEditorDiffInitData;
1066 > readonly modified: CustomEditorDiffInitData;
1067 > }
1068 >
1069 > export const enum WebviewMessageArrayBufferViewType {
1070 > Int8Array = 1,
1071 > Uint8Array = 2,
1072 > Uint8ClampedArray = 3,
1073 > Int16Array = 4,
1074 > Uint16Array = 5,
1075 > Int32Array = 6,
1076 > Uint32Array = 7,
1077 > Float32Array = 8,
1078 > Float64Array = 9,
1079 > BigInt64Array = 10,
1080 > BigUint64Array = 11,
1081 > }
1082 >
1083 > export interface WebviewMessageArrayBufferReference {
1084 > readonly $$vscode_array_buffer_reference$$: true;
1085 >
1086 > readonly index: number;
1087 >
1088 > /**
1089 > * Tracks if the reference is to a view instead of directly to an ArrayBuffer.
1090 > */
1091 > readonly view?: {
1092 > readonly type: WebviewMessageArrayBufferViewType;
1093 > readonly byteLength: number;
1094 > readonly byteOffset: number;
1095 > };
1096 > }
1097 >
1098 > export interface MainThreadWebviewsShape extends IDisposable {
1099 > $setHtml(handle: WebviewHandle, value: string): void;
1100 > $setOptions(handle: WebviewHandle, options: IWebviewContentOptions): void;
1101 > $postMessage(handle: WebviewHandle, value: string, ...buffers: VSBuffer[]): Promise<boolean>;
1102 > }
1103 >
1104 > export type IWebviewIconPath = ThemeIcon | {
1105 > readonly light: UriComponents;
1106 > readonly dark: UriComponents;
1107 > };
1108 >
1109 > export interface IWebviewInitData {
1110 > readonly title: string;
1111 > readonly webviewOptions: IWebviewContentOptions;
1112 > readonly panelOptions: IWebviewPanelOptions;
1113 > readonly serializeBuffersForPostMessage: boolean;
1114 > }
1115 >
1116 > export interface MainThreadWebviewPanelsShape extends IDisposable {
1117 > $createWebviewPanel(
1118 > extension: WebviewExtensionDescription,
1119 > handle: WebviewHandle,
1120 > viewType: string,
1121 > initData: IWebviewInitData,
1122 > showOptions: WebviewPanelShowOptions,
1123 > ): void;
1124 > $disposeWebview(handle: WebviewHandle): void;
1125 > $reveal(handle: WebviewHandle, showOptions: WebviewPanelShowOptions): void;
1126 > $setTitle(handle: WebviewHandle, value: string): void;
1127 > $setIconPath(handle: WebviewHandle, value: IWebviewIconPath | undefined): void;
1128 >
1129 > $registerSerializer(viewType: string, options: { serializeBuffersForPostMessage: boolean }): void;
1130 > $unregisterSerializer(viewType: string): void;
1131 > }
1132 >
1133 > export interface MainThreadCustomEditorsShape extends IDisposable {
1134 > $registerTextEditorProvider(extension: WebviewExtensionDescription, viewType: string, options: IWebviewPanelOptions, capabilities: CustomEditorProviderCapabilities, serializeBuffersForPostMessage: boolean): void;
1135 > $registerCustomEditorProvider(extension: WebviewExtensionDescription, viewType: string, options: IWebviewPanelOptions, capabilities: CustomEditorProviderCapabilities, supportsMultipleEditorsPerDocument: boolean, serializeBuffersForPostMessage: boolean): void;
1136 > $unregisterEditorProvider(viewType: string): void;
1137 >
1138 > $onDidEdit(resource: UriComponents, viewType: string, editId: number, label: string | undefined): void;
1139 > $onContentChange(resource: UriComponents, viewType: string): void;
1140 > }
1141 >
1142 > export interface MainThreadWebviewViewsShape extends IDisposable {
1143 > $registerWebviewViewProvider(extension: WebviewExtensionDescription, viewType: string, options: { retainContextWhenHidden?: boolean; serializeBuffersForPostMessage: boolean }): void;
1144 > $unregisterWebviewViewProvider(viewType: string): void;
1145 >
1146 > $setWebviewViewTitle(handle: WebviewHandle, value: string | undefined): void;
1147 > $setWebviewViewDescription(handle: WebviewHandle, value: string | undefined): void;
1148 > $setWebviewViewBadge(handle: WebviewHandle, badge: IViewBadge | undefined): void;
1149 >
1150 > $show(handle: WebviewHandle, preserveFocus: boolean): void;
1151 > }
1152 >
1153 > export interface WebviewPanelViewStateData {
1154 > [handle: string]: {
1155 > readonly active: boolean;
1156 > readonly visible: boolean;
1157 > readonly position: EditorGroupColumn;
1158 > };
1159 > }
1160 >
1161 > export interface ExtHostWebviewsShape {
1162 > $onMessage(handle: WebviewHandle, jsonSerializedMessage: string, buffers: SerializableObjectWithBuffers<VSBuffer[]>): void;
1163 > $onMissingCsp(handle: WebviewHandle, extensionId: string): void;
1164 > }
1165 >
1166 > export interface ExtHostWebviewPanelsShape {
1167 > $onDidChangeWebviewPanelViewStates(newState: WebviewPanelViewStateData): void;
1168 > $onDidDisposeWebviewPanel(handle: WebviewHandle): Promise<void>;
1169 > $deserializeWebviewPanel(
1170 > newWebviewHandle: WebviewHandle,
1171 > viewType: string,
1172 > initData: {
1173 > title: string;
1174 > state: any;
1175 > webviewOptions: IWebviewContentOptions;
1176 > panelOptions: IWebviewPanelOptions;
1177 > active: boolean;
1178 > },
1179 > position: EditorGroupColumn,
1180 > ): Promise<void>;
1181 > }
1182 >
1183 > export interface ExtHostCustomEditorsShape {
1184 > $resolveCustomEditor(
1185 > resource: UriComponents,
1186 > newWebviewHandle: WebviewHandle,
1187 > viewType: string,
1188 > initData: {
1189 > title: string;
1190 > contentOptions: IWebviewContentOptions;
1191 > options: IWebviewPanelOptions;
1192 > active: boolean;
1193 > },
1194 > position: EditorGroupColumn,
1195 > cancellation: CancellationToken
1196 > ): Promise<void>;
1197 > $resolveCustomEditorInlineDiff(
1198 > originalResource: UriComponents,
1199 > modifiedResource: UriComponents,
1200 > newWebviewHandle: WebviewHandle,
1201 > viewType: string,
1202 > initData: CustomEditorDiffInitData,
1203 > position: EditorGroupColumn,
1204 > cancellation: CancellationToken
1205 > ): Promise<void>;
1206 > $resolveCustomEditorSideBySideDiff(
1207 > originalResource: UriComponents,
1208 > modifiedResource: UriComponents,
1209 > webviewHandles: CustomEditorSideBySideDiffWebviewHandles,
1210 > viewType: string,
1211 > initData: CustomEditorSideBySideDiffInitData,
1212 > position: EditorGroupColumn,
1213 > cancellation: CancellationToken
1214 > ): Promise<void>;
1215 > $createCustomDocument(resource: UriComponents, viewType: string, backupId: string | undefined, untitledDocumentData: VSBuffer | undefined, cancellation: CancellationToken): Promise<{ editable: boolean }>;
1216 > $disposeCustomDocument(resource: UriComponents, viewType: string): Promise<void>;
1217 >
1218 > $undo(resource: UriComponents, viewType: string, editId: number, isDirty: boolean): Promise<void>;
1219 > $redo(resource: UriComponents, viewType: string, editId: number, isDirty: boolean): Promise<void>;
1220 > $revert(resource: UriComponents, viewType: string, cancellation: CancellationToken): Promise<void>;
1221 > $disposeEdits(resourceComponents: UriComponents, viewType: string, editIds: number[]): void;
1222 >
1223 > $onSave(resource: UriComponents, viewType: string, cancellation: CancellationToken): Promise<void>;
1224 > $onSaveAs(resource: UriComponents, viewType: string, targetResource: UriComponents, cancellation: CancellationToken): Promise<void>;
1225 >
1226 > $backup(resource: UriComponents, viewType: string, cancellation: CancellationToken): Promise<string>;
1227 >
1228 > $onMoveCustomEditor(handle: WebviewHandle, newResource: UriComponents, viewType: string): Promise<void>;
1229 > }
1230 >
1231 > export interface ExtHostWebviewViewsShape {
1232 > $resolveWebviewView(webviewHandle: WebviewHandle, viewType: string, title: string | undefined, state: any, cancellation: CancellationToken): Promise<void>;
1233 >
1234 > $onDidChangeWebviewViewVisibility(webviewHandle: WebviewHandle, visible: boolean): void;
1235 >
1236 > $disposeWebviewView(webviewHandle: WebviewHandle): void;
1237 > }
1238 >
1239 > export interface MainThreadManagedSocketsShape extends IDisposable {
1240 > $registerSocketFactory(socketFactoryId: number): Promise<void>;
1241 > $unregisterSocketFactory(socketFactoryId: number): Promise<void>;
1242 > $onDidManagedSocketHaveData(socketId: number, data: VSBuffer): void;
1243 > $onDidManagedSocketClose(socketId: number, error: string | undefined): void;
1244 > $onDidManagedSocketEnd(socketId: number): void;
1245 > }
1246 >
1247 > export interface ExtHostManagedSocketsShape {
1248 > $openRemoteSocket(socketFactoryId: number): Promise<number>;
1249 > $remoteSocketWrite(socketId: number, buffer: VSBuffer): void;
1250 > $remoteSocketEnd(socketId: number): void;
1251 > $remoteSocketDrain(socketId: number): Promise<void>;
1252 > }
1253 >
1254 > export interface MainThreadBrowserTunnelProxyShape extends IDisposable {
1255 > $updateProxyInfo(info: ITunnelProxyInfo | undefined): void;
1256 > }
1257 >
1258 > export interface ExtHostBrowserTunnelProxyShape {
1259 > $setEnabled(enabled: boolean): void;
1260 > }
1261 >
1262 > export enum CellOutputKind {
1263 > Text = 1,
1264 > Error = 2,
1265 > Rich = 3
1266 > }
1267 >
1268 > export enum NotebookEditorRevealType {
1269 > Default = 0,
1270 > InCenter = 1,
1271 > InCenterIfOutsideViewport = 2,
1272 > AtTop = 3
1273 > }
1274 >
1275 > export interface INotebookDocumentShowOptions {
1276 > position?: EditorGroupColumn;
1277 > preserveFocus?: boolean;
1278 > pinned?: boolean;
1279 > selections?: ICellRange[];
1280 > label?: string;
1281 > }
1282 >
1283 > export type INotebookCellStatusBarEntryDto = Dto<notebookCommon.INotebookCellStatusBarItem>;
1284 >
1285 > export interface INotebookCellStatusBarListDto {
1286 > items: INotebookCellStatusBarEntryDto[];
1287 > cacheId: number;
1288 > }
1289 >
1290 > export interface MainThreadNotebookShape extends IDisposable {
1291 > $registerNotebookSerializer(handle: number, extension: notebookCommon.NotebookExtensionDescription, viewType: string, options: notebookCommon.TransientOptions, registration: notebookCommon.INotebookContributionData | undefined): void;
1292 > $unregisterNotebookSerializer(handle: number): void;
1293 >
1294 > $registerNotebookCellStatusBarItemProvider(handle: number, eventHandle: number | undefined, viewType: string): Promise<void>;
1295 > $unregisterNotebookCellStatusBarItemProvider(handle: number, eventHandle: number | undefined): Promise<void>;
1296 > $emitCellStatusBarEvent(eventHandle: number): void;
1297 > }
1298 >
1299 > export interface MainThreadNotebookEditorsShape extends IDisposable {
1300 > $tryShowNotebookDocument(uriComponents: UriComponents, viewType: string, options: INotebookDocumentShowOptions): Promise<string>;
1301 > $tryRevealRange(id: string, range: ICellRange, revealType: NotebookEditorRevealType): Promise<void>;
1302 > $trySetSelections(id: string, range: ICellRange[]): void;
1303 > }
1304 >
1305 > export interface MainThreadNotebookDocumentsShape extends IDisposable {
1306 > $tryCreateNotebook(options: { viewType: string; content?: NotebookDataDto }): Promise<UriComponents>;
1307 > $tryOpenNotebook(uriComponents: UriComponents): Promise<UriComponents>;
1308 > $trySaveNotebook(uri: UriComponents): Promise<boolean>;
1309 > }
1310 >
1311 > export interface INotebookKernelDto2 {
1312 > id: string;
1313 > notebookType: string;
1314 > extensionId: ExtensionIdentifier;
1315 > extensionLocation: UriComponents;
1316 > label: string;
1317 > detail?: string;
1318 > description?: string;
1319 > supportedLanguages?: string[];
1320 > supportsInterrupt?: boolean;
1321 > supportsExecutionOrder?: boolean;
1322 > preloads?: { uri: UriComponents; provides: readonly string[] }[];
1323 > hasVariableProvider?: boolean;
1324 > }
1325 >
1326 > export interface INotebookProxyKernelDto {
1327 > id: string;
1328 > notebookType: string;
1329 > extensionId: ExtensionIdentifier;
1330 > extensionLocation: UriComponents;
1331 > label: string;
1332 > detail?: string;
1333 > description?: string;
1334 > kind?: string;
1335 > }
1336 >
1337 > export interface ICellExecuteOutputEditDto {
1338 > editType: CellExecutionUpdateType.Output;
1339 > cellHandle: number;
1340 > append?: boolean;
1341 > outputs: NotebookOutputDto[];
1342 > }
1343 >
1344 > export interface ICellExecuteOutputItemEditDto {
1345 > editType: CellExecutionUpdateType.OutputItems;
1346 > append?: boolean;
1347 > outputId: string;
1348 > items: NotebookOutputItemDto[];
1349 > }
1350 >
1351 > export interface ICellExecutionStateUpdateDto extends ICellExecutionStateUpdate {
1352 > }
1353 >
1354 > export interface ICellExecutionCompleteDto extends ICellExecutionComplete {
1355 > }
1356 >
1357 > export type ICellExecuteUpdateDto = ICellExecuteOutputEditDto | ICellExecuteOutputItemEditDto | ICellExecutionStateUpdateDto;
1358 >
1359 > export interface VariablesResult {
1360 > id: number;
1361 > name: string;
1362 > value: string;
1363 > type?: string;
1364 > language?: string;
1365 > expression?: string;
1366 > hasNamedChildren: boolean;
1367 > indexedChildrenCount: number;
1368 > extensionId: string;
1369 > }
1370 >
1371 > export interface MainThreadNotebookKernelsShape extends IDisposable {
1372 > $postMessage(handle: number, editorId: string | undefined, message: any): Promise<boolean>;
1373 > $addKernel(handle: number, data: INotebookKernelDto2): Promise<void>;
1374 > $updateKernel(handle: number, data: Partial<INotebookKernelDto2>): void;
1375 > $removeKernel(handle: number): void;
1376 > $updateNotebookPriority(handle: number, uri: UriComponents, value: number | undefined): void;
1377 >
1378 > $createExecution(handle: number, controllerId: string, uri: UriComponents, cellHandle: number): void;
1379 > $updateExecution(handle: number, data: SerializableObjectWithBuffers<ICellExecuteUpdateDto[]>): void;
1380 > $completeExecution(handle: number, data: SerializableObjectWithBuffers<ICellExecutionCompleteDto>): void;
1381 >
1382 > $createNotebookExecution(handle: number, controllerId: string, uri: UriComponents): void;
1383 > $beginNotebookExecution(handle: number,): void;
1384 > $completeNotebookExecution(handle: number): void;
1385 >
1386 > $addKernelDetectionTask(handle: number, notebookType: string): Promise<void>;
1387 > $removeKernelDetectionTask(handle: number): void;
1388 >
1389 > $addKernelSourceActionProvider(handle: number, eventHandle: number, notebookType: string): Promise<void>;
1390 > $removeKernelSourceActionProvider(handle: number, eventHandle: number): void;
1391 > $emitNotebookKernelSourceActionsChangeEvent(eventHandle: number): void;
1392 > $receiveVariable(requestId: string, variable: VariablesResult): void;
1393 > $variablesUpdated(notebookUri: UriComponents): void;
1394 > }
1395 >
1396 > export interface MainThreadNotebookRenderersShape extends IDisposable {
1397 > $postMessage(editorId: string | undefined, rendererId: string, message: unknown): Promise<boolean>;
1398 > }
1399 >
1400 > export interface MainThreadInteractiveShape extends IDisposable {
1401 > }
1402 >
1403 > export interface MainThreadSpeechShape extends IDisposable {
1404 > $registerProvider(handle: number, identifier: string, metadata: ISpeechProviderMetadata): void;
1405 > $unregisterProvider(handle: number): void;
1406 >
1407 > $emitSpeechToTextEvent(session: number, event: ISpeechToTextEvent): void;
1408 > $emitTextToSpeechEvent(session: number, event: ITextToSpeechEvent): void;
1409 > $emitKeywordRecognitionEvent(session: number, event: IKeywordRecognitionEvent): void;
1410 > }
1411 >
1412 > export interface ExtHostSpeechShape {
1413 > $createSpeechToTextSession(handle: number, session: number, language?: string): Promise<void>;
1414 > $cancelSpeechToTextSession(session: number): Promise<void>;
1415 >
1416 > $createTextToSpeechSession(handle: number, session: number, language?: string): Promise<void>;
1417 > $synthesizeSpeech(session: number, text: string): Promise<void>;
1418 > $cancelTextToSpeechSession(session: number): Promise<void>;
1419 >
1420 > $createKeywordRecognitionSession(handle: number, session: number): Promise<void>;
1421 > $cancelKeywordRecognitionSession(session: number): Promise<void>;
1422 > }
1423 >
1424 > export interface BrowserTabDto {
1425 > id: string;
1426 > url: string;
1427 > title: string;
1428 > favicon: string | undefined;
1429 > }
1430 >
1431 > export interface MainThreadBrowsersShape extends IDisposable {
1432 > $openBrowserTab(url: string, viewColumn?: EditorGroupColumn, options?: IEditorOptions): Promise<BrowserTabDto>;
1433 > $closeBrowserTab(browserId: string): Promise<void>;
1434 > $startCDPSession(sessionId: string, browserId: string): Promise<void>;
1435 > $closeCDPSession(sessionId: string): Promise<void>;
1436 > $sendCDPMessage(sessionId: string, message: CDPRequest): Promise<void>;
1437 > }
1438 >
1439 > export interface ExtHostBrowsersShape {
1440 > $onDidOpenBrowserTab(browser: BrowserTabDto): void;
1441 > $onDidCloseBrowserTab(browserId: string): void;
1442 > $onDidChangeActiveBrowserTab(browserId: string | undefined): void;
1443 > $onDidChangeBrowserTabState(browser: BrowserTabDto): void;
1444 > $onCDPSessionMessage(sessionId: string, message: CDPResponse | CDPEvent): void;
1445 > $onCDPSessionClosed(sessionId: string): void;
1446 > }
1447 >
1448 > export interface MainThreadLanguageModelsShape extends IDisposable {
1449 > $registerLanguageModelProvider(vendor: string): void;
1450 > $onLMProviderChange(vendor: string): void;
1451 > $unregisterProvider(vendor: string): void;
1452 > $tryStartChatRequest(extension: ExtensionIdentifier, modelIdentifier: string, requestId: number, messages: SerializableObjectWithBuffers<IChatMessage[]>, options: {}, token: CancellationToken): Promise<void>;
1453 > $reportResponsePart(requestId: number, chunk: SerializableObjectWithBuffers<IChatResponsePart | IChatResponsePart[]>): Promise<void>;
1454 > $reportResponseDone(requestId: number, error: SerializedError | undefined): Promise<void>;
1455 > $selectChatModels(selector: ILanguageModelChatSelector): Promise<string[]>;
1456 > $countTokens(modelId: string, value: string | IChatMessage, token: CancellationToken): Promise<number>;
1457 > $cancelLanguageModelChatRequest(requestId: number): void;
1458 > $fileIsIgnored(uri: UriComponents, token: CancellationToken): Promise<boolean>;
1459 > $registerFileIgnoreProvider(handle: number): void;
1460 > $unregisterFileIgnoreProvider(handle: number): void;
1461 > }
1462 >
1463 > export interface ExtHostLanguageModelsShape {
1464 > $provideLanguageModelChatInfo(vendor: string, options: ILanguageModelChatInfoOptions, token: CancellationToken): Promise<ILanguageModelChatMetadataAndIdentifier[]>;
1465 > $updateModelAccesslist(data: { from: ExtensionIdentifier; to: ExtensionIdentifier; enabled: boolean }[]): void;
1466 > $onChatModelsChange(): void;
1467 > $startChatRequest(modelId: string, requestId: number, from: ExtensionIdentifier | undefined, messages: SerializableObjectWithBuffers<IChatMessage[]>, options: ILanguageModelChatRequestOptions, token: CancellationToken): Promise<void>;
1468 > $acceptResponsePart(requestId: number, chunk: SerializableObjectWithBuffers<IChatResponsePart | IChatResponsePart[]>): Promise<void>;
1469 > $acceptResponseDone(requestId: number, error: SerializedError | undefined): Promise<void>;
1470 > $cancelLanguageModelChatRequest(requestId: number): void;
1471 > $provideTokenLength(modelId: string, value: string | IChatMessage, token: CancellationToken): Promise<number>;
1472 > $isFileIgnored(handle: number, uri: UriComponents, token: CancellationToken): Promise<boolean>;
1473 > }
1474 >
1475 > export type IChatContextItemDto = Dto<IChatContextItem>;
1476 >
1477 > export interface ExtHostChatContextShape {
1478 > $provideWorkspaceChatContext(handle: number, token: CancellationToken): Promise<IChatContextItem[]>;
1479 > $provideExplicitChatContext(handle: number, token: CancellationToken): Promise<IChatContextItem[]>;
1480 > $resolveExplicitChatContext(handle: number, context: IChatContextItem, token: CancellationToken): Promise<IChatContextItem>;
1481 > $provideResourceChatContext(handle: number, options: { resource: UriComponents; withValue: boolean; viewType?: string }, token: CancellationToken): Promise<IChatContextItem | undefined>;
1482 > $resolveResourceChatContext(handle: number, context: IChatContextItem, token: CancellationToken): Promise<IChatContextItem>;
1483 > $executeChatContextItemCommand(itemHandle: number): Promise<void>;
1484 > }
1485 >
1486 > export interface MainThreadChatContextShape extends IDisposable {
1487 > $registerChatWorkspaceContextProvider(handle: number, id: string): void;
1488 > $registerChatExplicitContextProvider(handle: number, id: string): void;
1489 > $registerChatResourceContextProvider(handle: number, id: string, selector: ITabSelectorDto): void;
1490 > $unregisterChatContextProvider(handle: number): void;
1491 > $updateWorkspaceContextItems(handle: number, items: IChatContextItemDto[]): void;
1492 > $executeChatContextItemCommand(itemHandle: number): Promise<void>;
1493 > }
1494 >
1495 > export interface IChatDebugEventCommonDto {
1496 > readonly id?: string;
1497 > readonly sessionResource?: UriComponents;
1498 > readonly created: number;
1499 > readonly parentEventId?: string;
1500 > }
1501 >
1502 > export interface IChatDebugToolCallEventDto extends IChatDebugEventCommonDto {
1503 > readonly kind: 'toolCall';
1504 > readonly toolName: string;
1505 > readonly toolCallId?: string;
1506 > readonly input?: string;
1507 > readonly output?: string;
1508 > readonly result?: 'success' | 'error';
1509 > readonly durationInMillis?: number;
1510 > }
1511 >
1512 > export interface IChatDebugModelTurnEventDto extends IChatDebugEventCommonDto {
1513 > readonly kind: 'modelTurn';
1514 > readonly model?: string;
1515 > readonly requestName?: string;
1516 > readonly inputTokens?: number;
1517 > readonly outputTokens?: number;
1518 > readonly cachedTokens?: number;
1519 > readonly totalTokens?: number;
1520 > readonly copilotUsageNanoAiu?: number;
1521 > readonly durationInMillis?: number;
1522 > }
1523 >
1524 > export interface IChatDebugGenericEventDto extends IChatDebugEventCommonDto {
1525 > readonly kind: 'generic';
1526 > readonly name: string;
1527 > readonly details?: string;
1528 > readonly level: number;
1529 > readonly category?: string;
1530 > }
1531 >
1532 > export interface IChatDebugSubagentInvocationEventDto extends IChatDebugEventCommonDto {
1533 > readonly kind: 'subagentInvocation';
1534 > readonly agentName: string;
1535 > readonly description?: string;
1536 > readonly status?: 'running' | 'completed' | 'failed';
1537 > readonly durationInMillis?: number;
1538 > readonly toolCallCount?: number;
1539 > readonly modelTurnCount?: number;
1540 > }
1541 >
1542 > export interface IChatDebugMessageSectionDto {
1543 > readonly name: string;
1544 > readonly content: string;
1545 > }
1546 >
1547 > export interface IChatDebugUserMessageEventDto extends IChatDebugEventCommonDto {
1548 > readonly kind: 'userMessage';
1549 > readonly message: string;
1550 > readonly sections: readonly IChatDebugMessageSectionDto[];
1551 > }
1552 >
1553 > export interface IChatDebugAgentResponseEventDto extends IChatDebugEventCommonDto {
1554 > readonly kind: 'agentResponse';
1555 > readonly message: string;
1556 > readonly sections: readonly IChatDebugMessageSectionDto[];
1557 > }
1558 >
1559 > export type IChatDebugEventDto = IChatDebugToolCallEventDto | IChatDebugModelTurnEventDto | IChatDebugGenericEventDto | IChatDebugSubagentInvocationEventDto | IChatDebugUserMessageEventDto | IChatDebugAgentResponseEventDto;
1560 >
1561 > export interface IChatDebugEventTextContentDto {
1562 > readonly kind: 'text';
1563 > readonly value: string;
1564 > }
1565 >
1566 > export interface IChatDebugEventMessageContentDto {
1567 > readonly kind: 'message';
1568 > readonly type: 'user' | 'agent';
1569 > readonly message: string;
1570 > readonly sections: readonly IChatDebugMessageSectionDto[];
1571 > }
1572 >
1573 > export interface IChatDebugEventToolCallContentDto {
1574 > readonly kind: 'toolCall';
1575 > readonly toolName: string;
1576 > readonly result?: 'success' | 'error';
1577 > readonly durationInMillis?: number;
1578 > readonly input?: string;
1579 > readonly output?: string;
1580 > }
1581 >
1582 > export interface IChatDebugEventModelTurnContentDto {
1583 > readonly kind: 'modelTurn';
1584 > readonly requestName: string;
1585 > readonly model?: string;
1586 > readonly status?: string;
1587 > readonly durationInMillis?: number;
1588 > readonly timeToFirstTokenInMillis?: number;
1589 > readonly requestId?: string;
1590 > readonly maxInputTokens?: number;
1591 > readonly maxOutputTokens?: number;
1592 > readonly inputTokens?: number;
1593 > readonly outputTokens?: number;
1594 > readonly cachedTokens?: number;
1595 > readonly totalTokens?: number;
1596 > readonly requestOptions?: string;
1597 > readonly errorMessage?: string;
1598 > readonly sections?: readonly IChatDebugMessageSectionDto[];
1599 > }
1600 >
1601 > export interface IChatDebugEventHookContentDto {
1602 > readonly kind: 'hook';
1603 > readonly hookType: string;
1604 > readonly command?: string;
1605 > readonly result?: 'success' | 'error' | 'nonBlockingError';
1606 > readonly durationInMillis?: number;
1607 > readonly input?: string;
1608 > readonly output?: string;
1609 > readonly exitCode?: number;
1610 > readonly errorMessage?: string;
1611 > }
1612 >
1613 > export type IChatDebugResolvedEventContentDto = IChatDebugEventTextContentDto | IChatDebugEventMessageContentDto | IChatDebugEventToolCallContentDto | IChatDebugEventModelTurnContentDto | IChatDebugEventHookContentDto;
1614 >
1615 > export interface ExtHostChatDebugShape {
1616 > $provideChatDebugLog(handle: number, sessionResource: UriComponents, token: CancellationToken): Promise<IChatDebugEventDto[] | undefined>;
1617 > $resolveChatDebugLogEvent(handle: number, eventId: string, token: CancellationToken): Promise<IChatDebugResolvedEventContentDto | undefined>;
1618 > $exportChatDebugLog(handle: number, sessionResource: UriComponents, coreEvents: IChatDebugEventDto[], sessionTitle: string | undefined, token: CancellationToken): Promise<VSBuffer | undefined>;
1619 > $importChatDebugLog(handle: number, data: VSBuffer, token: CancellationToken): Promise<{ uri: UriComponents; sessionTitle?: string } | undefined>;
1620 > $getAvailableDebugSessionResources(handle: number, token: CancellationToken): Promise<{ uri: UriComponents; title?: string }[]>;
1621 > $onCoreDebugEvent(event: IChatDebugEventDto): void;
1622 > }
1623 >
1624 > export interface MainThreadChatDebugShape extends IDisposable {
1625 > $registerChatDebugLogProvider(handle: number): void;
1626 > $unregisterChatDebugLogProvider(handle: number): void;
1627 > $acceptChatDebugEvent(handle: number, event: IChatDebugEventDto): void;
1628 > $subscribeToCoreDebugEvents(): void;
1629 > $unsubscribeFromCoreDebugEvents(): void;
1630 > }
1631 >
1632 > export interface MainThreadEmbeddingsShape extends IDisposable {
1633 > $registerEmbeddingProvider(handle: number, identifier: string): void;
1634 > $unregisterEmbeddingProvider(handle: number): void;
1635 > $computeEmbeddings(embeddingsModel: string, input: string[], token: CancellationToken): Promise<({ values: number[] }[])>;
1636 > }
1637 >
1638 > export interface ExtHostEmbeddingsShape {
1639 > $provideEmbeddings(handle: number, input: string[], token: CancellationToken): Promise<{ values: number[] }[]>;
1640 > $acceptEmbeddingModels(models: string[]): void;
1641 > }
1642 >
1643 > export interface IExtensionChatAgentMetadata extends Dto<IChatAgentMetadata> {
1644 > hasFollowups?: boolean;
1645 > }
1646 >
1647 > export interface IDynamicChatAgentProps {
1648 > name: string;
1649 > publisherName: string;
1650 > description?: string;
1651 > fullName?: string;
1652 > }
1653 >
1654 > export interface IChatAgentProgressShape {
1655 > $handleProgressChunk(requestId: string, chunks: (IChatProgressDto | [IChatProgressDto, number])[]): Promise<void>;
1656 > $handleAnchorResolve(requestId: string, handle: string, anchor: Dto<IChatContentInlineReference>): void;
1657 > }
1658 >
1659 > export interface MainThreadChatAgentsShape2 extends IChatAgentProgressShape, IDisposable {
1660 > $registerAgent(handle: number, extension: ExtensionIdentifier, id: string, metadata: IExtensionChatAgentMetadata, dynamicProps: IDynamicChatAgentProps | undefined): void;
1661 > $registerChatParticipantDetectionProvider(handle: number): void;
1662 > $unregisterChatParticipantDetectionProvider(handle: number): void;
1663 > $registerPromptFileProvider(handle: number, type: string, extension: ExtensionIdentifier): void;
1664 > $unregisterPromptFileProvider(handle: number): void;
1665 > $onDidChangePromptFiles(handle: number): void;
1666 > $registerChatSessionCustomizationProvider(handle: number, chatSessionType: string, metadata: IChatSessionCustomizationProviderMetadataDto, extension: ExtensionIdentifier): void;
1667 > $unregisterChatSessionCustomizationProvider(handle: number): void;
1668 > $onDidChangeCustomizations(handle: number): void;
1669 > $registerAgentCompletionsProvider(handle: number, id: string, triggerCharacters: string[]): void;
1670 > $unregisterAgentCompletionsProvider(handle: number, id: string): void;
1671 > $updateAgent(handle: number, metadataUpdate: IExtensionChatAgentMetadata): void;
1672 > $unregisterAgent(handle: number): void;
1673 >
1674 > $transferActiveChatSession(toWorkspace: UriComponents): Promise<void>;
1675 > $provideCustomAgents(token: CancellationToken): Promise<ICustomAgentDto[]>;
1676 > $provideInstructions(token: CancellationToken): Promise<IInstructionDto[]>;
1677 > $provideSkills(token: CancellationToken): Promise<ISkillDto[]>;
1678 > $provideSlashCommands(token: CancellationToken): Promise<ISlashCommandDto[]>;
1679 > $provideHooks(token: CancellationToken): Promise<IHookDto[]>;
1680 > $providePlugins(token: CancellationToken): Promise<IPluginDto[]>;
1681 > }
1682 >
1683 > export interface ICodeMapperTextEdit {
1684 > uri: URI;
1685 > edits: languages.TextEdit[];
1686 > }
1687 >
1688 > export interface ICodeMapperNotebookEditDto {
1689 > uri: URI;
1690 > edits: ICellEditOperationDto[];
1691 > }
1692 >
1693 > export type ICodeMapperProgressDto = Dto<ICodeMapperTextEdit> | Dto<ICodeMapperNotebookEditDto>;
1694 >
1695 > export interface MainThreadCodeMapperShape extends IDisposable {
1696 > $registerCodeMapperProvider(handle: number, displayName: string): void;
1697 > $unregisterCodeMapperProvider(handle: number): void;
1698 > $handleProgress(requestId: string, data: ICodeMapperProgressDto): Promise<void>;
1699 > }
1700 >
1701 > export interface IChatAgentCompletionItem {
1702 > id: string;
1703 > fullName?: string;
1704 > icon?: string;
1705 > insertText?: string;
1706 > label: string | languages.CompletionItemLabel;
1707 > value: IChatRequestVariableValueDto;
1708 > detail?: string;
1709 > documentation?: string | IMarkdownString;
1710 > command?: ICommandDto;
1711 > }
1712 >
1713 > export type IChatContentProgressDto =
1714 > | Dto<Exclude<IChatProgressHistoryResponseContent, IChatTask | IChatMultiDiffData>>
1715 > | IChatMultiDiffDataSerialized
1716 > | IChatTaskDto;
1717 >
1718 > export type IChatAgentHistoryEntryDto = {
1719 > request: IChatAgentRequest;
1720 > response: ReadonlyArray<IChatContentProgressDto>;
1721 > result: IChatAgentResult;
1722 > };
1723 >
1724 > export interface IChatSessionContextDto {
1725 > readonly chatSessionResource: UriComponents;
1726 > readonly isUntitled: boolean;
1727 > readonly initialSessionOptions?: ReadonlyArray<{ optionId: string; value: string }>;
1728 > }
1729 >
1730 > export interface IChatAgentInvokeResult extends IChatAgentResult {
1731 > /** Error callstack for telemetry only. Stripped at the RPC boundary — never persisted or sent to the model. */
1732 > errorCallstack?: string;
1733 > /** Error name (e.g. 'ChatQuotaExceeded', 'TypeError') for telemetry only. */
1734 > errorName?: string;
1735 > }
1736 >
1737 > export interface ExtHostChatAgentsShape2 {
1738 > $invokeAgent(handle: number, request: Dto<IChatAgentRequest>, context: { history: IChatAgentHistoryEntryDto[]; chatSessionContext?: IChatSessionContextDto }, token: CancellationToken): Promise<IChatAgentInvokeResult | undefined>;
1739 > $provideFollowups(request: Dto<IChatAgentRequest>, handle: number, result: IChatAgentResult, context: { history: IChatAgentHistoryEntryDto[] }, token: CancellationToken): Promise<IChatFollowup[]>;
1740 > $acceptFeedback(handle: number, result: IChatAgentResult, voteAction: IChatVoteAction): void;
1741 > $handleQuestionCarouselAnswer(requestId: string, resolveId: string, answers: Record<string, unknown> | undefined): void;
1742 > $acceptAction(handle: number, result: IChatAgentResult, action: IChatUserActionEvent): void;
1743 > $invokeCompletionProvider(handle: number, query: string, token: CancellationToken): Promise<IChatAgentCompletionItem[]>;
1744 > $provideChatTitle(handle: number, context: IChatAgentHistoryEntryDto[], token: CancellationToken): Promise<string | undefined>;
1745 > $provideChatSummary(handle: number, context: IChatAgentHistoryEntryDto[], token: CancellationToken): Promise<string | undefined>;
1746 > $releaseSession(sessionResource: UriComponents): void;
1747 > $detectChatParticipant(handle: number, request: Dto<IChatAgentRequest>, context: { history: IChatAgentHistoryEntryDto[] }, options: { participants: IChatParticipantMetadata[]; location: ChatAgentLocation }, token: CancellationToken): Promise<IChatParticipantDetectionResult | null | undefined>;
1748 > $providePromptFiles(handle: number, type: PromptsType, context: IPromptFileContext, token: CancellationToken): Promise<Dto<IPromptFileResource>[] | undefined>;
1749 > $provideChatSessionCustomizations(handle: number, sessionResource: UriComponents, token: CancellationToken): Promise<IChatSessionCustomizationItemDto[] | undefined>;
1750 > $provideSourceFolders(handle: number, sessionResource: UriComponents, type: string, token: CancellationToken): Promise<IChatSessionCustomizationSourceFolderDto[] | undefined>;
1751 > $setRequestTools(requestId: string, tools: UserSelectedTools): void;
1752 > $setYieldRequested(requestId: string, value: boolean): void;
1753 > $acceptActiveChatSession(sessionResource: UriComponents | undefined): void;
1754 > $onDidChangeCustomAgents(): void;
1755 > $onDidChangeInstructions(): void;
1756 > $onDidChangeSkills(): void;
1757 > $onDidChangeSlashCommands(): void;
1758 > $onDidChangeHooks(): void;
1759 > $onDidChangePlugins(): void;
1760 > }
1761 >
1762 > export type IChatResourceSourceDto = 'local' | 'user' | 'extension' | 'plugin' | 'builtin';
1763 >
1764 > export interface IChatResourceDto {
1765 > readonly uri: UriComponents;
1766 > readonly name: string;
1767 > readonly description?: string;
1768 > readonly source: IChatResourceSourceDto;
1769 > readonly extensionId?: string;
1770 > readonly pluginUri?: UriComponents;
1771 > readonly sessionTypes?: readonly string[];
1772 > }
1773 >
1774 > export interface ICustomAgentDto extends IChatResourceDto {
1775 > readonly argumentHint?: string;
1776 > readonly tools?: readonly string[];
1777 > readonly model?: readonly string[];
1778 > readonly userInvocable: boolean;
1779 > readonly disableModelInvocation: boolean;
1780 > readonly enabled: boolean;
1781 > }
1782 >
1783 > export interface IInstructionDto extends IChatResourceDto {
1784 > readonly pattern?: string;
1785 > }
1786 >
1787 > export interface ISkillDto extends IChatResourceDto {
1788 > readonly userInvocable: boolean;
1789 > readonly disableModelInvocation: boolean;
1790 > }
1791 >
1792 > export interface ISlashCommandDto extends IChatResourceDto {
1793 > readonly argumentHint?: string;
1794 > readonly userInvocable: boolean;
1795 > }
1796 >
1797 > export interface IHookDto {
1798 > readonly uri: UriComponents;
1799 > readonly sessionTypes?: readonly string[];
1800 > readonly source: IChatResourceSourceDto;
1801 > readonly extensionId?: string;
1802 > readonly pluginUri?: UriComponents;
1803 > }
1804 >
1805 > export interface IPluginDto {
1806 > readonly uri: UriComponents;
1807 > }
1808 >
1809 > export interface IChatSessionCustomizationProviderMetadataDto {
1810 > readonly label: string;
1811 > readonly iconId?: string;
1812 > readonly supportedTypes?: readonly string[];
1813 > }
1814 >
1815 > export interface IChatSessionCustomizationItemDto {
1816 > readonly uri: UriComponents;
1817 > readonly type: string;
1818 > readonly name: string;
1819 > readonly source: IChatResourceSourceDto;
1820 > readonly description?: string;
1821 > readonly groupKey?: string;
1822 > readonly badge?: string;
1823 > readonly extensionId?: string;
1824 > readonly pluginUri?: UriComponents;
1825 > readonly pluginLabel?: string;
1826 > readonly badgeTooltip?: string;
1827 > readonly userInvocable?: boolean;
1828 > }
1829 >
1830 > export interface IChatSessionCustomizationSourceFolderDto {
1831 > readonly uri: UriComponents;
1832 > readonly label: string;
1833 > readonly source: IChatResourceSourceDto;
1834 > }
1835 > export interface IChatParticipantMetadata {
1836 > participant: string;
1837 > command?: string;
1838 > disambiguation: { category: string; description: string; examples: string[] }[];
1839 > }
1840 >
1841 > export interface IChatParticipantDetectionResult {
1842 > participant: string;
1843 > command?: string;
1844 > }
1845 >
1846 > export interface IToolDataDto {
1847 > id: string;
1848 > toolReferenceName?: string;
1849 > legacyToolReferenceFullNames?: readonly string[];
1850 > fullReferenceName: string | undefined;
1851 > tags?: readonly string[];
1852 > displayName: string;
1853 > userDescription?: string;
1854 > modelDescription: string;
1855 > source: Dto<ToolDataSource>;
1856 > inputSchema?: IJSONSchema;
1857 > }
1858 >
1859 > export interface ILanguageModelChatSelectorDto {
1860 > vendor?: string;
1861 > family?: string;
1862 > version?: string;
1863 > id?: string;
1864 > }
1865 >
1866 > export interface IToolDefinitionDto extends IToolDataDto {
1867 > icon?: IconPathDto;
1868 > models?: ILanguageModelChatSelectorDto[];
1869 > toolSet?: string;
1870 > }
1871 >
1872 > export interface MainThreadLanguageModelToolsShape extends IDisposable {
1873 > $getTools(): Promise<Dto<IToolDataDto>[]>;
1874 > $acceptToolProgress(callId: string, progress: IToolProgressStep): void;
1875 > $invokeTool(dto: Dto<IToolInvocation>, token?: CancellationToken): Promise<Dto<IToolResult> | SerializableObjectWithBuffers<Dto<IToolResult>>>;
1876 > $countTokensForInvocation(callId: string, input: string, token: CancellationToken): Promise<number>;
1877 > $registerTool(id: string, hasHandleToolStream: boolean): void;
1878 > $registerToolWithDefinition(extensionId: ExtensionIdentifier, definition: IToolDefinitionDto, hasHandleToolStream: boolean): void;
1879 > $unregisterTool(name: string): void;
1880 > }
1881 >
1882 > export type IChatRequestVariableValueDto = Dto<IChatRequestVariableValue>;
1883 >
1884 > export interface ExtHostLanguageModelToolsShape {
1885 > $onDidChangeTools(tools: IToolDataDto[]): void;
1886 > $invokeTool(dto: Dto<IToolInvocation>, token: CancellationToken): Promise<Dto<IToolResult> | SerializableObjectWithBuffers<Dto<IToolResult>>>;
1887 > $countTokensForInvocation(callId: string, input: string, token: CancellationToken): Promise<number>;
1888 >
1889 > $handleToolStream(toolId: string, context: IToolInvocationStreamContext, token: CancellationToken): Promise<IStreamedToolInvocation | undefined>;
1890 > $prepareToolInvocation(toolId: string, context: IToolInvocationPreparationContext, token: CancellationToken): Promise<IPreparedToolInvocation | undefined>;
1891 > }
1892 >
1893 > export interface MainThreadUrlsShape extends IDisposable {
1894 > $registerUriHandler(handle: number, extensionId: ExtensionIdentifier, extensionDisplayName: string): Promise<void>;
1895 > $unregisterUriHandler(handle: number): Promise<void>;
1896 > $createAppUri(uri: UriComponents): Promise<UriComponents>;
1897 > }
1898 >
1899 > export interface IChatResponseProgressFileTreeData {
1900 > label: string;
1901 > uri: URI;
1902 > children?: IChatResponseProgressFileTreeData[];
1903 > }
1904 >
1905 > export type IDocumentContextDto = {
1906 > uri: UriComponents;
1907 > version: number;
1908 > ranges: IRange[];
1909 > };
1910 >
1911 > export type IChatProgressDto =
1912 > | Dto<Exclude<IChatProgress, IChatTask | IChatNotebookEdit>>
1913 > | IChatTaskDto
1914 > | IChatNotebookEditDto
1915 > | IChatExternalEditsDto
1916 > | IChatResponseClearToPreviousToolInvocationDto
1917 > | IChatBeginToolInvocationDto
1918 > | IChatUpdateToolInvocationDto
1919 > | IChatUsageDto;
1920 >
1921 > export interface ExtHostUrlsShape {
1922 > $handleExternalUri(handle: number, uri: UriComponents): Promise<void>;
1923 > }
1924 >
1925 > export interface MainThreadUriOpenersShape extends IDisposable {
1926 > $registerUriOpener(id: string, schemes: readonly string[], extensionId: ExtensionIdentifier, label: string): Promise<void>;
1927 > $unregisterUriOpener(id: string): Promise<void>;
1928 > }
1929 >
1930 > export interface ExtHostUriOpenersShape {
1931 > $canOpenUri(id: string, uri: UriComponents, token: CancellationToken): Promise<languages.ExternalUriOpenerPriority>;
1932 > $openUri(id: string, context: { resolvedUri: UriComponents; sourceUri: UriComponents }, token: CancellationToken): Promise<void>;
1933 > }
1934 >
1935 > export interface MainThreadChatOutputRendererShape extends IDisposable {
1936 > $registerChatOutputRenderer(viewType: string, extensionId: ExtensionIdentifier, extensionLocation: UriComponents): void;
1937 > $unregisterChatOutputRenderer(viewType: string): void;
1938 > }
1939 >
1940 > export interface IChatOutputRenderContextDto {
1941 > readonly codeBlockContext?: {
1942 > readonly languageIdentifier: string;
1943 > };
1944 > }
1945 >
1946 > export interface ExtHostChatOutputRendererShape {
1947 > $renderChatOutput(viewType: string, mime: string, valueData: VSBuffer, webviewHandle: string, context: IChatOutputRenderContextDto, token: CancellationToken): Promise<void>;
1948 > }
1949 >
1950 > export interface MainThreadProfileContentHandlersShape {
1951 > $registerProfileContentHandler(id: string, name: string, description: string | undefined, extensionId: string): Promise<void>;
1952 > $unregisterProfileContentHandler(id: string): Promise<void>;
1953 > }
1954 >
1955 > export interface ExtHostProfileContentHandlersShape {
1956 > $saveProfile(id: string, name: string, content: string, token: CancellationToken): Promise<UriDto<ISaveProfileResult> | null>;
1957 > $readProfile(id: string, idOrUri: string | UriComponents, token: CancellationToken): Promise<string | null>;
1958 > }
1959 >
1960 > export interface ITextSearchComplete {
1961 > limitHit?: boolean;
1962 > message?: TextSearchCompleteMessage | TextSearchCompleteMessage[];
1963 > }
1964 >
1965 > export interface ResourceTrustRequestOptionsDto {
1966 > readonly uri: UriComponents;
1967 > readonly message?: string;
1968 > }
1969 >
1970 > export interface MainThreadWorkspaceShape extends IDisposable {
1971 > $startFileSearch(includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<UriComponents[] | null>;
1972 > $startTextSearch(query: search.IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null>;
1973 > $checkExists(folders: readonly UriComponents[], includes: string[], token: CancellationToken): Promise<boolean>;
1974 > $save(uri: UriComponents, options: { saveAs: boolean }): Promise<UriComponents | undefined>;
1975 > $saveAll(includeUntitled?: boolean): Promise<boolean>;
1976 > $updateWorkspaceFolders(extensionName: string, index: number, deleteCount: number, workspaceFoldersToAdd: { uri: UriComponents; name?: string }[]): Promise<void>;
1977 > $resolveProxy(url: string): Promise<string | undefined>;
1978 > $lookupAuthorization(authInfo: AuthInfo): Promise<Credentials | undefined>;
1979 > $lookupKerberosAuthorization(url: string): Promise<string | undefined>;
1980 > $loadCertificates(): Promise<string[]>;
1981 > $requestResourceTrust(options: ResourceTrustRequestOptionsDto): Promise<boolean | undefined>;
1982 > $requestWorkspaceTrust(options?: WorkspaceTrustRequestOptions): Promise<boolean | undefined>;
1983 > $isResourceTrusted(resource: UriComponents): Promise<boolean>;
1984 > $registerEditSessionIdentityProvider(handle: number, scheme: string): void;
1985 > $unregisterEditSessionIdentityProvider(handle: number): void;
1986 > $registerCanonicalUriProvider(handle: number, scheme: string): void;
1987 > $unregisterCanonicalUriProvider(handle: number): void;
1988 > $resolveDecoding(resource: UriComponents | undefined, options?: { encoding?: string }): Promise<{ preferredEncoding: string; guessEncoding: boolean; candidateGuessEncodings: string[] }>;
1989 > $validateDetectedEncoding(resource: UriComponents | undefined, detectedEncoding: string, options?: { encoding?: string }): Promise<string>;
1990 > $resolveEncoding(resource: UriComponents | undefined, options?: { encoding?: string }): Promise<{ encoding: string; addBOM: boolean }>;
1991 > }
1992 >
1993 > export interface IFileChangeDto {
1994 > resource: UriComponents;
1995 > type: files.FileChangeType;
1996 > }
1997 >
1998 > export interface MainThreadFileSystemShape extends IDisposable {
1999 > $registerFileSystemProvider(handle: number, scheme: string, capabilities: files.FileSystemProviderCapabilities, readonlyMessage?: IMarkdownString): Promise<void>;
2000 > $unregisterProvider(handle: number): void;
2001 > $onFileSystemChange(handle: number, resource: IFileChangeDto[]): void;
2002 >
2003 > $stat(resource: UriComponents): Promise<files.IStat>;
2004 > $readdir(resource: UriComponents): Promise<[string, files.FileType][]>;
2005 > $readFile(resource: UriComponents): Promise<VSBuffer>;
2006 > $writeFile(resource: UriComponents, content: VSBuffer): Promise<void>;
2007 > $rename(resource: UriComponents, target: UriComponents, opts: files.IFileOverwriteOptions): Promise<void>;
2008 > $copy(resource: UriComponents, target: UriComponents, opts: files.IFileOverwriteOptions): Promise<void>;
2009 > $mkdir(resource: UriComponents): Promise<void>;
2010 > $delete(resource: UriComponents, opts: files.IFileDeleteOptions): Promise<void>;
2011 >
2012 > $ensureActivation(scheme: string): Promise<void>;
2013 > }
2014 >
2015 > export interface MainThreadFileSystemEventServiceShape extends IDisposable {
2016 > $watch(extensionId: string, session: number, resource: UriComponents, opts: files.IWatchOptions, correlate: boolean): void;
2017 > $unwatch(session: number): void;
2018 > }
2019 >
2020 > export interface MainThreadLabelServiceShape extends IDisposable {
2021 > $registerResourceLabelFormatter(handle: number, formatter: ResourceLabelFormatter): void;
2022 > $unregisterResourceLabelFormatter(handle: number): void;
2023 > }
2024 >
2025 > export interface MainThreadSearchShape extends IDisposable {
2026 > $registerFileSearchProvider(handle: number, scheme: string): void;
2027 > $registerAITextSearchProvider(handle: number, scheme: string): void;
2028 > $registerTextSearchProvider(handle: number, scheme: string): void;
2029 > $unregisterProvider(handle: number): void;
2030 > $handleFileMatch(handle: number, session: number, data: UriComponents[]): void;
2031 > $handleTextMatch(handle: number, session: number, data: search.IRawFileMatch2[]): void;
2032 > $handleKeywordResult(handle: number, session: number, data: AISearchKeyword): void;
2033 > $handleTelemetry(eventName: string, data: any): void;
2034 > }
2035 >
2036 > export interface MainThreadShareShape extends IDisposable {
2037 > $registerShareProvider(handle: number, selector: IDocumentFilterDto[], id: string, label: string, priority: number): void;
2038 > $unregisterShareProvider(handle: number): void;
2039 > }
2040 >
2041 > export interface MainThreadTaskShape extends IDisposable {
2042 > $createTaskId(task: tasks.ITaskDTO): Promise<string>;
2043 > $registerTaskProvider(handle: number, type: string): Promise<void>;
2044 > $unregisterTaskProvider(handle: number): Promise<void>;
2045 > $fetchTasks(filter?: tasks.ITaskFilterDTO): Promise<tasks.ITaskDTO[]>;
2046 > $getTaskExecution(value: tasks.ITaskHandleDTO | tasks.ITaskDTO): Promise<tasks.ITaskExecutionDTO>;
2047 > $executeTask(task: tasks.ITaskHandleDTO | tasks.ITaskDTO): Promise<tasks.ITaskExecutionDTO>;
2048 > $terminateTask(id: string): Promise<void>;
2049 > $registerTaskSystem(scheme: string, info: tasks.ITaskSystemInfoDTO): void;
2050 > $customExecutionComplete(id: string, result?: number): Promise<void>;
2051 > $registerSupportedExecutions(custom?: boolean, shell?: boolean, process?: boolean): Promise<void>;
2052 > }
2053 >
2054 > export interface MainThreadExtensionServiceShape extends IDisposable {
2055 > $getExtension(extensionId: string): Promise<Dto<IExtensionDescription> | undefined>;
2056 > $activateExtension(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<void>;
2057 > $onWillActivateExtension(extensionId: ExtensionIdentifier): Promise<void>;
2058 > $onDidActivateExtension(extensionId: ExtensionIdentifier, codeLoadingTime: number, activateCallTime: number, activateResolvedTime: number, activationReason: ExtensionActivationReason): void;
2059 > $onExtensionActivationError(extensionId: ExtensionIdentifier, error: SerializedError, missingExtensionDependency: MissingExtensionDependency | null): Promise<void>;
2060 > $onExtensionRuntimeError(extensionId: ExtensionIdentifier, error: SerializedError): void;
2061 > $setPerformanceMarks(marks: performance.PerformanceMark[]): Promise<void>;
2062 > $asBrowserUri(uri: UriComponents): Promise<UriComponents>;
2063 > }
2064 >
2065 > export interface SCMProviderFeatures {
2066 > hasArtifactProvider?: boolean;
2067 > hasHistoryProvider?: boolean;
2068 > hasQuickDiffProvider?: boolean;
2069 > quickDiffLabel?: string;
2070 > hasSecondaryQuickDiffProvider?: boolean;
2071 > secondaryQuickDiffLabel?: string;
2072 > count?: number;
2073 > commitTemplate?: string;
2074 > acceptInputCommand?: languages.Command;
2075 > actionButton?: SCMActionButtonDto | null;
2076 > statusBarCommands?: ICommandDto[];
2077 > contextValue?: string;
2078 > }
2079 >
2080 > export interface SCMActionButtonDto {
2081 > command: ICommandDto & { shortTitle?: string };
2082 > secondaryCommands?: ICommandDto[][];
2083 > enabled: boolean;
2084 > }
2085 >
2086 > export interface SCMGroupFeatures {
2087 > hideWhenEmpty?: boolean;
2088 > contextValue?: string;
2089 > }
2090 >
2091 > export type SCMRawResource = [
2092 > number /*handle*/,
2093 > UriComponents /*resourceUri*/,
2094 > [UriComponents | ThemeIcon | undefined, UriComponents | ThemeIcon | undefined] /*icons: light, dark*/,
2095 > string /*tooltip*/,
2096 > boolean /*strike through*/,
2097 > boolean /*faded*/,
2098 > string /*context value*/,
2099 > ICommandDto | undefined /*command*/,
2100 > UriComponents | undefined /* multiFileDiffEditorOriginalUri */,
2101 > UriComponents | undefined /* multiFileDiffEditorModifiedUri */,
2102 > ];
2103 >
2104 > export type SCMRawResourceSplice = [
2105 > number /* start */,
2106 > number /* delete count */,
2107 > SCMRawResource[]
2108 > ];
2109 >
2110 > export type SCMRawResourceSplices = [
2111 > number, /*handle*/
2112 > SCMRawResourceSplice[]
2113 > ];
2114 >
2115 > export interface SCMHistoryItemRefDto {
2116 > readonly id: string;
2117 > readonly name: string;
2118 > readonly revision?: string;
2119 > readonly category?: string;
2120 > readonly description?: string;
2121 > readonly icon?: IconPathDto;
2122 > }
2123 >
2124 > export interface SCMHistoryItemRefsChangeEventDto {
2125 > readonly added: readonly SCMHistoryItemRefDto[];
2126 > readonly modified: readonly SCMHistoryItemRefDto[];
2127 > readonly removed: readonly SCMHistoryItemRefDto[];
2128 > readonly silent: boolean;
2129 > }
2130 >
2131 > export interface SCMHistoryItemDto {
2132 > readonly id: string;
2133 > readonly parentIds: string[];
2134 > readonly subject: string;
2135 > readonly message: string;
2136 > readonly displayId?: string;
2137 > readonly author?: string;
2138 > readonly authorIcon?: IconPathDto;
2139 > readonly authorEmail?: string;
2140 > readonly timestamp?: number;
2141 > readonly statistics?: {
2142 > readonly files: number;
2143 > readonly insertions: number;
2144 > readonly deletions: number;
2145 > };
2146 > readonly references?: SCMHistoryItemRefDto[];
2147 > readonly tooltip?: IMarkdownString | Array<IMarkdownString> | undefined;
2148 > }
2149 >
2150 > export interface SCMHistoryItemChangeDto {
2151 > readonly uri: UriComponents;
2152 > readonly originalUri: UriComponents | undefined;
2153 > readonly modifiedUri: UriComponents | undefined;
2154 > }
2155 >
2156 > export interface SCMArtifactGroupDto {
2157 > readonly id: string;
2158 > readonly name: string;
2159 > readonly icon?: UriComponents | { light: UriComponents; dark: UriComponents } | ThemeIcon;
2160 > readonly supportsFolders?: boolean;
2161 > }
2162 >
2163 > export interface SCMArtifactDto {
2164 > readonly id: string;
2165 > readonly name: string;
2166 > readonly description?: string;
2167 > readonly icon?: UriComponents | { light: UriComponents; dark: UriComponents } | ThemeIcon;
2168 > readonly timestamp?: number;
2169 > readonly command?: ICommandDto;
2170 > }
2171 >
2172 > export interface MainThreadSCMShape extends IDisposable {
2173 > $registerSourceControl(handle: number, parentHandle: number | undefined, id: string, label: string, rootUri: UriComponents | undefined, iconPath: IconPathDto | undefined, isHidden: boolean | undefined, inputBoxDocumentUri: UriComponents): Promise<void>;
2174 > $updateSourceControl(handle: number, features: SCMProviderFeatures): Promise<void>;
2175 > $unregisterSourceControl(handle: number): Promise<void>;
2176 >
2177 > $registerGroups(sourceControlHandle: number, groups: [number /*handle*/, string /*id*/, string /*label*/, SCMGroupFeatures, /* multiDiffEditorEnableViewChanges */ boolean][], splices: SCMRawResourceSplices[]): Promise<void>;
2178 > $updateGroup(sourceControlHandle: number, handle: number, features: SCMGroupFeatures): Promise<void>;
2179 > $updateGroupLabel(sourceControlHandle: number, handle: number, label: string): Promise<void>;
2180 > $unregisterGroup(sourceControlHandle: number, handle: number): Promise<void>;
2181 >
2182 > $spliceResourceStates(sourceControlHandle: number, splices: SCMRawResourceSplices[]): Promise<void>;
2183 >
2184 > $setInputBoxValue(sourceControlHandle: number, value: string): Promise<void>;
2185 > $setInputBoxPlaceholder(sourceControlHandle: number, placeholder: string): Promise<void>;
2186 > $setInputBoxEnablement(sourceControlHandle: number, enabled: boolean): Promise<void>;
2187 > $setInputBoxVisibility(sourceControlHandle: number, visible: boolean): Promise<void>;
2188 > $showValidationMessage(sourceControlHandle: number, message: string | IMarkdownString, type: InputValidationType): Promise<void>;
2189 > $setValidationProviderIsEnabled(sourceControlHandle: number, enabled: boolean): Promise<void>;
2190 >
2191 > $onDidChangeHistoryProviderCurrentHistoryItemRefs(sourceControlHandle: number, historyItemRef?: SCMHistoryItemRefDto, historyItemRemoteRef?: SCMHistoryItemRefDto, historyItemBaseRef?: SCMHistoryItemRefDto): Promise<void>;
2192 > $onDidChangeHistoryProviderHistoryItemRefs(sourceControlHandle: number, historyItemRefs: SCMHistoryItemRefsChangeEventDto): Promise<void>;
2193 >
2194 > $onDidChangeArtifacts(sourceControlHandle: number, groups: string[]): Promise<void>;
2195 > }
2196 >
2197 > export interface MainThreadQuickDiffShape extends IDisposable {
2198 > $registerQuickDiffProvider(handle: number, selector: IDocumentFilterDto[], id: string, label: string, rootUri: UriComponents | undefined): Promise<void>;
2199 > $unregisterQuickDiffProvider(handle: number): Promise<void>;
2200 > $createSourceControlDiffInformation(handle: number, uri: UriComponents): Promise<void>;
2201 > $disposeSourceControlDiffInformation(handle: number): Promise<void>;
2202 > }
2203 >
2204 > export interface IAgentEditorCommentDto {
2205 > id: string;
2206 > range: IRange;
2207 > body: string;
2208 > author?: string;
2209 > }
2210 >
2211 > export interface MainThreadAgentEditorCommentsShape extends IDisposable {
2212 > $createAgentEditorComments(handle: number, uri: UriComponents): Promise<void>;
2213 > $addComment(handle: number, range: IRange, body: string): Promise<void>;
2214 > $deleteComment(handle: number, id: string): Promise<void>;
2215 > $disposeAgentEditorComments(handle: number): Promise<void>;
2216 > }
2217 >
2218 > export interface ExtHostAgentEditorCommentsShape {
2219 > $acceptAgentEditorComments(handle: number, comments: IAgentEditorCommentDto[], acceptsComments: boolean): void;
2220 > }
2221 >
2222 > export interface IDocumentDiffLineChangeDto {
2223 > originalRange: IRange;
2224 > modifiedRange: IRange;
2225 > innerChanges: { originalRange: IRange; modifiedRange: IRange }[] | undefined;
2226 > }
2227 >
2228 > export interface IDocumentDiffMoveDto {
2229 > originalRange: IRange;
2230 > modifiedRange: IRange;
2231 > changes: IDocumentDiffLineChangeDto[];
2232 > }
2233 >
2234 > export interface IDocumentDiffResultDto {
2235 > identical: boolean;
2236 > quitEarly: boolean;
2237 > changes: IDocumentDiffLineChangeDto[];
2238 > moves: IDocumentDiffMoveDto[];
2239 > }
2240 >
2241 > export interface MainThreadDocumentDiffShape extends IDisposable {
2242 > $computeDocumentDiff(originalUri: UriComponents, modifiedUri: UriComponents, ignoreTrimWhitespace: boolean, maxComputationTimeMs: number, computeMoves: boolean): Promise<IDocumentDiffResultDto | null>;
2243 > }
2244 >
2245 > export type DebugSessionUUID = string;
2246 >
2247 > export interface IDebugConfiguration {
2248 > type: string;
2249 > name: string;
2250 > request: string;
2251 > [key: string]: any;
2252 > }
2253 >
2254 > export interface IStartDebuggingOptions {
2255 > parentSessionID?: DebugSessionUUID;
2256 > lifecycleManagedByParent?: boolean;
2257 > repl?: IDebugSessionReplMode;
2258 > noDebug?: boolean;
2259 > compact?: boolean;
2260 > suppressDebugToolbar?: boolean;
2261 > suppressDebugStatusbar?: boolean;
2262 > suppressDebugView?: boolean;
2263 > suppressSaveBeforeStart?: boolean;
2264 > testRun?: IDebugTestRunReference;
2265 > }
2266 >
2267 > export interface MainThreadDebugServiceShape extends IDisposable {
2268 > $registerDebugTypes(debugTypes: string[]): void;
2269 > $sessionCached(sessionID: string): void;
2270 > $acceptDAMessage(handle: number, message: DebugProtocol.ProtocolMessage): void;
2271 > $acceptDAError(handle: number, name: string, message: string, stack: string | undefined): void;
2272 > $acceptDAExit(handle: number, code: number | undefined, signal: string | undefined): void;
2273 > $registerDebugConfigurationProvider(type: string, triggerKind: DebugConfigurationProviderTriggerKind, hasProvideMethod: boolean, hasResolveMethod: boolean, hasResolve2Method: boolean, handle: number): Promise<void>;
2274 > $registerDebugAdapterDescriptorFactory(type: string, handle: number): Promise<void>;
2275 > $unregisterDebugConfigurationProvider(handle: number): void;
2276 > $unregisterDebugAdapterDescriptorFactory(handle: number): void;
2277 > $startDebugging(folder: UriComponents | undefined, nameOrConfig: string | IDebugConfiguration, options: IStartDebuggingOptions): Promise<boolean>;
2278 > $stopDebugging(sessionId: DebugSessionUUID | undefined): Promise<void>;
2279 > $setDebugSessionName(id: DebugSessionUUID, name: string): void;
2280 > $customDebugAdapterRequest(id: DebugSessionUUID, command: string, args: any): Promise<any>;
2281 > $getDebugProtocolBreakpoint(id: DebugSessionUUID, breakpoinId: string): Promise<DebugProtocol.Breakpoint | undefined>;
2282 > $appendDebugConsole(value: string): void;
2283 > $registerBreakpoints(breakpoints: Array<ISourceMultiBreakpointDto | IFunctionBreakpointDto | IDataBreakpointDto>): Promise<void>;
2284 > $unregisterBreakpoints(breakpointIds: string[], functionBreakpointIds: string[], dataBreakpointIds: string[]): Promise<void>;
2285 > $registerDebugVisualizer(extensionId: string, id: string): void;
2286 > $unregisterDebugVisualizer(extensionId: string, id: string): void;
2287 > $registerDebugVisualizerTree(treeId: string, canEdit: boolean): void;
2288 > $unregisterDebugVisualizerTree(treeId: string): void;
2289 > }
2290 >
2291 > export interface IOpenUriOptions {
2292 > readonly allowTunneling?: boolean;
2293 > readonly allowContributedOpeners?: boolean | string;
2294 > }
2295 >
2296 > export interface MainThreadWindowShape extends IDisposable {
2297 > $getInitialState(): Promise<{ isFocused: boolean; isActive: boolean }>;
2298 > $openUri(uri: UriComponents, uriString: string | undefined, options: IOpenUriOptions): Promise<boolean>;
2299 > $asExternalUri(uri: UriComponents, options: IOpenUriOptions): Promise<UriComponents>;
2300 > }
2301 >
2302 > export enum CandidatePortSource {
2303 > None = 0,
2304 > Process = 1,
2305 > Output = 2,
2306 > Hybrid = 3
2307 > }
2308 >
2309 > export interface PortAttributesSelector {
2310 > portRange?: [number, number] | number;
2311 > commandPattern?: RegExp;
2312 > }
2313 >
2314 > export interface MainThreadTunnelServiceShape extends IDisposable {
2315 > $openTunnel(tunnelOptions: TunnelOptions, source: string | undefined): Promise<TunnelDto | undefined>;
2316 > $closeTunnel(remote: { host: string; port: number }): Promise<void>;
2317 > $getTunnels(): Promise<TunnelDescription[]>;
2318 > $setTunnelProvider(features: TunnelProviderFeatures | undefined, enablePortsView: boolean): Promise<void>;
2319 > $hasTunnelProvider(): Promise<boolean>;
2320 > $setRemoteTunnelService(processId: number): Promise<void>;
2321 > $setCandidateFilter(): Promise<void>;
2322 > $onFoundNewCandidates(candidates: CandidatePort[]): Promise<void>;
2323 > $setCandidatePortSource(source: CandidatePortSource): Promise<void>;
2324 > $registerPortsAttributesProvider(selector: PortAttributesSelector, providerHandle: number): Promise<void>;
2325 > $unregisterPortsAttributesProvider(providerHandle: number): Promise<void>;
2326 > }
2327 >
2328 > export interface MainThreadTimelineShape extends IDisposable {
2329 > $registerTimelineProvider(provider: TimelineProviderDescriptor): void;
2330 > $unregisterTimelineProvider(source: string): void;
2331 > $emitTimelineChangeEvent(e: TimelineChangeEvent | undefined): void;
2332 > }
2333 >
2334 > export interface HoverWithId extends languages.Hover {
2335 > /**
2336 > * Id of the hover
2337 > */
2338 > id: number;
2339 > }
2340 >
2341 > // -- extension host
2342 >
2343 > export interface ICommandMetadataDto {
2344 > /**
2345 > * NOTE: Please use an ILocalizedString. string is in the type for backcompat for now.
2346 > * A short summary of what the command does. This will be used in:
2347 > * - API commands
2348 > * - when showing keybindings that have no other UX
2349 > * - when searching for commands in the Command Palette
2350 > */
2351 > readonly description: ILocalizedString | string;
2352 > readonly args?: ReadonlyArray<{
2353 > readonly name: string;
2354 > readonly isOptional?: boolean;
2355 > readonly description?: string;
2356 > }>;
2357 > readonly returns?: string;
2358 > }
2359 >
2360 > export interface ICodeMapperRequestDto extends Dto<ICodeMapperRequest> {
2361 > requestId: string;
2362 > }
2363 >
2364 > export interface ExtHostCodeMapperShape {
2365 > $mapCode(handle: number, request: ICodeMapperRequestDto, token: CancellationToken): Promise<ICodeMapperResult | null | undefined>;
2366 > }
2367 >
2368 > export interface ExtHostCommandsShape {
2369 > $executeContributedCommand(id: string, ...args: unknown[]): Promise<unknown>;
2370 > $getContributedCommandMetadata(): Promise<{ [id: string]: string | ICommandMetadataDto }>;
2371 > }
2372 >
2373 > export interface ExtHostConfigurationShape {
2374 > $initializeConfiguration(data: IConfigurationInitData): void;
2375 > $acceptConfigurationChanged(data: IConfigurationInitData, change: IConfigurationChange): void;
2376 > }
2377 >
2378 > export interface ExtHostDiagnosticsShape {
2379 > $acceptMarkersChange(data: [UriComponents, IMarkerData[]][]): void;
2380 > }
2381 >
2382 > export interface ExtHostDocumentContentProvidersShape {
2383 > $provideTextDocumentContent(handle: number, uri: UriComponents): Promise<string | null | undefined>;
2384 > }
2385 >
2386 > export interface IModelAddedData {
2387 > uri: UriComponents;
2388 > versionId: number;
2389 > lines: string[];
2390 > EOL: string;
2391 > languageId: string;
2392 > isDirty: boolean;
2393 > encoding: string;
2394 > }
2395 > export interface ExtHostDocumentsShape {
2396 > $acceptModelLanguageChanged(strURL: UriComponents, newLanguageId: string): void;
2397 > $acceptModelSaved(strURL: UriComponents): void;
2398 > $acceptDirtyStateChanged(strURL: UriComponents, isDirty: boolean): void;
2399 > $acceptEncodingChanged(strURL: UriComponents, encoding: string): void;
2400 > $acceptModelChanged(strURL: UriComponents, e: ISerializedModelContentChangedEvent, isDirty: boolean): void;
2401 > }
2402 >
2403 > export interface ExtHostDocumentSaveParticipantShape {
2404 > $participateInSave(resource: UriComponents, reason: SaveReason): Promise<boolean[]>;
2405 > }
2406 >
2407 > export interface ITextEditorAddData {
2408 > id: string;
2409 > documentUri: UriComponents;
2410 > options: IResolvedTextEditorConfiguration;
2411 > selections: ISelection[];
2412 > visibleRanges: IRange[];
2413 > editorPosition: EditorGroupColumn | undefined;
2414 > }
2415 > export interface ITextEditorPositionData {
2416 > [id: string]: EditorGroupColumn;
2417 > }
2418 >
2419 > export type ITextEditorChange = [
2420 > originalStartLineNumber: number,
2421 > originalEndLineNumberExclusive: number,
2422 > modifiedStartLineNumber: number,
2423 > modifiedEndLineNumberExclusive: number
2424 > ];
2425 >
2426 > export interface ITextEditorDiffInformation {
2427 > readonly documentVersion: number;
2428 > readonly original: UriComponents | undefined;
2429 > readonly modified: UriComponents;
2430 > readonly changes: readonly ITextEditorChange[];
2431 > }
2432 >
2433 > export interface IEditorPropertiesChangeData {
2434 > options: IResolvedTextEditorConfiguration | null;
2435 > selections: ISelectionChangeEvent | null;
2436 > visibleRanges: IRange[] | null;
2437 > }
2438 > export interface ISelectionChangeEvent {
2439 > selections: Selection[];
2440 > source?: string;
2441 > }
2442 >
2443 > export interface ExtHostEditorsShape {
2444 > $acceptEditorPropertiesChanged(id: string, props: IEditorPropertiesChangeData): void;
2445 > $acceptEditorPositionData(data: ITextEditorPositionData): void;
2446 > $acceptEditorDiffInformation(id: string, diffInformation: ITextEditorDiffInformation[] | undefined): void;
2447 > }
2448 >
2449 > export interface IDocumentsAndEditorsDelta {
2450 > removedDocuments?: UriComponents[];
2451 > addedDocuments?: IModelAddedData[];
2452 > removedEditors?: string[];
2453 > addedEditors?: ITextEditorAddData[];
2454 > newActiveEditor?: string | null;
2455 > }
2456 >
2457 > export interface ExtHostDocumentsAndEditorsShape {
2458 > $acceptDocumentsAndEditorsDelta(delta: IDocumentsAndEditorsDelta): void;
2459 > }
2460 >
2461 > export interface IDataTransferFileDTO {
2462 > readonly id: string;
2463 > readonly name: string;
2464 > readonly uri?: UriComponents;
2465 > }
2466 >
2467 > export interface DataTransferItemDTO {
2468 > id: string;
2469 > readonly asString: string;
2470 > readonly fileData: IDataTransferFileDTO | undefined;
2471 > readonly uriListData?: ReadonlyArray<string | UriComponents>;
2472 > }
2473 >
2474 > export interface DataTransferDTO {
2475 > items: Array<readonly [/* type */string, DataTransferItemDTO]>;
2476 > }
2477 >
2478 > export interface CheckboxUpdate {
2479 > treeItemHandle: string;
2480 > newState: boolean;
2481 > }
2482 >
2483 > export interface ExtHostTreeViewsShape {
2484 > /**
2485 > * To reduce what is sent on the wire:
2486 > * w
2487 > * x
2488 > * y
2489 > * z
2490 > *
2491 > * for [x,y] returns
2492 > * [[1,z]], where the inner array is [original index, ...children]
2493 > */
2494 > $getChildren(treeViewId: string, treeItemHandles?: string[]): Promise<(readonly (number | ITreeItem)[])[] | undefined>;
2495 > $handleDrop(destinationViewId: string, requestId: number, treeDataTransfer: DataTransferDTO, targetHandle: string | undefined, token: CancellationToken, operationUuid?: string, sourceViewId?: string, sourceTreeItemHandles?: string[]): Promise<void>;
2496 > $handleDrag(sourceViewId: string, sourceTreeItemHandles: string[], operationUuid: string, token: CancellationToken): Promise<DataTransferDTO | undefined>;
2497 > $setExpanded(treeViewId: string, treeItemHandle: string, expanded: boolean): void;
2498 > $setSelectionAndFocus(treeViewId: string, selectionHandles: string[], focusHandle: string): void;
2499 > $setVisible(treeViewId: string, visible: boolean): void;
2500 > $changeCheckboxState(treeViewId: string, checkboxUpdates: CheckboxUpdate[]): void;
2501 > $hasResolve(treeViewId: string): Promise<boolean>;
2502 > $resolve(treeViewId: string, treeItemHandle: string, token: CancellationToken): Promise<ITreeItem | undefined>;
2503 > }
2504 >
2505 > export interface ExtHostWorkspaceShape {
2506 > $initializeWorkspace(workspace: IWorkspaceData | null, trusted: boolean): void;
2507 > $acceptWorkspaceData(workspace: IWorkspaceData | null): void;
2508 > $handleTextSearchResult(result: search.IRawFileMatch2, requestId: number): void;
2509 > $onDidGrantWorkspaceTrust(): void;
2510 > $onDidChangeWorkspaceTrustedFolders(): void;
2511 > $getEditSessionIdentifier(folder: UriComponents, token: CancellationToken): Promise<string | undefined>;
2512 > $provideEditSessionIdentityMatch(folder: UriComponents, identity1: string, identity2: string, token: CancellationToken): Promise<EditSessionIdentityMatch | undefined>;
2513 > $onWillCreateEditSessionIdentity(folder: UriComponents, token: CancellationToken, timeout: number): Promise<void>;
2514 > $provideCanonicalUri(uri: UriComponents, targetScheme: string, token: CancellationToken): Promise<UriComponents | undefined>;
2515 > }
2516 >
2517 > export interface ExtHostFileSystemInfoShape {
2518 > $acceptProviderInfos(uri: UriComponents, capabilities: number | null): void;
2519 > }
2520 >
2521 > export interface ExtHostFileSystemShape {
2522 > $stat(handle: number, resource: UriComponents): Promise<files.IStat>;
2523 > $readdir(handle: number, resource: UriComponents): Promise<[string, files.FileType][]>;
2524 > $readFile(handle: number, resource: UriComponents): Promise<VSBuffer>;
2525 > $writeFile(handle: number, resource: UriComponents, content: VSBuffer, opts: files.IFileWriteOptions): Promise<void>;
2526 > $rename(handle: number, resource: UriComponents, target: UriComponents, opts: files.IFileOverwriteOptions): Promise<void>;
2527 > $copy(handle: number, resource: UriComponents, target: UriComponents, opts: files.IFileOverwriteOptions): Promise<void>;
2528 > $mkdir(handle: number, resource: UriComponents): Promise<void>;
2529 > $delete(handle: number, resource: UriComponents, opts: files.IFileDeleteOptions): Promise<void>;
2530 > $watch(handle: number, session: number, resource: UriComponents, opts: files.IWatchOptions): void;
2531 > $unwatch(handle: number, session: number): void;
2532 > $open(handle: number, resource: UriComponents, opts: files.IFileOpenOptions): Promise<number>;
2533 > $close(handle: number, fd: number): Promise<void>;
2534 > $read(handle: number, fd: number, pos: number, length: number): Promise<VSBuffer>;
2535 > $write(handle: number, fd: number, pos: number, data: VSBuffer): Promise<number>;
2536 > }
2537 >
2538 > export interface ExtHostLabelServiceShape {
2539 > $registerResourceLabelFormatter(formatter: ResourceLabelFormatter): IDisposable;
2540 > }
2541 >
2542 > export interface ExtHostAuthenticationShape {
2543 > $getSessions(id: string, scopes: string[] | undefined, options: IAuthenticationGetSessionsOptions): Promise<ReadonlyArray<AuthenticationSession>>;
2544 > $createSession(id: string, scopes: string[], options: IAuthenticationCreateSessionOptions): Promise<AuthenticationSession>;
2545 > $getSessionsFromChallenges(id: string, constraint: IAuthenticationConstraint, options: IAuthenticationGetSessionsOptions): Promise<ReadonlyArray<AuthenticationSession>>;
2546 > $createSessionFromChallenges(id: string, constraint: IAuthenticationConstraint, options: IAuthenticationCreateSessionOptions): Promise<AuthenticationSession>;
2547 > $removeSession(id: string, sessionId: string): Promise<void>;
2548 > $onDidChangeAuthenticationSessions(id: string, label: string, extensionIdFilter?: string[]): Promise<void>;
2549 > $onDidUnregisterAuthenticationProvider(id: string): Promise<void>;
2550 > $registerDynamicAuthProvider(authorizationServer: UriComponents, serverMetadata: IAuthorizationServerMetadata, resource?: IAuthorizationProtectedResourceMetadata, clientId?: string, clientSecret?: string, initialTokens?: (IAuthorizationTokenResponse & { created_at: number })[]): Promise<string>;
2551 > $registerXaaAuthProvider(issuer: UriComponents, serverMetadata: IAuthorizationServerMetadata, clientId?: string, clientSecret?: string, initialTokens?: (IAuthorizationTokenResponse & { created_at: number })[]): Promise<string>;
2552 > $onDidChangeDynamicAuthProviderTokens(authProviderId: string, clientId: string, tokens?: (IAuthorizationTokenResponse & { created_at: number })[]): Promise<void>;
2553 > }
2554 >
2555 > export interface ExtHostAiRelatedInformationShape {
2556 > $provideAiRelatedInformation(handle: number, query: string, token: CancellationToken): Promise<RelatedInformationResult[]>;
2557 > }
2558 >
2559 > export interface MainThreadAiRelatedInformationShape {
2560 > $getAiRelatedInformation(query: string, types: RelatedInformationType[]): Promise<RelatedInformationResult[]>;
2561 > $registerAiRelatedInformationProvider(handle: number, type: RelatedInformationType): void;
2562 > $unregisterAiRelatedInformationProvider(handle: number): void;
2563 > }
2564 >
2565 > export interface ExtHostAiSettingsSearchShape {
2566 > $startSearch(handle: number, query: string, option: AiSettingsSearchProviderOptions, token: CancellationToken): Promise<void>;
2567 > }
2568 >
2569 > export interface MainThreadAiSettingsSearchShape {
2570 > $registerAiSettingsSearchProvider(handle: number): void;
2571 > $unregisterAiSettingsSearchProvider(handle: number): void;
2572 > $handleSearchResult(handle: number, result: AiSettingsSearchResult): void;
2573 > }
2574 >
2575 > export interface ExtHostAiEmbeddingVectorShape {
2576 > $provideAiEmbeddingVector(handle: number, strings: string[], token: CancellationToken): Promise<number[][]>;
2577 > }
2578 >
2579 > export interface MainThreadAiEmbeddingVectorShape {
2580 > $registerAiEmbeddingVectorProvider(model: string, handle: number): void;
2581 > $unregisterAiEmbeddingVectorProvider(handle: number): void;
2582 > }
2583 >
2584 > export interface ExtHostSecretStateShape {
2585 > $onDidChangePassword(e: { extensionId: string; key: string }): Promise<void>;
2586 > }
2587 >
2588 > export interface ExtHostSearchShape {
2589 > $enableExtensionHostSearch(): void;
2590 > $getAIName(handle: number): Promise<string | undefined>;
2591 > $provideFileSearchResults(handle: number, session: number, query: search.IRawQuery, token: CancellationToken): Promise<search.ISearchCompleteStats>;
2592 > $provideAITextSearchResults(handle: number, session: number, query: search.IRawAITextQuery, token: CancellationToken): Promise<search.ISearchCompleteStats>;
2593 > $provideTextSearchResults(handle: number, session: number, query: search.IRawTextQuery, token: CancellationToken): Promise<search.ISearchCompleteStats>;
2594 > $clearCache(cacheKey: string): Promise<void>;
2595 > }
2596 >
2597 > export interface ExtHostExtensionServiceShape {
2598 > $resolveAuthority(remoteAuthority: string, resolveAttempt: number): Promise<Dto<IResolveAuthorityResult>>;
2599 > /**
2600 > * Returns `null` if no resolver for `remoteAuthority` is found.
2601 > */
2602 > $getCanonicalURI(remoteAuthority: string, uri: UriComponents): Promise<UriComponents | null>;
2603 > $startExtensionHost(extensionsDelta: IExtensionDescriptionDelta): Promise<void>;
2604 > $extensionTestsExecute(): Promise<number>;
2605 > $activateByEvent(activationEvent: string, activationKind: ActivationKind): Promise<void>;
2606 > $activate(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<boolean>;
2607 > $setRemoteEnvironment(env: { [key: string]: string | null }): Promise<void>;
2608 > $updateRemoteConnectionData(connectionData: IRemoteConnectionData): Promise<void>;
2609 >
2610 > $deltaExtensions(extensionsDelta: IExtensionDescriptionDelta): Promise<void>;
2611 >
2612 > $test_latency(n: number): Promise<number>;
2613 > $test_up(b: VSBuffer): Promise<number>;
2614 > $test_down(size: number): Promise<VSBuffer>;
2615 > }
2616 >
2617 > export interface FileSystemEvents {
2618 > session?: number;
2619 > created: UriComponents[];
2620 > changed: UriComponents[];
2621 > deleted: UriComponents[];
2622 > }
2623 >
2624 > export interface SourceTargetPair {
2625 > source?: UriComponents;
2626 > target: UriComponents;
2627 > }
2628 >
2629 > export interface IWillRunFileOperationParticipation {
2630 > edit: IWorkspaceEditDto;
2631 > extensionNames: string[];
2632 > }
2633 >
2634 > export interface ExtHostFileSystemEventServiceShape {
2635 > $onFileEvent(events: FileSystemEvents): void;
2636 > $onWillRunFileOperation(operation: files.FileOperation, files: readonly SourceTargetPair[], timeout: number, token: CancellationToken): Promise<IWillRunFileOperationParticipation | undefined>;
2637 > $onDidRunFileOperation(operation: files.FileOperation, files: readonly SourceTargetPair[]): void;
2638 > }
2639 >
2640 > export interface ExtHostLanguagesShape {
2641 > $acceptLanguageIds(ids: string[]): void;
2642 > $acceptSyntaxHighlightingThemeChanged(): void;
2643 > }
2644 >
2645 > export interface ExtHostHeapServiceShape {
2646 > $onGarbageCollection(ids: number[]): void;
2647 > }
2648 > export interface IRawColorInfo {
2649 > color: [number, number, number, number];
2650 > range: IRange;
2651 > }
2652 >
2653 > export class IdObject {
2654 > _id?: number;
2655 > private static _n = 0;
2656 > static mixin<T extends object>(object: T): T & IdObject {
2657 // eslint-disable-next-line local/code-no-any-casts
2658 (<any>object)._id = IdObject._n++;
2660 return <any>object;
2661 }
2663 >
2664 > export const enum ISuggestDataDtoField {
2665 > label = 'a',
2666 > kind = 'b',
2667 > detail = 'c',
2668 > documentation = 'd',
2669 > sortText = 'e',
2670 > filterText = 'f',
2671 > preselect = 'g',
2672 > insertText = 'h',
2673 > insertTextRules = 'i',
2674 > range = 'j',
2675 > commitCharacters = 'k',
2676 > additionalTextEdits = 'l',
2677 > kindModifier = 'm',
2678 > commandIdent = 'n',
2679 > commandId = 'o',
2680 > commandArguments = 'p',
2681 > }
2682 >
2683 > export interface ISuggestDataDto {
2684 > [ISuggestDataDtoField.label]: string | languages.CompletionItemLabel;
2685 > [ISuggestDataDtoField.kind]?: languages.CompletionItemKind;
2686 > [ISuggestDataDtoField.detail]?: string;
2687 > [ISuggestDataDtoField.documentation]?: string | IMarkdownString;
2688 > [ISuggestDataDtoField.sortText]?: string;
2689 > [ISuggestDataDtoField.filterText]?: string;
2690 > [ISuggestDataDtoField.preselect]?: true;
2691 > [ISuggestDataDtoField.insertText]?: string;
2692 > [ISuggestDataDtoField.insertTextRules]?: languages.CompletionItemInsertTextRule;
2693 > [ISuggestDataDtoField.range]?: IRange | { insert: IRange; replace: IRange };
2694 > [ISuggestDataDtoField.commitCharacters]?: string;
2695 > [ISuggestDataDtoField.additionalTextEdits]?: ISingleEditOperation[];
2696 > [ISuggestDataDtoField.kindModifier]?: languages.CompletionItemTag[];
2697 > // Command
2698 > [ISuggestDataDtoField.commandIdent]?: string;
2699 > [ISuggestDataDtoField.commandId]?: string;
2700 > [ISuggestDataDtoField.commandArguments]?: unknown[];
2701 > // not-standard
2702 > x?: ChainedCacheId;
2703 > }
2704 >
2705 > export const enum ISuggestResultDtoField {
2706 > defaultRanges = 'a',
2707 > completions = 'b',
2708 > isIncomplete = 'c',
2709 > duration = 'd',
2710 > }
2711 >
2712 > export interface ISuggestResultDto {
2713 > [ISuggestResultDtoField.defaultRanges]: { insert: IRange; replace: IRange };
2714 > [ISuggestResultDtoField.completions]: ISuggestDataDto[];
2715 > [ISuggestResultDtoField.isIncomplete]: undefined | true;
2716 > [ISuggestResultDtoField.duration]: number;
2717 > x?: number;
2718 > }
2719 >
2720 > export interface ISignatureHelpDto {
2721 > id: CacheId;
2722 > signatures: languages.SignatureInformation[];
2723 > activeSignature: number;
2724 > activeParameter: number;
2725 > }
2726 >
2727 > export interface ISignatureHelpContextDto {
2728 > readonly triggerKind: languages.SignatureHelpTriggerKind;
2729 > readonly triggerCharacter: string | undefined;
2730 > readonly isRetrigger: boolean;
2731 > readonly activeSignatureHelp: ISignatureHelpDto | undefined;
2732 > }
2733 >
2734 > export type IInlayHintDto = CachedSessionItem<Dto<languages.InlayHint>>;
2735 >
2736 > export type IInlayHintsDto = CachedSession<{ hints: IInlayHintDto[] }>;
2737 >
2738 > export type ILocationDto = Dto<languages.Location>;
2739 > export type ILocationLinkDto = Dto<languages.LocationLink>;
2740 >
2741 > export type IWorkspaceSymbolDto = CachedSessionItem<Dto<IWorkspaceSymbol>>;
2742 > export type IWorkspaceSymbolsDto = CachedSession<{ symbols: IWorkspaceSymbolDto[] }>;
2743 >
2744 > export interface IWorkspaceEditEntryMetadataDto {
2745 > needsConfirmation: boolean;
2746 > label: string;
2747 > description?: string;
2748 > iconPath?: IconPathDto;
2749 > }
2750 >
2751 > export interface IChatNotebookEditDto {
2752 > uri: UriComponents;
2753 > edits: ICellEditOperationDto[];
2754 > kind: 'notebookEdit';
2755 > done?: boolean;
2756 > }
2757 >
2758 > export interface IChatResponseClearToPreviousToolInvocationDto {
2759 > kind: 'clearToPreviousToolInvocation';
2760 > reason: ChatResponseClearToPreviousToolInvocationReason;
2761 > }
2762 >
2763 > export interface IChatBeginToolInvocationDto {
2764 > kind: 'beginToolInvocation';
2765 > toolCallId: string;
2766 > toolName: string;
2767 > streamData?: {
2768 > partialInput?: unknown;
2769 > };
2770 > subagentInvocationId?: string;
2771 > }
2772 >
2773 > export interface IChatUpdateToolInvocationDto {
2774 > kind: 'updateToolInvocation';
2775 > toolCallId: string;
2776 > streamData: {
2777 > partialInput?: unknown;
2778 > };
2779 > }
2780 >
2781 > export interface IChatUsageDto {
2782 > kind: 'usage';
2783 > promptTokens: number;
2784 > completionTokens: number;
2785 > outputBuffer?: number;
2786 > copilotCredits?: number;
2787 > promptTokenDetails?: readonly { category: string; label: string; percentageOfPrompt: number }[];
2788 > }
2789 >
2790 > export interface IQuotaSnapshotDto {
2791 > readonly percentRemaining: number;
2792 > readonly unlimited: boolean;
2793 > readonly hasQuota?: boolean;
2794 > readonly resetAt?: number;
2795 > readonly usageBasedBilling?: boolean;
2796 > readonly entitlement?: number;
2797 > readonly quotaRemaining?: number;
2798 > }
2799 >
2800 > export interface IRateLimitSnapshotDto {
2801 > readonly percentRemaining: number;
2802 > readonly unlimited: boolean;
2803 > readonly resetDate?: string;
2804 > }
2805 >
2806 > export interface IQuotaSnapshotsDto {
2807 > readonly resetDate?: string;
2808 > readonly resetDateHasTime?: boolean;
2809 > readonly usageBasedBilling?: boolean;
2810 > readonly canUpgradePlan?: boolean;
2811 > readonly chat?: IQuotaSnapshotDto;
2812 > readonly completions?: IQuotaSnapshotDto;
2813 > readonly premiumChat?: IQuotaSnapshotDto;
2814 > readonly additionalUsageEnabled?: boolean;
2815 > readonly additionalUsageCount?: number;
2816 > readonly sessionRateLimit?: IRateLimitSnapshotDto;
2817 > readonly weeklyRateLimit?: IRateLimitSnapshotDto;
2818 > }
2819 >
2820 > export type ICellEditOperationDto =
2821 > notebookCommon.ICellMetadataEdit
2822 > | notebookCommon.IDocumentMetadataEdit
2823 > | {
2824 > editType: notebookCommon.CellEditType.Replace;
2825 > index: number;
2826 > count: number;
2827 > cells: NotebookCellDataDto[];
2828 > };
2829 >
2830 > export type IWorkspaceCellEditDto = Dto<Omit<notebookCommon.IWorkspaceNotebookCellEdit, 'cellEdit'>> & { cellEdit: ICellEditOperationDto };
2831 >
2832 > export type IWorkspaceFileEditDto = Dto<
2833 > Omit<languages.IWorkspaceFileEdit, 'options'> & {
2834 > options?: Omit<languages.WorkspaceFileEditOptions, 'contents'> & { contents?: { type: 'base64'; value: string } | { type: 'dataTransferItem'; id: string } };
2835 > }>;
2836 >
2837 > export type IWorkspaceTextEditDto = Dto<languages.IWorkspaceTextEdit>;
2838 >
2839 > export interface IWorkspaceEditDto {
2840 > edits: Array<IWorkspaceFileEditDto | IWorkspaceTextEditDto | IWorkspaceCellEditDto>;
2841 > }
2842 >
2843 > export type ICommandDto = { $ident?: string } & languages.Command;
2844 >
2845 > export interface ICodeActionDto {
2846 > cacheId?: ChainedCacheId;
2847 > title: string;
2848 > edit?: IWorkspaceEditDto;
2849 > diagnostics?: Dto<IMarkerData[]>;
2850 > command?: ICommandDto;
2851 > kind?: string;
2852 > isPreferred?: boolean;
2853 > isAI?: boolean;
2854 > disabled?: string;
2855 > ranges?: IRange[];
2856 > }
2857 >
2858 > export interface ICodeActionListDto {
2859 > cacheId: CacheId;
2860 > actions: ReadonlyArray<ICodeActionDto>;
2861 > }
2862 >
2863 > export interface ICodeActionProviderMetadataDto {
2864 > readonly providedKinds?: readonly string[];
2865 > readonly documentation?: ReadonlyArray<{ readonly kind: string; readonly command: ICommandDto }>;
2866 > }
2867 >
2868 > export type CacheId = number;
2869 > export type ChainedCacheId = [CacheId, CacheId];
2870 >
2871 > type CachedSessionItem<T> = T & { cacheId?: ChainedCacheId };
2872 > type CachedSession<T> = T & { cacheId?: CacheId };
2873 >
2874 > export type ILinksListDto = CachedSession<{ links: ILinkDto[] }>;
2875 > export type ILinkDto = CachedSessionItem<Dto<languages.ILink>>;
2876 >
2877 > export type ICodeLensListDto = CachedSession<{ lenses: ICodeLensDto[] }>;
2878 > export type ICodeLensDto = CachedSessionItem<Dto<languages.CodeLens>>;
2879 >
2880 > export type ICallHierarchyItemDto = Dto<CallHierarchyItem>;
2881 >
2882 > export interface IIncomingCallDto {
2883 > from: ICallHierarchyItemDto;
2884 > fromRanges: IRange[];
2885 > }
2886 >
2887 > export interface IOutgoingCallDto {
2888 > fromRanges: IRange[];
2889 > to: ICallHierarchyItemDto;
2890 > }
2891 >
2892 > export interface ILanguageWordDefinitionDto {
2893 > languageId: string;
2894 > regexSource: string;
2895 > regexFlags: string;
2896 > }
2897 >
2898 > export interface ILinkedEditingRangesDto {
2899 > ranges: IRange[];
2900 > wordPattern?: IRegExpDto;
2901 > }
2902 >
2903 > export interface IInlineValueContextDto {
2904 > frameId: number;
2905 > stoppedLocation: IRange;
2906 > }
2907 >
2908 > export type ITypeHierarchyItemDto = Dto<TypeHierarchyItem>;
2909 >
2910 > export interface IPasteEditProviderMetadataDto {
2911 > readonly supportsCopy: boolean;
2912 > readonly supportsPaste: boolean;
2913 > readonly supportsResolve: boolean;
2914 >
2915 > readonly providedPasteEditKinds?: readonly string[];
2916 > readonly copyMimeTypes?: readonly string[];
2917 > readonly pasteMimeTypes?: readonly string[];
2918 > }
2919 >
2920 > export interface IDocumentPasteContextDto {
2921 > readonly only: string | undefined;
2922 > readonly triggerKind: languages.DocumentPasteTriggerKind;
2923 > }
2924 >
2925 > export interface IPasteEditDto {
2926 > _cacheId?: ChainedCacheId;
2927 > title: string;
2928 > kind: { value: string } | undefined;
2929 > insertText: string | { snippet: string };
2930 > additionalEdit?: IWorkspaceEditDto;
2931 > yieldTo?: readonly string[];
2932 > }
2933 >
2934 > export interface IDocumentDropEditProviderMetadata {
2935 > readonly supportsResolve: boolean;
2936 >
2937 > readonly dropMimeTypes: readonly string[];
2938 > readonly providedDropKinds?: readonly string[];
2939 > }
2940 >
2941 > export interface IDocumentDropEditDto {
2942 > _cacheId?: ChainedCacheId;
2943 > title: string;
2944 > kind: string | undefined;
2945 > insertText: string | { snippet: string };
2946 > additionalEdit?: IWorkspaceEditDto;
2947 > yieldTo?: readonly string[];
2948 > }
2949 >
2950 > export interface ExtHostLanguageFeaturesShape {
2951 > $provideDocumentSymbols(handle: number, resource: UriComponents, token: CancellationToken): Promise<languages.DocumentSymbol[] | undefined>;
2952 > $provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Promise<ICodeLensListDto | undefined>;
2953 > $resolveCodeLens(handle: number, symbol: ICodeLensDto, token: CancellationToken): Promise<ICodeLensDto | undefined>;
2954 > $releaseCodeLenses(handle: number, id: number): void;
2955 > $provideDefinition(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<ILocationLinkDto[]>;
2956 > $provideDeclaration(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<ILocationLinkDto[]>;
2957 > $provideImplementation(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<ILocationLinkDto[]>;
2958 > $provideTypeDefinition(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<ILocationLinkDto[]>;
2959 > $provideHover(handle: number, resource: UriComponents, position: IPosition, context: languages.HoverContext<{ id: number }> | undefined, token: CancellationToken): Promise<HoverWithId | undefined>;
2960 > $releaseHover(handle: number, id: number): void;
2961 > $provideEvaluatableExpression(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<languages.EvaluatableExpression | undefined>;
2962 > $provideInlineValues(handle: number, resource: UriComponents, range: IRange, context: languages.InlineValueContext, token: CancellationToken): Promise<languages.InlineValue[] | undefined>;
2963 > $provideDocumentHighlights(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<languages.DocumentHighlight[] | undefined>;
2964 > $provideMultiDocumentHighlights(handle: number, resource: UriComponents, position: IPosition, otherModels: UriComponents[], token: CancellationToken): Promise<Dto<languages.MultiDocumentHighlight[]> | undefined>;
2965 > $provideLinkedEditingRanges(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<ILinkedEditingRangesDto | undefined>;
2966 > $provideReferences(handle: number, resource: UriComponents, position: IPosition, context: languages.ReferenceContext, token: CancellationToken): Promise<ILocationDto[] | undefined>;
2967 > $provideCodeActions(handle: number, resource: UriComponents, rangeOrSelection: IRange | ISelection, context: languages.CodeActionContext, token: CancellationToken): Promise<ICodeActionListDto | undefined>;
2968 > $resolveCodeAction(handle: number, id: ChainedCacheId, token: CancellationToken): Promise<{ edit?: IWorkspaceEditDto; command?: ICommandDto }>;
2969 > $releaseCodeActions(handle: number, cacheId: number): void;
2970 > $prepareDocumentPaste(handle: number, uri: UriComponents, ranges: readonly IRange[], dataTransfer: DataTransferDTO, token: CancellationToken): Promise<DataTransferDTO | undefined>;
2971 > $providePasteEdits(handle: number, requestId: number, uri: UriComponents, ranges: IRange[], dataTransfer: DataTransferDTO, context: IDocumentPasteContextDto, token: CancellationToken): Promise<IPasteEditDto[] | undefined>;
2972 > $resolvePasteEdit(handle: number, id: ChainedCacheId, token: CancellationToken): Promise<{ insertText?: string; additionalEdit?: IWorkspaceEditDto }>;
2973 > $releasePasteEdits(handle: number, cacheId: number): void;
2974 > $provideDocumentFormattingEdits(handle: number, resource: UriComponents, options: languages.FormattingOptions, token: CancellationToken): Promise<languages.TextEdit[] | undefined>;
2975 > $provideDocumentRangeFormattingEdits(handle: number, resource: UriComponents, range: IRange, options: languages.FormattingOptions, token: CancellationToken): Promise<languages.TextEdit[] | undefined>;
2976 > $provideDocumentRangesFormattingEdits(handle: number, resource: UriComponents, range: IRange[], options: languages.FormattingOptions, token: CancellationToken): Promise<languages.TextEdit[] | undefined>;
2977 > $provideOnTypeFormattingEdits(handle: number, resource: UriComponents, position: IPosition, ch: string, options: languages.FormattingOptions, token: CancellationToken): Promise<languages.TextEdit[] | undefined>;
2978 > $provideWorkspaceSymbols(handle: number, search: string, token: CancellationToken): Promise<IWorkspaceSymbolsDto>;
2979 > $resolveWorkspaceSymbol(handle: number, symbol: IWorkspaceSymbolDto, token: CancellationToken): Promise<IWorkspaceSymbolDto | undefined>;
2980 > $releaseWorkspaceSymbols(handle: number, id: number): void;
2981 > $provideRenameEdits(handle: number, resource: UriComponents, position: IPosition, newName: string, token: CancellationToken): Promise<IWorkspaceEditDto & { rejectReason?: string } | undefined>;
2982 > $resolveRenameLocation(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<languages.RenameLocation | undefined>;
2983 > $supportsAutomaticNewSymbolNamesTriggerKind(handle: number): Promise<boolean | undefined>;
2984 > $provideNewSymbolNames(handle: number, resource: UriComponents, range: IRange, triggerKind: languages.NewSymbolNameTriggerKind, token: CancellationToken): Promise<languages.NewSymbolName[] | undefined>;
2985 > $provideDocumentSemanticTokens(handle: number, resource: UriComponents, previousResultId: number, token: CancellationToken): Promise<VSBuffer | null>;
2986 > $releaseDocumentSemanticTokens(handle: number, semanticColoringResultId: number): void;
2987 > $provideDocumentRangeSemanticTokens(handle: number, resource: UriComponents, range: IRange, token: CancellationToken): Promise<VSBuffer | null>;
2988 > $provideCompletionItems(handle: number, resource: UriComponents, position: IPosition, context: languages.CompletionContext, token: CancellationToken): Promise<ISuggestResultDto | undefined>;
2989 > $resolveCompletionItem(handle: number, id: ChainedCacheId, token: CancellationToken): Promise<ISuggestDataDto | undefined>;
2990 > $releaseCompletionItems(handle: number, id: number): void;
2991 > $provideInlineCompletions(handle: number, resource: UriComponents, position: IPosition, context: languages.InlineCompletionContext, token: CancellationToken): Promise<IdentifiableInlineCompletions | undefined>;
2992 > $handleInlineCompletionDidShow(handle: number, pid: number, idx: number, updatedInsertText: string): void;
2993 > $handleInlineCompletionPartialAccept(handle: number, pid: number, idx: number, acceptedCharacters: number, info: languages.PartialAcceptInfo): void;
2994 > $handleInlineCompletionEndOfLifetime(handle: number, pid: number, idx: number, reason: languages.InlineCompletionEndOfLifeReason<{ pid: number; idx: number }>): void;
2995 > $handleInlineCompletionRejection(handle: number, pid: number, idx: number): void;
2996 > $freeInlineCompletionsList(handle: number, pid: number, reason: languages.InlineCompletionsDisposeReason): void;
2997 > $acceptInlineCompletionsUnificationState(state: IInlineCompletionsUnificationState): void;
2998 > $handleInlineCompletionSetCurrentModelId(handle: number, modelId: string): void;
2999 > $handleInlineCompletionSetProviderOption(handle: number, optionId: string, valueId: string): void;
3000 > $provideSignatureHelp(handle: number, resource: UriComponents, position: IPosition, context: languages.SignatureHelpContext, token: CancellationToken): Promise<ISignatureHelpDto | undefined>;
3001 > $releaseSignatureHelp(handle: number, id: number): void;
3002 > $provideInlayHints(handle: number, resource: UriComponents, range: IRange, token: CancellationToken): Promise<IInlayHintsDto | undefined>;
3003 > $resolveInlayHint(handle: number, id: ChainedCacheId, token: CancellationToken): Promise<IInlayHintDto | undefined>;
3004 > $releaseInlayHints(handle: number, id: number): void;
3005 > $provideDocumentLinks(handle: number, resource: UriComponents, token: CancellationToken): Promise<ILinksListDto | undefined>;
3006 > $resolveDocumentLink(handle: number, id: ChainedCacheId, token: CancellationToken): Promise<ILinkDto | undefined>;
3007 > $releaseDocumentLinks(handle: number, id: number): void;
3008 > $provideDocumentColors(handle: number, resource: UriComponents, token: CancellationToken): Promise<IRawColorInfo[]>;
3009 > $provideColorPresentations(handle: number, resource: UriComponents, colorInfo: IRawColorInfo, token: CancellationToken): Promise<languages.IColorPresentation[] | undefined>;
3010 > $provideFoldingRanges(handle: number, resource: UriComponents, context: languages.FoldingContext, token: CancellationToken): Promise<languages.FoldingRange[] | undefined>;
3011 > $provideSelectionRanges(handle: number, resource: UriComponents, positions: IPosition[], token: CancellationToken): Promise<languages.SelectionRange[][]>;
3012 > $prepareCallHierarchy(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<ICallHierarchyItemDto[] | undefined>;
3013 > $provideCallHierarchyIncomingCalls(handle: number, sessionId: string, itemId: string, token: CancellationToken): Promise<IIncomingCallDto[] | undefined>;
3014 > $provideCallHierarchyOutgoingCalls(handle: number, sessionId: string, itemId: string, token: CancellationToken): Promise<IOutgoingCallDto[] | undefined>;
3015 > $releaseCallHierarchy(handle: number, sessionId: string): void;
3016 > $setWordDefinitions(wordDefinitions: ILanguageWordDefinitionDto[]): void;
3017 > $prepareTypeHierarchy(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<ITypeHierarchyItemDto[] | undefined>;
3018 > $provideTypeHierarchySupertypes(handle: number, sessionId: string, itemId: string, token: CancellationToken): Promise<ITypeHierarchyItemDto[] | undefined>;
3019 > $provideTypeHierarchySubtypes(handle: number, sessionId: string, itemId: string, token: CancellationToken): Promise<ITypeHierarchyItemDto[] | undefined>;
3020 > $releaseTypeHierarchy(handle: number, sessionId: string): void;
3021 > $provideDocumentOnDropEdits(handle: number, requestId: number, resource: UriComponents, position: IPosition, dataTransferDto: DataTransferDTO, token: CancellationToken): Promise<IDocumentDropEditDto[] | undefined>;
3022 > $releaseDocumentOnDropEdits(handle: number, cacheId: number): void;
3023 > }
3024 >
3025 > export interface ExtHostQuickOpenShape {
3026 > $onItemSelected(handle: number): void;
3027 > $validateInput(input: string): Promise<string | { content: string; severity: Severity } | null | undefined>;
3028 > $onDidChangeActive(sessionId: number, handles: number[]): void;
3029 > $onDidChangeSelection(sessionId: number, handles: number[]): void;
3030 > $onDidAccept(sessionId: number): void;
3031 > $onDidChangeValue(sessionId: number, value: string): void;
3032 > $onDidTriggerButton(sessionId: number, handle: number, checked?: boolean): void;
3033 > $onDidTriggerItemButton(sessionId: number, itemHandle: number, buttonHandle: number, checked?: boolean): void;
3034 > $onDidHide(sessionId: number): void;
3035 > }
3036 >
3037 > export interface ExtHostTelemetryShape {
3038 > $initializeTelemetryLevel(level: TelemetryLevel, supportsTelemetry: boolean, productConfig?: { usage: boolean; error: boolean }): void;
3039 > $onDidChangeTelemetryLevel(level: TelemetryLevel): void;
3040 > }
3041 >
3042 > export interface MainThreadMeteredConnectionShape extends IDisposable {
3043 > }
3044 >
3045 > export interface ExtHostMeteredConnectionShape {
3046 > $initializeIsConnectionMetered(isMetered: boolean): void;
3047 > $onDidChangeIsConnectionMetered(isMetered: boolean): void;
3048 > }
3049 >
3050 > export interface ITerminalLinkDto {
3051 > /** The ID of the link to enable activation and disposal. */
3052 > id: number;
3053 > /** The startIndex of the link in the line. */
3054 > startIndex: number;
3055 > /** The length of the link in the line. */
3056 > length: number;
3057 > /** The descriptive label for what the link does when activated. */
3058 > label?: string;
3059 > }
3060 >
3061 > export interface ITerminalDimensionsDto {
3062 > columns: number;
3063 > rows: number;
3064 > }
3065 >
3066 > type SingleOrMany<T> = T[] | T;
3067 >
3068 > export interface ITerminalQuickFixTerminalCommandDto {
3069 > terminalCommand: string;
3070 > shouldExecute?: boolean;
3071 > }
3072 >
3073 > export interface ITerminalQuickFixOpenerDto {
3074 > uri: UriComponents;
3075 > }
3076 >
3077 > export type TerminalQuickFix = ITerminalQuickFixTerminalCommandDto | ITerminalQuickFixOpenerDto | ICommandDto;
3078 >
3079 > export interface TerminalCommandMatchResultDto {
3080 > commandLine: string;
3081 > commandLineMatch: RegExpMatchArray;
3082 > outputMatch?: {
3083 > regexMatch: RegExpMatchArray;
3084 > outputLines: string[];
3085 > };
3086 > }
3087 >
3088 > export interface ITerminalCommandDto {
3089 > commandLine: string | undefined;
3090 > cwd: URI | string | undefined;
3091 > exitCode: number | undefined;
3092 > output: string | undefined;
3093 > }
3094 >
3095 > export interface ITerminalCompletionContextDto {
3096 > commandLine: string;
3097 > cursorIndex: number;
3098 > }
3099 >
3100 > export interface ITerminalCompletionItemDto {
3101 > label: string | CompletionItemLabel;
3102 > detail?: string;
3103 > documentation?: string | IMarkdownString;
3104 > icon?: ThemeIcon | undefined;
3105 > kind?: number | undefined;
3106 > isFile?: boolean | undefined;
3107 > isDirectory?: boolean | undefined;
3108 > isKeyword?: boolean | undefined;
3109 > replacementRange: readonly [number, number];
3110 > }
3111 >
3112 > export interface ITerminalCompletionProvider {
3113 > id: string;
3114 > shellTypes?: TerminalShellType[];
3115 > provideCompletions(value: string, cursorPosition: number, token: CancellationToken): Promise<TerminalCompletionListDto<ITerminalCompletionItemDto> | undefined>;
3116 > triggerCharacters?: string[];
3117 > isBuiltin?: boolean;
3118 > }
3119 > /**
3120 > * Represents a collection of {@link CompletionItem completion items} to be presented
3121 > * in the editor.
3122 > */
3123 > export class TerminalCompletionListDto<T extends ITerminalCompletionItemDto = ITerminalCompletionItemDto> {
3124 >
3125 > /**
3126 > * Resources should be shown in the completions list
3127 > */
3128 > resourceOptions?: TerminalCompletionResourceOptionsDto;
3129 >
3130 > /**
3131 > * The completion items.
3132 > */
3133 > items: T[];
3134 >
3135 > /**
3136 > * Creates a new completion list.
3137 > *
3138 > * @param items The completion items.
3139 > * @param isIncomplete The list is not complete.
3140 > */
3141 > constructor(items?: T[], resourceOptions?: TerminalCompletionResourceOptionsDto) {
3142 this.items = items ?? [];
3143 this.resourceOptions = resourceOptions;
3144 }
3146 >
3147 > export interface TerminalCompletionResourceOptionsDto {
3148 > showFiles?: boolean;
3149 > showDirectories?: boolean;
3150 > globPattern?: string | IRelativePattern;
3151 > cwd: UriComponents;
3152 > pathSeparator: string;
3153 > }
3154 >
3155 > export interface ExtHostTerminalServiceShape {
3156 > $acceptTerminalClosed(id: number, exitCode: number | undefined, exitReason: TerminalExitReason): void;
3157 > $acceptTerminalOpened(id: number, extHostTerminalId: string | undefined, name: string, shellLaunchConfig: IShellLaunchConfigDto): void;
3158 > $acceptActiveTerminalChanged(id: number | null): void;
3159 > $acceptTerminalProcessId(id: number, processId: number): void;
3160 > $acceptTerminalProcessData(id: number, data: string): void;
3161 > $acceptDidExecuteCommand(id: number, command: ITerminalCommandDto): void;
3162 > $acceptTerminalTitleChange(id: number, name: string): void;
3163 > $acceptTerminalDimensions(id: number, cols: number, rows: number): void;
3164 > $acceptTerminalMaximumDimensions(id: number, cols: number, rows: number): void;
3165 > $acceptTerminalInteraction(id: number): void;
3166 > $acceptTerminalSelection(id: number, selection: string | undefined): void;
3167 > $acceptTerminalShellType(id: number, shellType: TerminalShellType | undefined): void;
3168 > $startExtensionTerminal(id: number, initialDimensions: ITerminalDimensionsDto | undefined): Promise<ITerminalLaunchError | undefined>;
3169 > $acceptProcessAckDataEvent(id: number, charCount: number): void;
3170 > $acceptProcessInput(id: number, data: string): void;
3171 > $acceptProcessResize(id: number, cols: number, rows: number): void;
3172 > $acceptProcessShutdown(id: number, immediate: boolean): void;
3173 > $acceptProcessRequestInitialCwd(id: number): void;
3174 > $acceptProcessRequestCwd(id: number): void;
3175 > $acceptProcessRequestLatency(id: number): Promise<number>;
3176 > $provideLinks(id: number, line: string): Promise<ITerminalLinkDto[]>;
3177 > $activateLink(id: number, linkId: number): void;
3178 > $initEnvironmentVariableCollections(collections: [string, ISerializableEnvironmentVariableCollection][]): void;
3179 > $acceptDefaultProfile(profile: ITerminalProfile, automationProfile: ITerminalProfile): void;
3180 > $createContributedProfileTerminal(id: string, options: ICreateContributedTerminalProfileOptions): Promise<void>;
3181 > $provideTerminalQuickFixes(id: string, matchResult: TerminalCommandMatchResultDto, token: CancellationToken): Promise<SingleOrMany<TerminalQuickFix> | undefined>;
3182 > $provideTerminalCompletions(id: string, options: ITerminalCompletionContextDto, token: CancellationToken): Promise<TerminalCompletionListDto | undefined>;
3183 > }
3184 >
3185 > export interface ExtHostTerminalShellIntegrationShape {
3186 > $shellIntegrationChange(instanceId: number, supportsExecuteCommandApi: boolean): void;
3187 > $shellExecutionStart(instanceId: number, supportsExecuteCommandApi: boolean, commandLineValue: string, commandLineConfidence: TerminalShellExecutionCommandLineConfidence, isTrusted: boolean, cwd: string | undefined): void;
3188 > $shellExecutionEnd(instanceId: number, commandLineValue: string, commandLineConfidence: TerminalShellExecutionCommandLineConfidence, isTrusted: boolean, exitCode: number | undefined): void;
3189 > $shellExecutionData(instanceId: number, data: string): void;
3190 > $shellEnvChange(instanceId: number, shellEnvKeys: string[], shellEnvValues: string[], isTrusted: boolean): void;
3191 > $cwdChange(instanceId: number, cwd: string | undefined): void;
3192 > $closeTerminal(instanceId: number): void;
3193 > }
3194 >
3195 > export interface ExtHostSCMShape {
3196 > $provideOriginalResource(sourceControlHandle: number, uri: UriComponents, token: CancellationToken): Promise<UriComponents | null>;
3197 > $provideSecondaryOriginalResource(sourceControlHandle: number, uri: UriComponents, token: CancellationToken): Promise<UriComponents | null>;
3198 > $onInputBoxValueChange(sourceControlHandle: number, value: string): void;
3199 > $executeResourceCommand(sourceControlHandle: number, groupHandle: number, handle: number, preserveFocus: boolean): Promise<void>;
3200 > $validateInput(sourceControlHandle: number, value: string, cursorPosition: number): Promise<[string | IMarkdownString, number] | undefined>;
3201 > $setSelectedSourceControl(selectedSourceControlHandle: number | undefined): Promise<void>;
3202 > $provideHistoryItemRefs(sourceControlHandle: number, historyItemRefs: string[] | undefined, token: CancellationToken): Promise<SCMHistoryItemRefDto[] | undefined>;
3203 > $provideHistoryItems(sourceControlHandle: number, options: ISCMHistoryOptions, token: CancellationToken): Promise<SCMHistoryItemDto[] | undefined>;
3204 > $provideHistoryItemChanges(sourceControlHandle: number, historyItemId: string, historyItemParentId: string | undefined, token: CancellationToken): Promise<SCMHistoryItemChangeDto[] | undefined>;
3205 > $resolveHistoryItem(sourceControlHandle: number, historyItemId: string, token: CancellationToken): Promise<SCMHistoryItemDto | undefined>;
3206 > $resolveHistoryItemChatContext(sourceControlHandle: number, historyItemId: string, token: CancellationToken): Promise<string | undefined>;
3207 > $resolveHistoryItemChangeRangeChatContext(sourceControlHandle: number, historyItemId: string, historyItemParentId: string, path: string, token: CancellationToken): Promise<string | undefined>;
3208 > $resolveHistoryItemRefsCommonAncestor(sourceControlHandle: number, historyItemRefs: string[], token: CancellationToken): Promise<string | undefined>;
3209 >
3210 > $provideArtifactGroups(sourceControlHandle: number, token: CancellationToken): Promise<SCMArtifactGroupDto[] | undefined>;
3211 > $provideArtifacts(sourceControlHandle: number, group: string, token: CancellationToken): Promise<SCMArtifactDto[] | undefined>;
3212 > }
3213 >
3214 > export interface ExtHostQuickDiffShape {
3215 > $provideOriginalResource(sourceControlHandle: number, uri: UriComponents, token: CancellationToken): Promise<UriComponents | null>;
3216 > $acceptSourceControlDiffInformation(handle: number, diffInformation: ITextEditorDiffInformation | undefined): void;
3217 > }
3218 >
3219 > export interface ExtHostShareShape {
3220 > $provideShare(handle: number, shareableItem: IShareableItemDto, token: CancellationToken): Promise<UriComponents | string | undefined>;
3221 > }
3222 >
3223 > export interface ExtHostTaskShape {
3224 > $provideTasks(handle: number, validTypes: { [key: string]: boolean }): Promise<tasks.ITaskSetDTO>;
3225 > $resolveTask(handle: number, taskDTO: tasks.ITaskDTO): Promise<tasks.ITaskDTO | undefined>;
3226 > $onDidStartTask(execution: tasks.ITaskExecutionDTO, terminalId: number, resolvedDefinition: tasks.ITaskDefinitionDTO): void;
3227 > $onDidStartTaskProcess(value: tasks.ITaskProcessStartedDTO): void;
3228 > $onDidEndTaskProcess(value: tasks.ITaskProcessEndedDTO): void;
3229 > $OnDidEndTask(execution: tasks.ITaskExecutionDTO): void;
3230 > $onDidStartTaskProblemMatchers(status: tasks.ITaskProblemMatcherStartedDto): void;
3231 > $onDidEndTaskProblemMatchers(status: tasks.ITaskProblemMatcherEndedDto): void;
3232 > $resolveVariables(workspaceFolder: UriComponents, toResolve: { process?: { name: string; cwd?: string }; variables: string[] }): Promise<{ process?: string; variables: { [key: string]: string } }>;
3233 > $jsonTasksSupported(): Promise<boolean>;
3234 > $findExecutable(command: string, cwd?: string, paths?: string[]): Promise<string | undefined>;
3235 > }
3236 >
3237 > export interface IBreakpointDto {
3238 > type: string;
3239 > id?: string;
3240 > enabled: boolean;
3241 > condition?: string;
3242 > hitCondition?: string;
3243 > logMessage?: string;
3244 > mode?: string;
3245 > }
3246 >
3247 > export interface IFunctionBreakpointDto extends IBreakpointDto {
3248 > type: 'function';
3249 > functionName: string;
3250 > mode?: string;
3251 > }
3252 >
3253 > export interface IDataBreakpointDto extends IBreakpointDto {
3254 > type: 'data';
3255 > dataId: string;
3256 > canPersist: boolean;
3257 > label: string;
3258 > accessTypes?: DebugProtocol.DataBreakpointAccessType[];
3259 > accessType: DebugProtocol.DataBreakpointAccessType;
3260 > mode?: string;
3261 > }
3262 >
3263 > export interface ISourceBreakpointDto extends IBreakpointDto {
3264 > type: 'source';
3265 > uri: UriComponents;
3266 > line: number;
3267 > character: number;
3268 > }
3269 >
3270 > export interface IBreakpointsDeltaDto {
3271 > added?: Array<ISourceBreakpointDto | IFunctionBreakpointDto | IDataBreakpointDto>;
3272 > removed?: string[];
3273 > changed?: Array<ISourceBreakpointDto | IFunctionBreakpointDto | IDataBreakpointDto>;
3274 > }
3275 >
3276 > export interface ISourceMultiBreakpointDto {
3277 > type: 'sourceMulti';
3278 > uri: UriComponents;
3279 > lines: {
3280 > id: string;
3281 > enabled: boolean;
3282 > condition?: string;
3283 > hitCondition?: string;
3284 > logMessage?: string;
3285 > line: number;
3286 > character: number;
3287 > mode?: string;
3288 > }[];
3289 > }
3290 >
3291 > export interface IDebugSessionFullDto {
3292 > id: DebugSessionUUID;
3293 > type: string;
3294 > name: string;
3295 > parent: DebugSessionUUID | undefined;
3296 > folderUri: UriComponents | undefined;
3297 > configuration: IConfig;
3298 > }
3299 >
3300 > export type IDebugSessionDto = IDebugSessionFullDto | DebugSessionUUID;
3301 >
3302 > export interface IThreadFocusDto {
3303 > kind: 'thread';
3304 > sessionId: string;
3305 > threadId: number;
3306 > }
3307 >
3308 > export interface IStackFrameFocusDto {
3309 > kind: 'stackFrame';
3310 > sessionId: string;
3311 > threadId: number;
3312 > frameId: number;
3313 > }
3314 >
3315 >
3316 > export interface ExtHostDebugServiceShape {
3317 > $substituteVariables(folder: UriComponents | undefined, config: IConfig): Promise<IConfig>;
3318 > $runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, sessionId: string): Promise<number | undefined>;
3319 > $startDASession(handle: number, session: IDebugSessionDto): Promise<void>;
3320 > $stopDASession(handle: number): Promise<void>;
3321 > $sendDAMessage(handle: number, message: DebugProtocol.ProtocolMessage): void;
3322 > $resolveDebugConfiguration(handle: number, folder: UriComponents | undefined, debugConfiguration: IConfig, token: CancellationToken): Promise<IConfig | null | undefined>;
3323 > $resolveDebugConfigurationWithSubstitutedVariables(handle: number, folder: UriComponents | undefined, debugConfiguration: IConfig, token: CancellationToken): Promise<IConfig | null | undefined>;
3324 > $provideDebugConfigurations(handle: number, folder: UriComponents | undefined, token: CancellationToken): Promise<IConfig[]>;
3325 > $provideDebugAdapter(handle: number, session: IDebugSessionDto): Promise<Dto<IAdapterDescriptor>>;
3326 > $acceptDebugSessionStarted(session: IDebugSessionDto): void;
3327 > $acceptDebugSessionTerminated(session: IDebugSessionDto): void;
3328 > $acceptDebugSessionActiveChanged(session: IDebugSessionDto | undefined): void;
3329 > $acceptDebugSessionCustomEvent(session: IDebugSessionDto, event: any): void;
3330 > $acceptBreakpointsDelta(delta: IBreakpointsDeltaDto): void;
3331 > $acceptDebugSessionNameChanged(session: IDebugSessionDto, name: string): void;
3332 > $acceptStackFrameFocus(focus: IThreadFocusDto | IStackFrameFocusDto | undefined): void;
3333 > $provideDebugVisualizers(extensionId: string, id: string, context: IDebugVisualizationContext, token: CancellationToken): Promise<IDebugVisualization.Serialized[]>;
3334 > $resolveDebugVisualizer(id: number, token: CancellationToken): Promise<MainThreadDebugVisualization>;
3335 > $executeDebugVisualizerCommand(id: number): Promise<void>;
3336 > $disposeDebugVisualizers(ids: number[]): void;
3337 > $getVisualizerTreeItem(treeId: string, element: IDebugVisualizationContext): Promise<IDebugVisualizationTreeItem.Serialized | undefined>;
3338 > $getVisualizerTreeItemChildren(treeId: string, element: number): Promise<IDebugVisualizationTreeItem.Serialized[]>;
3339 > $editVisualizerTreeItem(element: number, value: string): Promise<IDebugVisualizationTreeItem.Serialized | undefined>;
3340 > $disposeVisualizedTree(element: number): void;
3341 > }
3342 >
3343 >
3344 > export interface DecorationRequest {
3345 > readonly id: number;
3346 > readonly uri: UriComponents;
3347 > }
3348 >
3349 > export type DecorationData = [boolean, string, string | ThemeIcon, ThemeColor];
3350 > export type DecorationReply = { [id: number]: DecorationData };
3351 >
3352 > export interface ExtHostDecorationsShape {
3353 > $provideDecorations(handle: number, requests: DecorationRequest[], token: CancellationToken): Promise<DecorationReply>;
3354 > }
3355 >
3356 > export interface ExtHostWindowShape {
3357 > $onDidChangeWindowFocus(value: boolean): void;
3358 > $onDidChangeWindowActive(value: boolean): void;
3359 > $onDidChangeActiveNativeWindowHandle(handle: string | undefined): void;
3360 > }
3361 >
3362 > export type PowerSystemIdleState = 'active' | 'idle' | 'locked' | 'unknown';
3363 > export type PowerThermalState = 'unknown' | 'nominal' | 'fair' | 'serious' | 'critical';
3364 > export type PowerSaveBlockerType = 'prevent-app-suspension' | 'prevent-display-sleep';
3365 >
3366 > export interface MainThreadPowerShape extends IDisposable {
3367 > $getSystemIdleState(idleThreshold: number): Promise<PowerSystemIdleState>;
3368 > $getSystemIdleTime(): Promise<number>;
3369 > $getCurrentThermalState(): Promise<PowerThermalState>;
3370 > $isOnBatteryPower(): Promise<boolean>;
3371 > $startPowerSaveBlocker(type: PowerSaveBlockerType): Promise<number>;
3372 > $stopPowerSaveBlocker(id: number): Promise<boolean>;
3373 > $isPowerSaveBlockerStarted(id: number): Promise<boolean>;
3374 > }
3375 >
3376 > export interface ExtHostPowerShape {
3377 > $onDidSuspend(): void;
3378 > $onDidResume(): void;
3379 > $onDidChangeOnBatteryPower(isOnBattery: boolean): void;
3380 > $onDidChangeThermalState(state: PowerThermalState): void;
3381 > $onDidChangeSpeedLimit(limit: number): void;
3382 > $onWillShutdown(): void;
3383 > $onDidLockScreen(): void;
3384 > $onDidUnlockScreen(): void;
3385 > }
3386 >
3387 > export interface ExtHostLogLevelServiceShape {
3388 > $setLogLevel(level: LogLevel, resource?: UriComponents): void;
3389 > }
3390 >
3391 > export interface MainThreadLoggerShape {
3392 > $log(file: UriComponents, messages: [LogLevel, string][]): void;
3393 > $flush(file: UriComponents): void;
3394 > $createLogger(file: UriComponents, options?: ILoggerOptions): Promise<void>;
3395 > $registerLogger(logger: UriDto<ILoggerResource>): Promise<void>;
3396 > $deregisterLogger(resource: UriComponents): Promise<void>;
3397 > $setVisibility(resource: UriComponents, visible: boolean): Promise<void>;
3398 > }
3399 >
3400 > export interface ExtHostOutputServiceShape {
3401 > $setVisibleChannel(channelId: string | null): void;
3402 > }
3403 >
3404 > export interface ExtHostProgressShape {
3405 > $acceptProgressCanceled(handle: number): void;
3406 > }
3407 >
3408 > export interface ExtHostCommentsShape {
3409 > $createCommentThreadTemplate(commentControllerHandle: number, uriComponents: UriComponents, range: IRange | undefined, editorId?: string): Promise<void>;
3410 > $updateCommentThreadTemplate(commentControllerHandle: number, threadHandle: number, range: IRange): Promise<void>;
3411 > $updateCommentThread(commentControllerHandle: number, threadHandle: number, changes: CommentThreadChanges): Promise<void>;
3412 > $deleteCommentThread(commentControllerHandle: number, commentThreadHandle: number): void;
3413 > $provideCommentingRanges(commentControllerHandle: number, uriComponents: UriComponents, token: CancellationToken): Promise<{ ranges: IRange[]; fileComments: boolean } | undefined>;
3414 > $toggleReaction(commentControllerHandle: number, threadHandle: number, uri: UriComponents, comment: languages.Comment, reaction: languages.CommentReaction): Promise<void>;
3415 > $setActiveComment(controllerHandle: number, commentInfo: { commentThreadHandle: number; uniqueIdInThread?: number } | undefined): Promise<void>;
3416 > }
3417 >
3418 > export interface INotebookSelectionChangeEvent {
3419 > selections: ICellRange[];
3420 > }
3421 >
3422 > export interface INotebookVisibleRangesEvent {
3423 > ranges: ICellRange[];
3424 > }
3425 >
3426 > export interface INotebookEditorPropertiesChangeData {
3427 > visibleRanges?: INotebookVisibleRangesEvent;
3428 > selections?: INotebookSelectionChangeEvent;
3429 > }
3430 >
3431 > export interface INotebookDocumentPropertiesChangeData {
3432 > metadata?: notebookCommon.NotebookDocumentMetadata;
3433 > }
3434 >
3435 > export interface INotebookModelAddedData {
3436 > uri: UriComponents;
3437 > versionId: number;
3438 > cells: NotebookCellDto[];
3439 > viewType: string;
3440 > metadata?: notebookCommon.NotebookDocumentMetadata;
3441 > }
3442 >
3443 > export interface INotebookEditorAddData {
3444 > id: string;
3445 > documentUri: UriComponents;
3446 > selections: ICellRange[];
3447 > visibleRanges: ICellRange[];
3448 > viewColumn?: number;
3449 > viewType: string;
3450 > }
3451 >
3452 > export interface INotebookDocumentsAndEditorsDelta {
3453 > removedDocuments?: UriComponents[];
3454 > addedDocuments?: INotebookModelAddedData[];
3455 > removedEditors?: string[];
3456 > addedEditors?: INotebookEditorAddData[];
3457 > newActiveEditor?: string | null;
3458 > visibleEditors?: string[];
3459 > }
3460 >
3461 > export interface NotebookOutputItemDto {
3462 > readonly mime: string;
3463 > readonly valueBytes: VSBuffer;
3464 > }
3465 >
3466 > export interface NotebookOutputDto {
3467 > items: NotebookOutputItemDto[];
3468 > outputId: string;
3469 > metadata?: Record<string, any>;
3470 > }
3471 >
3472 > export interface NotebookCellDataDto {
3473 > source: string;
3474 > language: string;
3475 > mime: string | undefined;
3476 > cellKind: notebookCommon.CellKind;
3477 > outputs: NotebookOutputDto[];
3478 > metadata?: notebookCommon.NotebookCellMetadata;
3479 > internalMetadata?: notebookCommon.NotebookCellInternalMetadata;
3480 > }
3481 >
3482 > export interface NotebookDataDto {
3483 > readonly cells: NotebookCellDataDto[];
3484 > readonly metadata: notebookCommon.NotebookDocumentMetadata;
3485 > }
3486 >
3487 > export interface NotebookCellDto {
3488 > handle: number;
3489 > uri: UriComponents;
3490 > eol: string;
3491 > source: string[];
3492 > language: string;
3493 > mime?: string;
3494 > cellKind: notebookCommon.CellKind;
3495 > outputs: NotebookOutputDto[];
3496 > metadata?: notebookCommon.NotebookCellMetadata;
3497 > internalMetadata?: notebookCommon.NotebookCellInternalMetadata;
3498 > }
3499 >
3500 > export type INotebookPartialFileStatsWithMetadata = Omit<files.IFileStatWithMetadata, 'resource' | 'children'>;
3501 >
3502 > export interface ExtHostNotebookShape extends ExtHostNotebookDocumentsAndEditorsShape {
3503 > $provideNotebookCellStatusBarItems(handle: number, uri: UriComponents, index: number, token: CancellationToken): Promise<INotebookCellStatusBarListDto | undefined>;
3504 > $releaseNotebookCellStatusBarItems(id: number): void;
3505 >
3506 > $dataToNotebook(handle: number, data: VSBuffer, token: CancellationToken): Promise<SerializableObjectWithBuffers<NotebookDataDto>>;
3507 > $notebookToData(handle: number, data: SerializableObjectWithBuffers<NotebookDataDto>, token: CancellationToken): Promise<VSBuffer>;
3508 > $saveNotebook(handle: number, uri: UriComponents, versionId: number, options: files.IWriteFileOptions, token: CancellationToken): Promise<INotebookPartialFileStatsWithMetadata | files.FileOperationError>;
3509 >
3510 > $searchInNotebooks(handle: number, textQuery: search.ITextQuery, viewTypeFileTargets: NotebookPriorityInfo[], otherViewTypeFileTargets: NotebookPriorityInfo[], token: CancellationToken): Promise<{ results: IRawClosedNotebookFileMatch[]; limitHit: boolean }>;
3511 > }
3512 >
3513 > export interface ExtHostNotebookDocumentSaveParticipantShape {
3514 > $participateInSave(resource: UriComponents, reason: SaveReason, token: CancellationToken): Promise<boolean>;
3515 > }
3516 >
3517 > export interface ExtHostNotebookRenderersShape {
3518 > $postRendererMessage(editorId: string, rendererId: string, message: unknown): void;
3519 > }
3520 >
3521 > export interface ExtHostNotebookDocumentsAndEditorsShape {
3522 > $acceptDocumentAndEditorsDelta(delta: SerializableObjectWithBuffers<INotebookDocumentsAndEditorsDelta>): void;
3523 > }
3524 >
3525 > export type NotebookRawContentEventDto =
3526 > // notebookCommon.NotebookCellsInitializeEvent<NotebookCellDto>
3527 > | {
3528 >
3529 > readonly kind: notebookCommon.NotebookCellsChangeType.ModelChange;
3530 > readonly changes: notebookCommon.NotebookCellTextModelSplice<NotebookCellDto>[];
3531 > }
3532 > | {
3533 > readonly kind: notebookCommon.NotebookCellsChangeType.Move;
3534 > readonly index: number;
3535 > readonly length: number;
3536 > readonly newIdx: number;
3537 > }
3538 > | {
3539 > readonly kind: notebookCommon.NotebookCellsChangeType.Output;
3540 > readonly index: number;
3541 > readonly outputs: NotebookOutputDto[];
3542 > }
3543 > | {
3544 > readonly kind: notebookCommon.NotebookCellsChangeType.OutputItem;
3545 > readonly index: number;
3546 > readonly outputId: string;
3547 > readonly outputItems: NotebookOutputItemDto[];
3548 > readonly append: boolean;
3549 > }
3550 > | notebookCommon.NotebookCellsChangeLanguageEvent
3551 > | notebookCommon.NotebookCellsChangeMimeEvent
3552 > | notebookCommon.NotebookCellsChangeMetadataEvent
3553 > | notebookCommon.NotebookCellsChangeInternalMetadataEvent
3554 > // | notebookCommon.NotebookDocumentChangeMetadataEvent
3555 > | notebookCommon.NotebookCellContentChangeEvent
3556 > // | notebookCommon.NotebookDocumentUnknownChangeEvent
3557 > ;
3558 >
3559 > export type NotebookCellsChangedEventDto = {
3560 > readonly rawEvents: NotebookRawContentEventDto[];
3561 > readonly versionId: number;
3562 > };
3563 >
3564 > export interface ExtHostNotebookDocumentsShape {
3565 > $acceptModelChanged(uriComponents: UriComponents, event: SerializableObjectWithBuffers<NotebookCellsChangedEventDto>, isDirty: boolean, newMetadata?: notebookCommon.NotebookDocumentMetadata): void;
3566 > $acceptDirtyStateChanged(uriComponents: UriComponents, isDirty: boolean): void;
3567 > $acceptModelSaved(uriComponents: UriComponents): void;
3568 > }
3569 >
3570 > export type INotebookEditorViewColumnInfo = Record<string, number>;
3571 >
3572 > export interface ExtHostNotebookEditorsShape {
3573 > $acceptEditorPropertiesChanged(id: string, data: INotebookEditorPropertiesChangeData): void;
3574 > $acceptEditorViewColumns(data: INotebookEditorViewColumnInfo): void;
3575 > }
3576 >
3577 > export interface ExtHostNotebookKernelsShape {
3578 > $acceptNotebookAssociation(handle: number, uri: UriComponents, value: boolean): void;
3579 > $executeCells(handle: number, uri: UriComponents, handles: number[]): Promise<void>;
3580 > $cancelCells(handle: number, uri: UriComponents, handles: number[]): Promise<void>;
3581 > $acceptKernelMessageFromRenderer(handle: number, editorId: string, message: any): void;
3582 > $provideKernelSourceActions(handle: number, token: CancellationToken): Promise<notebookCommon.INotebookKernelSourceAction[]>;
3583 > $provideVariables(handle: number, requestId: string, notebookUri: UriComponents, parentId: number | undefined, kind: 'named' | 'indexed', start: number, token: CancellationToken): Promise<void>;
3584 > }
3585 >
3586 > export interface ExtHostInteractiveShape {
3587 > $willAddInteractiveDocument(uri: UriComponents, eol: string, languageId: string, notebookUri: UriComponents): void;
3588 > $willRemoveInteractiveDocument(uri: UriComponents, notebookUri: UriComponents): void;
3589 > }
3590 >
3591 > export interface ExtHostStorageShape {
3592 > $acceptValue(shared: boolean, extensionId: string, value: string): void;
3593 > }
3594 >
3595 > export interface ExtHostThemingShape {
3596 > $onColorThemeChange(themeType: string): void;
3597 > }
3598 >
3599 > export interface MainThreadThemingShape extends IDisposable {
3600 > }
3601 >
3602 > export interface MainThreadLocalizationShape extends IDisposable {
3603 > $fetchBuiltInBundleUri(id: string, language: string): Promise<UriComponents | undefined>;
3604 > $fetchBundleContents(uriComponents: UriComponents): Promise<string>;
3605 > }
3606 >
3607 > export interface TunnelDto {
3608 > remoteAddress: { port: number; host: string };
3609 > localAddress: { port: number; host: string } | string;
3610 > public: boolean;
3611 > privacy: TunnelPrivacyId | string;
3612 > protocol: string | undefined;
3613 > }
3614 >
3615 >
3616 > export interface ExtHostTunnelServiceShape {
3617 > $forwardPort(tunnelOptions: TunnelOptions, tunnelCreationOptions: TunnelCreationOptions): Promise<TunnelDto | string | undefined>;
3618 > $closeTunnel(remote: { host: string; port: number }, silent?: boolean): Promise<void>;
3619 > $onDidTunnelsChange(): Promise<void>;
3620 > $registerCandidateFinder(enable: boolean): Promise<void>;
3621 > $applyCandidateFilter(candidates: CandidatePort[]): Promise<CandidatePort[]>;
3622 > $providePortAttributes(handles: number[], ports: number[], pid: number | undefined, commandline: string | undefined, cancellationToken: CancellationToken): Promise<ProvidedPortAttributes[]>;
3623 > }
3624 >
3625 > export interface ExtHostTimelineShape {
3626 > $getTimeline(source: string, uri: UriComponents, options: TimelineOptions, token: CancellationToken): Promise<Dto<Timeline> | undefined>;
3627 > }
3628 >
3629 > export const enum ExtHostTestingResource {
3630 > Workspace,
3631 > TextDocument
3632 > }
3633 >
3634 > export interface ExtHostTestingShape {
3635 > $runControllerTests(req: IStartControllerTests[], token: CancellationToken): Promise<{ error?: string }[]>;
3636 > $startContinuousRun(req: ICallProfileRunHandler[], token: CancellationToken): Promise<{ error?: string }[]>;
3637 > $cancelExtensionTestRun(runId: string | undefined, taskId: string | undefined): void;
3638 > /** Handles a diff of tests, as a result of a subscribeToDiffs() call */
3639 > $acceptDiff(diff: TestsDiffOp.Serialized[]): void;
3640 > /** Expands a test item's children, by the given number of levels. */
3641 > $expandTest(testId: string, levels: number): Promise<void>;
3642 > /** Requests coverage details for a test run. Errors if not available. */
3643 > $getCoverageDetails(coverageId: string, testId: string | undefined, token: CancellationToken): Promise<CoverageDetails.Serialized[]>;
3644 > /** Disposes resources associated with a test run. */
3645 > $disposeRun(runId: string): void;
3646 > /** Configures a test run config. */
3647 > $configureRunProfile(controllerId: string, configId: number): void;
3648 > /** Asks the controller to refresh its tests */
3649 > $refreshTests(controllerId: string, token: CancellationToken): Promise<void>;
3650 > /** Ensures any pending test diffs are flushed */
3651 > $syncTests(): Promise<void>;
3652 > /** Sets the active test run profiles */
3653 > $setDefaultRunProfiles(profiles: Record</* controller id */string, /* profile id */ number[]>): void;
3654 > $getTestsRelatedToCode(uri: UriComponents, position: IPosition, token: CancellationToken): Promise<string[]>;
3655 > $getCodeRelatedToTest(testId: string, token: CancellationToken): Promise<ILocationDto[]>;
3656 >
3657 > // --- test results:
3658 >
3659 > /** Publishes that a test run finished. */
3660 > $publishTestResults(results: ISerializedTestResults[]): void;
3661 > /** Requests followup actions for a test (failure) message */
3662 > $provideTestFollowups(req: TestMessageFollowupRequest, token: CancellationToken): Promise<TestMessageFollowupResponse[]>;
3663 > /** Actions a followup actions for a test (failure) message */
3664 > $executeTestFollowup(id: number): Promise<void>;
3665 > /** Disposes followup actions for a test (failure) message */
3666 > $disposeTestFollowups(id: number[]): void;
3667 > }
3668 >
3669 > export interface IStartMcpOptions {
3670 > launch: McpServerLaunch.Serialized;
3671 > defaultCwd?: UriComponents;
3672 > errorOnUserInteraction?: boolean;
3673 > }
3674 >
3675 > export interface ExtHostMcpShape {
3676 > $substituteVariables(workspaceFolder: UriComponents | undefined, value: McpServerLaunch.Serialized): Promise<McpServerLaunch.Serialized>;
3677 > $resolveMcpLaunch(collectionId: string, label: string): Promise<McpServerLaunch.Serialized | undefined>;
3678 > $startMcp(id: number, opts: IStartMcpOptions): void;
3679 > $stopMcp(id: number): void;
3680 > $sendMessage(id: number, message: string): void;
3681 > $waitForInitialCollectionProviders(): Promise<void>;
3682 > $onDidChangeMcpServerDefinitions(servers: McpServerDefinition.Serialized[]): void;
3683 > $onDidChangeGatewayServers(gatewayId: string, servers: { label: string; address: UriComponents }[]): void;
3684 > }
3685 >
3686 > export interface IMcpAuthenticationDetails {
3687 > authorizationServer: UriComponents;
3688 > authorizationServerMetadata: IAuthorizationServerMetadata;
3689 > resourceMetadata: IAuthorizationProtectedResourceMetadata | undefined;
3690 > scopes: string[] | undefined;
3691 > clientId?: string;
3692 > /**
3693 > * When true, the MCP server has opted into enterprise-managed authentication
3694 > * (OAuth Identity Assertion Authorization Grant). The main thread is expected
3695 > * to route token acquisition through the XAA authentication provider for the
3696 > * configured issuer rather than the per-resource dynamic auth provider.
3697 > */
3698 > enterpriseManaged?: boolean;
3699 > }
3700 >
3701 > export interface IMcpAuthenticationOptions {
3702 > errorOnUserInteraction?: boolean;
3703 > forceNewRegistration?: boolean;
3704 > clientId?: string;
3705 > }
3706 >
3707 > export const enum IAuthResourceMetadataSource {
3708 > Header = 'header',
3709 > WellKnown = 'wellKnown',
3710 > None = 'none',
3711 > }
3712 >
3713 > export const enum IAuthServerMetadataSource {
3714 > ResourceMetadata = 'resourceMetadata',
3715 > WellKnown = 'wellKnown',
3716 > Default = 'default',
3717 > }
3718 >
3719 > export interface IAuthMetadataSource {
3720 > resourceMetadataSource: IAuthResourceMetadataSource;
3721 > serverMetadataSource: IAuthServerMetadataSource;
3722 > }
3723 >
3724 > export interface MainThreadMcpShape {
3725 > $onDidChangeState(id: number, state: McpConnectionState): void;
3726 > $onDidPublishLog(id: number, level: LogLevel, log: string): void;
3727 > $onDidReceiveMessage(id: number, message: string): void;
3728 > $upsertMcpCollection(collection: McpCollectionDefinition.FromExtHost, servers: McpServerDefinition.Serialized[]): void;
3729 > $deleteMcpCollection(collectionId: string): void;
3730 > $getTokenFromServerMetadata(id: number, authDetails: IMcpAuthenticationDetails, options?: IMcpAuthenticationOptions): Promise<string | undefined>;
3731 > $getTokenForProviderId(id: number, providerId: string, scopes: string[], options?: IMcpAuthenticationOptions): Promise<string | undefined>;
3732 > $logMcpAuthSetup(data: IAuthMetadataSource): void;
3733 > $startMcpGateway(chatSessionResource?: UriComponents): Promise<{ servers: { label: string; address: UriComponents }[]; gatewayId: string } | undefined>;
3734 > $disposeMcpGateway(gatewayId: string): void;
3735 > }
3736 >
3737 > export interface MainThreadDataChannelsShape extends IDisposable {
3738 > }
3739 >
3740 > export interface ExtHostDataChannelsShape {
3741 > $onDidReceiveData(channelId: string, data: unknown): void;
3742 > }
3743 >
3744 > export interface ExtHostLocalizationShape {
3745 > getMessage(extensionId: string, details: IStringDetails): string;
3746 > getBundle(extensionId: string): { [key: string]: string } | undefined;
3747 > getBundleUri(extensionId: string): URI | undefined;
3748 > initializeLocalizedMessages(extension: IExtensionDescription): Promise<void>;
3749 > }
3750 >
3751 > export interface IStringDetails {
3752 > message: string;
3753 > args?: Record<string | number, any>;
3754 > comment?: string | string[];
3755 > }
3756 >
3757 > export interface ITestControllerPatch {
3758 > label?: string;
3759 > capabilities?: TestControllerCapability;
3760 > }
3761 >
3762 > export interface MainThreadTestingShape {
3763 > // --- test lifecycle:
3764 >
3765 > /** Registers that there's a test controller with the given ID */
3766 > $registerTestController(controllerId: string, label: string, capability: TestControllerCapability): void;
3767 > /** Updates the label of an existing test controller. */
3768 > $updateController(controllerId: string, patch: ITestControllerPatch): void;
3769 > /** Diposes of the test controller with the given ID */
3770 > $unregisterTestController(controllerId: string): void;
3771 > /** Requests tests published to VS Code. */
3772 > $subscribeToDiffs(): void;
3773 > /** Stops requesting tests published to VS Code. */
3774 > $unsubscribeFromDiffs(): void;
3775 > /** Publishes that new tests were available on the given source. */
3776 > $publishDiff(controllerId: string, diff: TestsDiffOp.Serialized[]): void;
3777 > /** Gets coverage details from a test result. */
3778 > $getCoverageDetails(resultId: string, taskIndex: number, uri: UriComponents, token: CancellationToken): Promise<CoverageDetails.Serialized[]>;
3779 >
3780 > // --- test run configurations:
3781 >
3782 > /** Called when a new test run configuration is available */
3783 > $publishTestRunProfile(config: ITestRunProfile): void;
3784 > /** Updates an existing test run configuration */
3785 > $updateTestRunConfig(controllerId: string, configId: number, update: Partial<ITestRunProfile>): void;
3786 > /** Removes a previously-published test run config */
3787 > $removeTestProfile(controllerId: string, configId: number): void;
3788 >
3789 >
3790 > // --- test run handling:
3791 >
3792 > /** Request by an extension to run tests. */
3793 > $runTests(req: ResolvedTestRunRequest, token: CancellationToken): Promise<string>;
3794 > /**
3795 > * Adds tests to the run. The tests are given in descending depth. The first
3796 > * item will be a previously-known test, or a test root.
3797 > */
3798 > $addTestsToRun(controllerId: string, runId: string, tests: ITestItem.Serialized[]): void;
3799 > /** Updates the state of a test run in the given run. */
3800 > $updateTestStateInRun(runId: string, taskId: string, testId: string, state: TestResultState, duration?: number): void;
3801 > /** Appends a message to a test in the run. */
3802 > $appendTestMessagesInRun(runId: string, taskId: string, testId: string, messages: ITestMessage.Serialized[]): void;
3803 > /** Appends raw output to the test run.. */
3804 > $appendOutputToRun(runId: string, taskId: string, output: VSBuffer, location?: ILocationDto, testId?: string): void;
3805 > /** Triggered when coverage is added to test results. */
3806 > $appendCoverage(runId: string, taskId: string, coverage: IFileCoverage.Serialized): void;
3807 > /** Signals a task in a test run started. */
3808 > $startedTestRunTask(runId: string, task: ITestRunTask): void;
3809 > /** Signals a task in a test run ended. */
3810 > $finishedTestRunTask(runId: string, taskId: string): void;
3811 > /** Start a new extension-provided test run. */
3812 > $startedExtensionTestRun(req: ExtensionRunTestsRequest): void;
3813 > /** Signals that an extension-provided test run finished. */
3814 > $finishedExtensionTestRun(runId: string): void;
3815 > /** Marks a test (or controller) as retired in all results. */
3816 > $markTestRetired(testIds: string[] | undefined): void;
3817 > }
3818 >
3819 > export type ChatStatusItemDto = {
3820 > id: string;
3821 > title: string | { label: string; link: string; helpText?: string };
3822 > description: string;
3823 > detail: string | undefined;
3824 > tooltip: string | undefined;
3825 > };
3826 >
3827 > export interface MainThreadChatStatusShape {
3828 > $setEntry(id: string, entry: ChatStatusItemDto): void;
3829 > $disposeEntry(id: string): void;
3830 > }
3831 >
3832 > export interface MainThreadChatQuotaShape extends IDisposable {
3833 > $updateQuotas(quotas: IQuotaSnapshotsDto): void;
3834 > }
3835 >
3836 > export interface ExtHostChatQuotaShape {
3837 > }
3838 >
3839 > export const enum ChatInputNotificationSeverityDto {
3840 > Info = 0,
3841 > Warning = 1,
3842 > Error = 2,
3843 > }
3844 >
3845 > export type ChatInputNotificationActionDto = {
3846 > label: string;
3847 > commandId: string;
3848 > commandArgs?: unknown[];
3849 > };
3850 >
3851 > export type ChatInputNotificationDto = {
3852 > id: string;
3853 > severity: ChatInputNotificationSeverityDto;
3854 > message: string;
3855 > description: string | undefined;
3856 > actions: ChatInputNotificationActionDto[];
3857 > dismissible: boolean;
3858 > autoDismissOnMessage: boolean;
3859 > };
3860 >
3861 > export interface MainThreadChatInputNotificationShape {
3862 > $setNotification(notification: ChatInputNotificationDto): void;
3863 > $disposeNotification(id: string): void;
3864 > }
3865 >
3866 > export type IChatSessionHistoryItemDto = {
3867 > id?: string;
3868 > type: 'request';
3869 > prompt: string;
3870 > participant: string;
3871 > command?: string;
3872 > variableData?: Dto<IChatRequestVariableData>;
3873 > modelId?: string;
3874 > modeInstructions?: Dto<IChatRequestModeInstructions>;
3875 > } | {
3876 > type: 'response';
3877 > parts: IChatProgressDto[];
3878 > participant: string;
3879 > details?: string;
3880 > };
3881 >
3882 > export type IChatSessionRequestHistoryItemDto = Extract<IChatSessionHistoryItemDto, { type: 'request' }>;
3883 >
3884 >
3885 >
3886 > export interface ChatSessionContentContextDto {
3887 > readonly initialSessionOptions?: ReadonlyArray<{ optionId: string; value: string }>;
3888 > }
3889 >
3890 > export interface IChatNewSessionRequestDto {
3891 > readonly prompt: string;
3892 > readonly command?: string;
3893 >
3894 > readonly initialSessionOptions?: ReadonlyArray<{ optionId: string; value: string }>;
3895 > }
3896 >
3897 > export interface IChatSessionDto {
3898 > resource: UriComponents;
3899 > title?: string;
3900 > history: Array<IChatSessionHistoryItemDto>;
3901 > hasActiveResponseCallback: boolean;
3902 > hasRequestHandler: boolean;
3903 > hasForkHandler: boolean;
3904 > supportsInterruption: boolean;
3905 > options?: Record<string, string | IChatSessionProviderOptionItem>;
3906 > }
3907 >
3908 > export interface IChatSessionProviderOptions {
3909 > optionGroups?: readonly IChatSessionProviderOptionGroup[];
3910 > newSessionOptions?: Record<string, string | IChatSessionProviderOptionItem>;
3911 > }
3912 >
3913 > export interface IChatSessionItemsChange {
3914 > readonly addedOrUpdated: readonly Dto<IChatSessionItem>[];
3915 > readonly removed: readonly UriComponents[];
3916 > }
3917 >
3918 > export interface MainThreadChatSessionsShape extends IDisposable {
3919 > $registerChatSessionItemController(controllerHandle: number, chatSessionType: string, supportsResolve: boolean): void;
3920 > $updateChatSessionItemControllerCapabilities(controllerHandle: number, supportsResolve: boolean): void;
3921 > $unregisterChatSessionItemController(controllerHandle: number): void;
3922 > $updateChatSessionItems(controllerHandle: number, change: IChatSessionItemsChange): Promise<void>;
3923 > $addOrUpdateChatSessionItem(controllerHandle: number, item: Dto<IChatSessionItem>): Promise<void>;
3924 > $onDidCommitChatSessionItem(controllerHandle: number, original: UriComponents, modified: UriComponents): void;
3925 > $registerChatSessionContentProvider(handle: number, chatSessionScheme: string): void;
3926 > $unregisterChatSessionContentProvider(handle: number): void;
3927 > $onDidChangeChatSessionOptions(handle: number, sessionResource: UriComponents, updates: Record<string, string | IChatSessionProviderOptionItem>): void;
3928 > $onDidChangeChatSessionProviderOptions(handle: number): void;
3929 >
3930 > $updateChatSessionInputState(controllerHandle: number, sessionResource: UriComponents, optionGroups: readonly IChatSessionProviderOptionGroup[]): void;
3931 >
3932 > $handleProgressChunk(handle: number, sessionResource: UriComponents, requestId: string, chunks: (IChatProgressDto | [IChatProgressDto, number])[]): Promise<void>;
3933 > $handleAnchorResolve(handle: number, sessionResource: UriComponents, requestId: string, requestHandle: string, anchor: Dto<IChatContentInlineReference>): void;
3934 > $handleProgressComplete(handle: number, sessionResource: UriComponents, requestId: string): void;
3935 > }
3936 >
3937 > export interface ExtHostChatSessionsShape {
3938 > $refreshChatSessionItems(providerHandle: number, token: CancellationToken): Promise<void>;
3939 > $onDidChangeChatSessionItemState(providerHandle: number, sessionResource: UriComponents, archived: boolean): void;
3940 > $newChatSessionItem(controllerHandle: number, request: IChatNewSessionRequestDto, token: CancellationToken): Promise<Dto<IChatSessionItem> | undefined>;
3941 >
3942 > $provideChatSessionContent(providerHandle: number, sessionResource: UriComponents, context: ChatSessionContentContextDto, token: CancellationToken): Promise<IChatSessionDto>;
3943 > $interruptChatSessionActiveResponse(providerHandle: number, sessionResource: UriComponents, requestId: string): Promise<void>;
3944 > $disposeChatSessionContent(providerHandle: number, sessionResource: UriComponents): Promise<void>;
3945 > $invokeChatSessionRequestHandler(providerHandle: number, sessionResource: UriComponents, request: IChatAgentRequest, history: any[], token: CancellationToken): Promise<IChatAgentResult>;
3946 > $provideChatSessionProviderOptions(providerHandle: number, token: CancellationToken): Promise<IChatSessionProviderOptions | undefined>;
3947 > $provideHandleOptionsChange(providerHandle: number, sessionResource: UriComponents, updates: Record<string, string | IChatSessionProviderOptionItem | undefined>, token: CancellationToken): Promise<void>;
3948 > $forkChatSession(providerHandle: number, sessionResource: UriComponents, request: IChatSessionRequestHistoryItemDto | undefined, token: CancellationToken): Promise<Dto<IChatSessionItem>>;
3949 > $resolveChatSessionItem(providerHandle: number, sessionResource: UriComponents, token: CancellationToken): Promise<Dto<IChatSessionItem> | undefined>;
3950 > $provideChatSessionInputState(controllerHandle: number, sessionResource: UriComponents | undefined, token: CancellationToken): Promise<IChatSessionProviderOptionGroup[] | undefined>;
3951 > }
3952 >
3953 > export interface GitRefQueryDto {
3954 > readonly contains?: string;
3955 > readonly count?: number;
3956 > readonly pattern?: string | string[];
3957 > readonly sort?: 'alphabetically' | 'committerdate' | 'creatordate';
3958 > }
3959 >
3960 > export enum GitRefTypeDto {
3961 > Head,
3962 > RemoteHead,
3963 > Tag
3964 > }
3965 >
3966 > export interface GitRefDto {
3967 > readonly id: string;
3968 > readonly name: string;
3969 > readonly type: GitRefTypeDto;
3970 > readonly revision: string;
3971 > }
3972 >
3973 > export interface GitChangeDto {
3974 > readonly uri: UriComponents;
3975 > readonly originalUri: UriComponents | undefined;
3976 > readonly modifiedUri: UriComponents | undefined;
3977 > }
3978 >
3979 > export interface GitDiffChangeDto extends GitChangeDto {
3980 > readonly insertions: number;
3981 > readonly deletions: number;
3982 > }
3983 >
3984 > export interface GitRemoteDto {
3985 > readonly name: string;
3986 > readonly fetchUrl?: string;
3987 > readonly pushUrl?: string;
3988 > readonly isReadOnly: boolean;
3989 > }
3990 >
3991 > export interface GitRepositoryStateDto {
3992 > readonly HEAD?: GitBranchDto;
3993 > readonly remotes: readonly GitRemoteDto[];
3994 > readonly mergeChanges: readonly GitChangeDto[];
3995 > readonly indexChanges: readonly GitChangeDto[];
3996 > readonly workingTreeChanges: readonly GitChangeDto[];
3997 > readonly untrackedChanges: readonly GitChangeDto[];
3998 > }
3999 >
4000 > export interface GitBranchDto {
4001 > readonly name?: string;
4002 > readonly commit?: string;
4003 > readonly type: GitRefTypeDto;
4004 > readonly remote?: string;
4005 > readonly upstream?: GitUpstreamRefDto;
4006 > readonly ahead?: number;
4007 > readonly behind?: number;
4008 > }
4009 >
4010 > export interface GitBaseRefDto {
4011 > readonly name: string;
4012 > readonly isProtected: boolean;
4013 > }
4014 >
4015 > export interface GitUpstreamRefDto {
4016 > readonly remote: string;
4017 > readonly name: string;
4018 > readonly commit?: string;
4019 > }
4020 >
4021 > export interface ExtHostGitExtensionShape {
4022 > $isGitExtensionAvailable(): Promise<boolean>;
4023 > $openRepository(root: UriComponents): Promise<{ handle: number; rootUri: UriComponents; state: GitRepositoryStateDto } | undefined>;
4024 > $getRefs(handle: number, query: GitRefQueryDto, token?: CancellationToken): Promise<GitRefDto[]>;
4025 > $getRepositoryState(handle: number): Promise<GitRepositoryStateDto | undefined>;
4026 > $diffBetweenWithStats(handle: number, ref1: string, ref2: string, path?: string): Promise<GitDiffChangeDto[]>;
4027 > $diffBetweenWithStats2(handle: number, ref: string, path?: string): Promise<GitDiffChangeDto[]>;
4028 > }
4029 >
4030 > // --- proxy identifiers
4031 >
4032 > export const MainContext = {
4033 > MainThreadAuthentication: createProxyIdentifier<MainThreadAuthenticationShape>('MainThreadAuthentication'),
4034 > MainThreadBulkEdits: createProxyIdentifier<MainThreadBulkEditsShape>('MainThreadBulkEdits'),
4035 > MainThreadLanguageModels: createProxyIdentifier<MainThreadLanguageModelsShape>('MainThreadLanguageModels'),
4036 > MainThreadEmbeddings: createProxyIdentifier<MainThreadEmbeddingsShape>('MainThreadEmbeddings'),
4037 > MainThreadChatAgents2: createProxyIdentifier<MainThreadChatAgentsShape2>('MainThreadChatAgents2'),
4038 > MainThreadCodeMapper: createProxyIdentifier<MainThreadCodeMapperShape>('MainThreadCodeMapper'),
4039 > MainThreadLanguageModelTools: createProxyIdentifier<MainThreadLanguageModelToolsShape>('MainThreadChatSkills'),
4040 > MainThreadGitExtension: createProxyIdentifier<MainThreadGitExtensionShape>('MainThreadGitExtension'),
4041 > MainThreadClipboard: createProxyIdentifier<MainThreadClipboardShape>('MainThreadClipboard'),
4042 > MainThreadCommands: createProxyIdentifier<MainThreadCommandsShape>('MainThreadCommands'),
4043 > MainThreadComments: createProxyIdentifier<MainThreadCommentsShape>('MainThreadComments'),
4044 > MainThreadConfiguration: createProxyIdentifier<MainThreadConfigurationShape>('MainThreadConfiguration'),
4045 > MainThreadConsole: createProxyIdentifier<MainThreadConsoleShape>('MainThreadConsole'),
4046 > MainThreadDebugService: createProxyIdentifier<MainThreadDebugServiceShape>('MainThreadDebugService'),
4047 > MainThreadDecorations: createProxyIdentifier<MainThreadDecorationsShape>('MainThreadDecorations'),
4048 > MainThreadDiagnostics: createProxyIdentifier<MainThreadDiagnosticsShape>('MainThreadDiagnostics'),
4049 > MainThreadDialogs: createProxyIdentifier<MainThreadDiaglogsShape>('MainThreadDiaglogs'),
4050 > MainThreadDocuments: createProxyIdentifier<MainThreadDocumentsShape>('MainThreadDocuments'),
4051 > MainThreadDocumentContentProviders: createProxyIdentifier<MainThreadDocumentContentProvidersShape>('MainThreadDocumentContentProviders'),
4052 > MainThreadTextEditors: createProxyIdentifier<MainThreadTextEditorsShape>('MainThreadTextEditors'),
4053 > MainThreadEditorInsets: createProxyIdentifier<MainThreadEditorInsetsShape>('MainThreadEditorInsets'),
4054 > MainThreadEditorTabs: createProxyIdentifier<MainThreadEditorTabsShape>('MainThreadEditorTabs'),
4055 > MainThreadErrors: createProxyIdentifier<MainThreadErrorsShape>('MainThreadErrors'),
4056 > MainThreadTreeViews: createProxyIdentifier<MainThreadTreeViewsShape>('MainThreadTreeViews'),
4057 > MainThreadDownloadService: createProxyIdentifier<MainThreadDownloadServiceShape>('MainThreadDownloadService'),
4058 > MainThreadLanguageFeatures: createProxyIdentifier<MainThreadLanguageFeaturesShape>('MainThreadLanguageFeatures'),
4059 > MainThreadLanguages: createProxyIdentifier<MainThreadLanguagesShape>('MainThreadLanguages'),
4060 > MainThreadLogger: createProxyIdentifier<MainThreadLoggerShape>('MainThreadLogger'),
4061 > MainThreadMessageService: createProxyIdentifier<MainThreadMessageServiceShape>('MainThreadMessageService'),
4062 > MainThreadOutputService: createProxyIdentifier<MainThreadOutputServiceShape>('MainThreadOutputService'),
4063 > MainThreadProgress: createProxyIdentifier<MainThreadProgressShape>('MainThreadProgress'),
4064 > MainThreadQuickDiff: createProxyIdentifier<MainThreadQuickDiffShape>('MainThreadQuickDiff'),
4065 > MainThreadAgentEditorComments: createProxyIdentifier<MainThreadAgentEditorCommentsShape>('MainThreadAgentEditorComments'),
4066 > MainThreadDocumentDiff: createProxyIdentifier<MainThreadDocumentDiffShape>('MainThreadDocumentDiff'),
4067 > MainThreadQuickOpen: createProxyIdentifier<MainThreadQuickOpenShape>('MainThreadQuickOpen'),
4068 > MainThreadStatusBar: createProxyIdentifier<MainThreadStatusBarShape>('MainThreadStatusBar'),
4069 > MainThreadSecretState: createProxyIdentifier<MainThreadSecretStateShape>('MainThreadSecretState'),
4070 > MainThreadStorage: createProxyIdentifier<MainThreadStorageShape>('MainThreadStorage'),
4071 > MainThreadSpeech: createProxyIdentifier<MainThreadSpeechShape>('MainThreadSpeechProvider'),
4072 > MainThreadTelemetry: createProxyIdentifier<MainThreadTelemetryShape>('MainThreadTelemetry'),
4073 > MainThreadMeteredConnection: createProxyIdentifier<MainThreadMeteredConnectionShape>('MainThreadMeteredConnection'),
4074 > MainThreadTerminalService: createProxyIdentifier<MainThreadTerminalServiceShape>('MainThreadTerminalService'),
4075 > MainThreadTerminalShellIntegration: createProxyIdentifier<MainThreadTerminalShellIntegrationShape>('MainThreadTerminalShellIntegration'),
4076 > MainThreadWebviews: createProxyIdentifier<MainThreadWebviewsShape>('MainThreadWebviews'),
4077 > MainThreadWebviewPanels: createProxyIdentifier<MainThreadWebviewPanelsShape>('MainThreadWebviewPanels'),
4078 > MainThreadWebviewViews: createProxyIdentifier<MainThreadWebviewViewsShape>('MainThreadWebviewViews'),
4079 > MainThreadCustomEditors: createProxyIdentifier<MainThreadCustomEditorsShape>('MainThreadCustomEditors'),
4080 > MainThreadUrls: createProxyIdentifier<MainThreadUrlsShape>('MainThreadUrls'),
4081 > MainThreadUriOpeners: createProxyIdentifier<MainThreadUriOpenersShape>('MainThreadUriOpeners'),
4082 > MainThreadProfileContentHandlers: createProxyIdentifier<MainThreadProfileContentHandlersShape>('MainThreadProfileContentHandlers'),
4083 > MainThreadWorkspace: createProxyIdentifier<MainThreadWorkspaceShape>('MainThreadWorkspace'),
4084 > MainThreadFileSystem: createProxyIdentifier<MainThreadFileSystemShape>('MainThreadFileSystem'),
4085 > MainThreadFileSystemEventService: createProxyIdentifier<MainThreadFileSystemEventServiceShape>('MainThreadFileSystemEventService'),
4086 > MainThreadExtensionService: createProxyIdentifier<MainThreadExtensionServiceShape>('MainThreadExtensionService'),
4087 > MainThreadSCM: createProxyIdentifier<MainThreadSCMShape>('MainThreadSCM'),
4088 > MainThreadSearch: createProxyIdentifier<MainThreadSearchShape>('MainThreadSearch'),
4089 > MainThreadShare: createProxyIdentifier<MainThreadShareShape>('MainThreadShare'),
4090 > MainThreadTask: createProxyIdentifier<MainThreadTaskShape>('MainThreadTask'),
4091 > MainThreadWindow: createProxyIdentifier<MainThreadWindowShape>('MainThreadWindow'),
4092 > MainThreadPower: createProxyIdentifier<MainThreadPowerShape>('MainThreadPower'),
4093 > MainThreadLabelService: createProxyIdentifier<MainThreadLabelServiceShape>('MainThreadLabelService'),
4094 > MainThreadNotebook: createProxyIdentifier<MainThreadNotebookShape>('MainThreadNotebook'),
4095 > MainThreadNotebookDocuments: createProxyIdentifier<MainThreadNotebookDocumentsShape>('MainThreadNotebookDocumentsShape'),
4096 > MainThreadNotebookEditors: createProxyIdentifier<MainThreadNotebookEditorsShape>('MainThreadNotebookEditorsShape'),
4097 > MainThreadNotebookKernels: createProxyIdentifier<MainThreadNotebookKernelsShape>('MainThreadNotebookKernels'),
4098 > MainThreadNotebookRenderers: createProxyIdentifier<MainThreadNotebookRenderersShape>('MainThreadNotebookRenderers'),
4099 > MainThreadInteractive: createProxyIdentifier<MainThreadInteractiveShape>('MainThreadInteractive'),
4100 > MainThreadTheming: createProxyIdentifier<MainThreadThemingShape>('MainThreadTheming'),
4101 > MainThreadTunnelService: createProxyIdentifier<MainThreadTunnelServiceShape>('MainThreadTunnelService'),
4102 > MainThreadManagedSockets: createProxyIdentifier<MainThreadManagedSocketsShape>('MainThreadManagedSockets'),
4103 > MainThreadBrowserTunnelProxy: createProxyIdentifier<MainThreadBrowserTunnelProxyShape>('MainThreadBrowserTunnelProxy'),
4104 > MainThreadTimeline: createProxyIdentifier<MainThreadTimelineShape>('MainThreadTimeline'),
4105 > MainThreadTesting: createProxyIdentifier<MainThreadTestingShape>('MainThreadTesting'),
4106 > MainThreadLocalization: createProxyIdentifier<MainThreadLocalizationShape>('MainThreadLocalizationShape'),
4107 > MainThreadMcp: createProxyIdentifier<MainThreadMcpShape>('MainThreadMcpShape'),
4108 > MainThreadAiRelatedInformation: createProxyIdentifier<MainThreadAiRelatedInformationShape>('MainThreadAiRelatedInformation'),
4109 > MainThreadAiEmbeddingVector: createProxyIdentifier<MainThreadAiEmbeddingVectorShape>('MainThreadAiEmbeddingVector'),
4110 > MainThreadChatStatus: createProxyIdentifier<MainThreadChatStatusShape>('MainThreadChatStatus'),
4111 > MainThreadChatQuota: createProxyIdentifier<MainThreadChatQuotaShape>('MainThreadChatQuota'),
4112 > MainThreadChatInputNotification: createProxyIdentifier<MainThreadChatInputNotificationShape>('MainThreadChatInputNotification'),
4113 > MainThreadAiSettingsSearch: createProxyIdentifier<MainThreadAiSettingsSearchShape>('MainThreadAiSettingsSearch'),
4114 > MainThreadDataChannels: createProxyIdentifier<MainThreadDataChannelsShape>('MainThreadDataChannels'),
4115 > MainThreadChatSessions: createProxyIdentifier<MainThreadChatSessionsShape>('MainThreadChatSessions'),
4116 > MainThreadChatOutputRenderer: createProxyIdentifier<MainThreadChatOutputRendererShape>('MainThreadChatOutputRenderer'),
4117 > MainThreadChatContext: createProxyIdentifier<MainThreadChatContextShape>('MainThreadChatContext'),
4118 > MainThreadChatDebug: createProxyIdentifier<MainThreadChatDebugShape>('MainThreadChatDebug'),
4119 > MainThreadBrowsers: createProxyIdentifier<MainThreadBrowsersShape>('MainThreadBrowsers'),
4120 > };
4121 >
4122 > export const ExtHostContext = {
4123 > ExtHostCodeMapper: createProxyIdentifier<ExtHostCodeMapperShape>('ExtHostCodeMapper'),
4124 > ExtHostCommands: createProxyIdentifier<ExtHostCommandsShape>('ExtHostCommands'),
4125 > ExtHostConfiguration: createProxyIdentifier<ExtHostConfigurationShape>('ExtHostConfiguration'),
4126 > ExtHostDiagnostics: createProxyIdentifier<ExtHostDiagnosticsShape>('ExtHostDiagnostics'),
4127 > ExtHostDebugService: createProxyIdentifier<ExtHostDebugServiceShape>('ExtHostDebugService'),
4128 > ExtHostDecorations: createProxyIdentifier<ExtHostDecorationsShape>('ExtHostDecorations'),
4129 > ExtHostDocumentsAndEditors: createProxyIdentifier<ExtHostDocumentsAndEditorsShape>('ExtHostDocumentsAndEditors'),
4130 > ExtHostDocuments: createProxyIdentifier<ExtHostDocumentsShape>('ExtHostDocuments'),
4131 > ExtHostDocumentContentProviders: createProxyIdentifier<ExtHostDocumentContentProvidersShape>('ExtHostDocumentContentProviders'),
4132 > ExtHostDocumentSaveParticipant: createProxyIdentifier<ExtHostDocumentSaveParticipantShape>('ExtHostDocumentSaveParticipant'),
4133 > ExtHostEditors: createProxyIdentifier<ExtHostEditorsShape>('ExtHostEditors'),
4134 > ExtHostTreeViews: createProxyIdentifier<ExtHostTreeViewsShape>('ExtHostTreeViews'),
4135 > ExtHostFileSystem: createProxyIdentifier<ExtHostFileSystemShape>('ExtHostFileSystem'),
4136 > ExtHostFileSystemInfo: createProxyIdentifier<ExtHostFileSystemInfoShape>('ExtHostFileSystemInfo'),
4137 > ExtHostFileSystemEventService: createProxyIdentifier<ExtHostFileSystemEventServiceShape>('ExtHostFileSystemEventService'),
4138 > ExtHostLanguages: createProxyIdentifier<ExtHostLanguagesShape>('ExtHostLanguages'),
4139 > ExtHostLanguageFeatures: createProxyIdentifier<ExtHostLanguageFeaturesShape>('ExtHostLanguageFeatures'),
4140 > ExtHostQuickOpen: createProxyIdentifier<ExtHostQuickOpenShape>('ExtHostQuickOpen'),
4141 > ExtHostQuickDiff: createProxyIdentifier<ExtHostQuickDiffShape>('ExtHostQuickDiff'),
4142 > ExtHostAgentEditorComments: createProxyIdentifier<ExtHostAgentEditorCommentsShape>('ExtHostAgentEditorComments'),
4143 > ExtHostStatusBar: createProxyIdentifier<ExtHostStatusBarShape>('ExtHostStatusBar'),
4144 > ExtHostShare: createProxyIdentifier<ExtHostShareShape>('ExtHostShare'),
4145 > ExtHostExtensionService: createProxyIdentifier<ExtHostExtensionServiceShape>('ExtHostExtensionService'),
4146 > ExtHostLogLevelServiceShape: createProxyIdentifier<ExtHostLogLevelServiceShape>('ExtHostLogLevelServiceShape'),
4147 > ExtHostTerminalService: createProxyIdentifier<ExtHostTerminalServiceShape>('ExtHostTerminalService'),
4148 > ExtHostTerminalShellIntegration: createProxyIdentifier<ExtHostTerminalShellIntegrationShape>('ExtHostTerminalShellIntegration'),
4149 > ExtHostSCM: createProxyIdentifier<ExtHostSCMShape>('ExtHostSCM'),
4150 > ExtHostSearch: createProxyIdentifier<ExtHostSearchShape>('ExtHostSearch'),
4151 > ExtHostTask: createProxyIdentifier<ExtHostTaskShape>('ExtHostTask'),
4152 > ExtHostWorkspace: createProxyIdentifier<ExtHostWorkspaceShape>('ExtHostWorkspace'),
4153 > ExtHostWindow: createProxyIdentifier<ExtHostWindowShape>('ExtHostWindow'),
4154 > ExtHostPower: createProxyIdentifier<ExtHostPowerShape>('ExtHostPower'),
4155 > ExtHostWebviews: createProxyIdentifier<ExtHostWebviewsShape>('ExtHostWebviews'),
4156 > ExtHostWebviewPanels: createProxyIdentifier<ExtHostWebviewPanelsShape>('ExtHostWebviewPanels'),
4157 > ExtHostCustomEditors: createProxyIdentifier<ExtHostCustomEditorsShape>('ExtHostCustomEditors'),
4158 > ExtHostWebviewViews: createProxyIdentifier<ExtHostWebviewViewsShape>('ExtHostWebviewViews'),
4159 > ExtHostEditorInsets: createProxyIdentifier<ExtHostEditorInsetsShape>('ExtHostEditorInsets'),
4160 > ExtHostEditorTabs: createProxyIdentifier<IExtHostEditorTabsShape>('ExtHostEditorTabs'),
4161 > ExtHostProgress: createProxyIdentifier<ExtHostProgressShape>('ExtHostProgress'),
4162 > ExtHostComments: createProxyIdentifier<ExtHostCommentsShape>('ExtHostComments'),
4163 > ExtHostSecretState: createProxyIdentifier<ExtHostSecretStateShape>('ExtHostSecretState'),
4164 > ExtHostStorage: createProxyIdentifier<ExtHostStorageShape>('ExtHostStorage'),
4165 > ExtHostUrls: createProxyIdentifier<ExtHostUrlsShape>('ExtHostUrls'),
4166 > ExtHostUriOpeners: createProxyIdentifier<ExtHostUriOpenersShape>('ExtHostUriOpeners'),
4167 > ExtHostChatOutputRenderer: createProxyIdentifier<ExtHostChatOutputRendererShape>('ExtHostChatOutputRenderer'),
4168 > ExtHostProfileContentHandlers: createProxyIdentifier<ExtHostProfileContentHandlersShape>('ExtHostProfileContentHandlers'),
4169 > ExtHostOutputService: createProxyIdentifier<ExtHostOutputServiceShape>('ExtHostOutputService'),
4170 > ExtHostLabelService: createProxyIdentifier<ExtHostLabelServiceShape>('ExtHostLabelService'),
4171 > ExtHostNotebook: createProxyIdentifier<ExtHostNotebookShape>('ExtHostNotebook'),
4172 > ExtHostNotebookDocuments: createProxyIdentifier<ExtHostNotebookDocumentsShape>('ExtHostNotebookDocuments'),
4173 > ExtHostNotebookEditors: createProxyIdentifier<ExtHostNotebookEditorsShape>('ExtHostNotebookEditors'),
4174 > ExtHostNotebookKernels: createProxyIdentifier<ExtHostNotebookKernelsShape>('ExtHostNotebookKernels'),
4175 > ExtHostNotebookRenderers: createProxyIdentifier<ExtHostNotebookRenderersShape>('ExtHostNotebookRenderers'),
4176 > ExtHostNotebookDocumentSaveParticipant: createProxyIdentifier<ExtHostNotebookDocumentSaveParticipantShape>('ExtHostNotebookDocumentSaveParticipant'),
4177 > ExtHostInteractive: createProxyIdentifier<ExtHostInteractiveShape>('ExtHostInteractive'),
4178 > ExtHostChatAgents2: createProxyIdentifier<ExtHostChatAgentsShape2>('ExtHostChatAgents'),
4179 > ExtHostLanguageModelTools: createProxyIdentifier<ExtHostLanguageModelToolsShape>('ExtHostChatSkills'),
4180 > ExtHostChatProvider: createProxyIdentifier<ExtHostLanguageModelsShape>('ExtHostChatProvider'),
4181 > ExtHostChatContext: createProxyIdentifier<ExtHostChatContextShape>('ExtHostChatContext'),
4182 > ExtHostChatDebug: createProxyIdentifier<ExtHostChatDebugShape>('ExtHostChatDebug'),
4183 > ExtHostSpeech: createProxyIdentifier<ExtHostSpeechShape>('ExtHostSpeech'),
4184 > ExtHostEmbeddings: createProxyIdentifier<ExtHostEmbeddingsShape>('ExtHostEmbeddings'),
4185 > ExtHostAiRelatedInformation: createProxyIdentifier<ExtHostAiRelatedInformationShape>('ExtHostAiRelatedInformation'),
4186 > ExtHostAiEmbeddingVector: createProxyIdentifier<ExtHostAiEmbeddingVectorShape>('ExtHostAiEmbeddingVector'),
4187 > ExtHostAiSettingsSearch: createProxyIdentifier<ExtHostAiSettingsSearchShape>('ExtHostAiSettingsSearch'),
4188 > ExtHostTheming: createProxyIdentifier<ExtHostThemingShape>('ExtHostTheming'),
4189 > ExtHostTunnelService: createProxyIdentifier<ExtHostTunnelServiceShape>('ExtHostTunnelService'),
4190 > ExtHostManagedSockets: createProxyIdentifier<ExtHostManagedSocketsShape>('ExtHostManagedSockets'),
4191 > ExtHostBrowserTunnelProxy: createProxyIdentifier<ExtHostBrowserTunnelProxyShape>('ExtHostBrowserTunnelProxy'),
4192 > ExtHostAuthentication: createProxyIdentifier<ExtHostAuthenticationShape>('ExtHostAuthentication'),
4193 > ExtHostTimeline: createProxyIdentifier<ExtHostTimelineShape>('ExtHostTimeline'),
4194 > ExtHostTesting: createProxyIdentifier<ExtHostTestingShape>('ExtHostTesting'),
4195 > ExtHostTelemetry: createProxyIdentifier<ExtHostTelemetryShape>('ExtHostTelemetry'),
4196 > ExtHostMeteredConnection: createProxyIdentifier<ExtHostMeteredConnectionShape>('ExtHostMeteredConnection'),
4197 > ExtHostLocalization: createProxyIdentifier<ExtHostLocalizationShape>('ExtHostLocalization'),
4198 > ExtHostMcp: createProxyIdentifier<ExtHostMcpShape>('ExtHostMcp'),
4199 > ExtHostDataChannels: createProxyIdentifier<ExtHostDataChannelsShape>('ExtHostDataChannels'),
4200 > ExtHostChatSessions: createProxyIdentifier<ExtHostChatSessionsShape>('ExtHostChatSessions'),
4201 > ExtHostChatQuota: createProxyIdentifier<ExtHostChatQuotaShape>('ExtHostChatQuota'),
4202 > ExtHostGitExtension: createProxyIdentifier<ExtHostGitExtensionShape>('ExtHostGitExtension'),
4203 > ExtHostBrowsers: createProxyIdentifier<ExtHostBrowsersShape>('ExtHostBrowsers'),
4204 > };
src/vs/platform/mcp/common/modelContextProtocol.ts 3277 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- modelContextProtocol.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > /* eslint-disable local/code-no-unexternalized-strings */
7 >
8 > //#region proposals
9 > /**
10 > * MCP protocol proposals.
11 > * - Proposals here MUST have an MCP PR linked to them
12 > * - Proposals here are subject to change and SHALL be removed when
13 > * the upstream MCP PR is merged or closed.
14 > */
15 > export namespace MCP {
16 >
17 > // Nothing, yet
18 >
19 > }
20 >
21 > //#endregion
22 >
23 > /**
24 > * Schema updated from the Model Context Protocol repository at
25 > * https://github.com/modelcontextprotocol/specification/tree/main/schema
26 > *
27 > * ⚠️ Do not edit within `namespace` manually except to update schema versions ⚠️
28 > */
29 > export namespace MCP {
30 > /* JSON-RPC types */
31 >
32 > /**
33 > * Refers to any valid JSON-RPC object that can be decoded off the wire, or encoded to be sent.
34 > *
35 > * @category JSON-RPC
36 > */
37 > export type JSONRPCMessage =
38 > | JSONRPCRequest
39 > | JSONRPCNotification
40 > | JSONRPCResponse;
41 >
42 > /** @internal */
43 > export const LATEST_PROTOCOL_VERSION = "2025-11-25";
44 > /** @internal */
45 > export const JSONRPC_VERSION = "2.0";
46 >
47 > /**
48 > * Represents the contents of a `_meta` field, which clients and servers use to attach additional metadata to their interactions.
49 > *
50 > * Certain key names are reserved by MCP for protocol-level metadata; implementations MUST NOT make assumptions about values at these keys. Additionally, specific schema definitions may reserve particular names for purpose-specific metadata, as declared in those definitions.
51 > *
52 > * Valid keys have two segments:
53 > *
54 > * **Prefix:**
55 > * - Optional - if specified, MUST be a series of _labels_ separated by dots (`.`), followed by a slash (`/`).
56 > * - Labels MUST start with a letter and end with a letter or digit. Interior characters may be letters, digits, or hyphens (`-`).
57 > * - Any prefix consisting of zero or more labels, followed by `modelcontextprotocol` or `mcp`, followed by any label, is **reserved** for MCP use. For example: `modelcontextprotocol.io/`, `mcp.dev/`, `api.modelcontextprotocol.org/`, and `tools.mcp.com/` are all reserved.
58 > *
59 > * **Name:**
60 > * - Unless empty, MUST start and end with an alphanumeric character (`[a-z0-9A-Z]`).
61 > * - Interior characters may be alphanumeric, hyphens (`-`), underscores (`_`), or dots (`.`).
62 > *
63 > * @see [General fields: `_meta`](/specification/draft/basic/index#meta) for more details.
64 > * @category Common Types
65 > */
66 > export type MetaObject = Record<string, unknown>;
67 >
68 > /**
69 > * Extends {@link MetaObject} with additional request-specific fields. All key naming rules from `MetaObject` apply.
70 > *
71 > * @see {@link MetaObject} for key naming rules and reserved prefixes.
72 > * @see [General fields: `_meta`](/specification/draft/basic/index#meta) for more details.
73 > * @category Common Types
74 > */
75 > export interface RequestMetaObject extends MetaObject {
76 > /**
77 > * If specified, the caller is requesting out-of-band progress notifications for this request (as represented by {@link ProgressNotification | notifications/progress}). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications.
78 > */
79 > progressToken?: ProgressToken;
80 > }
81 >
82 > /**
83 > * A progress token, used to associate progress notifications with the original request.
84 > *
85 > * @category Common Types
86 > */
87 > export type ProgressToken = string | number;
88 >
89 > /**
90 > * An opaque token used to represent a cursor for pagination.
91 > *
92 > * @category Common Types
93 > */
94 > export type Cursor = string;
95 >
96 > /**
97 > * Common params for any task-augmented request.
98 > *
99 > * @internal
100 > */
101 > export interface TaskAugmentedRequestParams extends RequestParams {
102 > /**
103 > * If specified, the caller is requesting task-augmented execution for this request.
104 > * The request will return a {@link CreateTaskResult} immediately, and the actual result can be
105 > * retrieved later via {@link GetTaskPayloadRequest | tasks/result}.
106 > *
107 > * Task augmentation is subject to capability negotiation - receivers MUST declare support
108 > * for task augmentation of specific request types in their capabilities.
109 > */
110 > task?: TaskMetadata;
111 > }
112 >
113 > /**
114 > * Common params for any request.
115 > *
116 > * @category Common Types
117 > */
118 > export interface RequestParams {
119 > _meta?: RequestMetaObject;
120 > }
121 >
122 > /** @internal */
123 > export interface Request {
124 > method: string;
125 > // Allow unofficial extensions of `Request.params` without impacting `RequestParams`.
126 > // eslint-disable-next-line @typescript-eslint/no-explicit-any
127 > params?: { [key: string]: any };
128 > }
129 >
130 > /**
131 > * Common params for any notification.
132 > *
133 > * @category Common Types
134 > */
135 > export interface NotificationParams {
136 > _meta?: MetaObject;
137 > }
138 >
139 > /** @internal */
140 > export interface Notification {
141 > method: string;
142 > // Allow unofficial extensions of `Notification.params` without impacting `NotificationParams`.
143 > // eslint-disable-next-line @typescript-eslint/no-explicit-any
144 > params?: { [key: string]: any };
145 > }
146 >
147 > /**
148 > * Common result fields.
149 > *
150 > * @category Common Types
151 > */
152 > export interface Result {
153 > _meta?: MetaObject;
154 > [key: string]: unknown;
155 > }
156 >
157 > /**
158 > * @category Errors
159 > */
160 > export interface Error {
161 > /**
162 > * The error type that occurred.
163 > */
164 > code: number;
165 > /**
166 > * A short description of the error. The message SHOULD be limited to a concise single sentence.
167 > */
168 > message: string;
169 > /**
170 > * Additional information about the error. The value of this member is defined by the sender (e.g. detailed error information, nested errors etc.).
171 > */
172 > data?: unknown;
173 > }
174 >
175 > /**
176 > * A uniquely identifying ID for a request in JSON-RPC.
177 > *
178 > * @category Common Types
179 > */
180 > export type RequestId = string | number;
181 >
182 > /**
183 > * A request that expects a response.
184 > *
185 > * @category JSON-RPC
186 > */
187 > export interface JSONRPCRequest extends Request {
188 > jsonrpc: typeof JSONRPC_VERSION;
189 > id: RequestId;
190 > }
191 >
192 > /**
193 > * A notification which does not expect a response.
194 > *
195 > * @category JSON-RPC
196 > */
197 > export interface JSONRPCNotification extends Notification {
198 > jsonrpc: typeof JSONRPC_VERSION;
199 > }
200 >
201 > /**
202 > * A successful (non-error) response to a request.
203 > *
204 > * @category JSON-RPC
205 > */
206 > export interface JSONRPCResultResponse {
207 > jsonrpc: typeof JSONRPC_VERSION;
208 > id: RequestId;
209 > result: Result;
210 > }
211 >
212 > /**
213 > * A response to a request that indicates an error occurred.
214 > *
215 > * @category JSON-RPC
216 > */
217 > export interface JSONRPCErrorResponse {
218 > jsonrpc: typeof JSONRPC_VERSION;
219 > id?: RequestId;
220 > error: Error;
221 > }
222 >
223 > /**
224 > * A response to a request, containing either the result or error.
225 > *
226 > * @category JSON-RPC
227 > */
228 > export type JSONRPCResponse = JSONRPCResultResponse | JSONRPCErrorResponse;
229 >
230 > // Standard JSON-RPC error codes
231 > export const PARSE_ERROR = -32700;
232 > export const INVALID_REQUEST = -32600;
233 > export const METHOD_NOT_FOUND = -32601;
234 > export const INVALID_PARAMS = -32602;
235 > export const INTERNAL_ERROR = -32603;
236 >
237 > /**
238 > * A JSON-RPC error indicating that invalid JSON was received by the server. This error is returned when the server cannot parse the JSON text of a message.
239 > *
240 > * @see {@link https://www.jsonrpc.org/specification#error_object | JSON-RPC 2.0 Error Object}
241 > *
242 > * @example Invalid JSON
243 > * {@includeCode ./examples/ParseError/invalid-json.json}
244 > *
245 > * @category Errors
246 > */
247 > export interface ParseError extends Error {
248 > code: typeof PARSE_ERROR;
249 > }
250 >
251 > /**
252 > * A JSON-RPC error indicating that the request is not a valid request object. This error is returned when the message structure does not conform to the JSON-RPC 2.0 specification requirements for a request (e.g., missing required fields like `jsonrpc` or `method`, or using invalid types for these fields).
253 > *
254 > * @see {@link https://www.jsonrpc.org/specification#error_object | JSON-RPC 2.0 Error Object}
255 > *
256 > * @category Errors
257 > */
258 > export interface InvalidRequestError extends Error {
259 > code: typeof INVALID_REQUEST;
260 > }
261 >
262 > /**
263 > * A JSON-RPC error indicating that the requested method does not exist or is not available.
264 > *
265 > * In MCP, this error is returned when a request is made for a method that requires a capability that has not been declared. This can occur in either direction:
266 > *
267 > * - A server returning this error when the client requests a capability it doesn't support (e.g., requesting completions when the `completions` capability was not advertised)
268 > * - A client returning this error when the server requests a capability it doesn't support (e.g., requesting roots when the client did not declare the `roots` capability)
269 > *
270 > * @see {@link https://www.jsonrpc.org/specification#error_object | JSON-RPC 2.0 Error Object}
271 > *
272 > * @example Roots not supported
273 > * {@includeCode ./examples/MethodNotFoundError/roots-not-supported.json}
274 > *
275 > * @category Errors
276 > */
277 > export interface MethodNotFoundError extends Error {
278 > code: typeof METHOD_NOT_FOUND;
279 > }
280 >
281 > /**
282 > * A JSON-RPC error indicating that the method parameters are invalid or malformed.
283 > *
284 > * In MCP, this error is returned in various contexts when request parameters fail validation:
285 > *
286 > * - **Tools**: Unknown tool name or invalid tool arguments
287 > * - **Prompts**: Unknown prompt name or missing required arguments
288 > * - **Pagination**: Invalid or expired cursor values
289 > * - **Logging**: Invalid log level
290 > * - **Tasks**: Invalid or nonexistent task ID, invalid cursor, or attempting to cancel a task already in a terminal status
291 > * - **Elicitation**: Server requests an elicitation mode not declared in client capabilities
292 > * - **Sampling**: Missing tool result or tool results mixed with other content
293 > *
294 > * @see {@link https://www.jsonrpc.org/specification#error_object | JSON-RPC 2.0 Error Object}
295 > *
296 > * @example Unknown tool
297 > * {@includeCode ./examples/InvalidParamsError/unknown-tool.json}
298 > *
299 > * @example Invalid tool arguments
300 > * {@includeCode ./examples/InvalidParamsError/invalid-tool-arguments.json}
301 > *
302 > * @example Unknown prompt
303 > * {@includeCode ./examples/InvalidParamsError/unknown-prompt.json}
304 > *
305 > * @example Invalid cursor
306 > * {@includeCode ./examples/InvalidParamsError/invalid-cursor.json}
307 > *
308 > * @category Errors
309 > */
310 > export interface InvalidParamsError extends Error {
311 > code: typeof INVALID_PARAMS;
312 > }
313 >
314 > /**
315 > * A JSON-RPC error indicating that an internal error occurred on the receiver. This error is returned when the receiver encounters an unexpected condition that prevents it from fulfilling the request.
316 > *
317 > * @see {@link https://www.jsonrpc.org/specification#error_object | JSON-RPC 2.0 Error Object}
318 > *
319 > * @example Unexpected error
320 > * {@includeCode ./examples/InternalError/unexpected-error.json}
321 > *
322 > * @category Errors
323 > */
324 > export interface InternalError extends Error {
325 > code: typeof INTERNAL_ERROR;
326 > }
327 >
328 > // Implementation-specific JSON-RPC error codes [-32000, -32099]
329 > /** @internal */
330 > export const URL_ELICITATION_REQUIRED = -32042;
331 >
332 > /**
333 > * An error response that indicates that the server requires the client to provide additional information via an elicitation request.
334 > *
335 > * @example Authorization required
336 > * {@includeCode ./examples/URLElicitationRequiredError/authorization-required.json}
337 > *
338 > * @internal
339 > */
340 > export interface URLElicitationRequiredError extends Omit<
341 > JSONRPCErrorResponse,
342 > "error"
343 > > {
344 > error: Error & {
345 > code: typeof URL_ELICITATION_REQUIRED;
346 > data: {
347 > elicitations: ElicitRequestURLParams[];
348 > [key: string]: unknown;
349 > };
350 > };
351 > }
352 >
353 > /* Empty result */
354 > /**
355 > * A result that indicates success but carries no data.
356 > *
357 > * @category Common Types
358 > */
359 > export type EmptyResult = Result;
360 >
361 > /* Cancellation */
362 > /**
363 > * Parameters for a `notifications/cancelled` notification.
364 > *
365 > * @example User-requested cancellation
366 > * {@includeCode ./examples/CancelledNotificationParams/user-requested-cancellation.json}
367 > *
368 > * @category `notifications/cancelled`
369 > */
370 > export interface CancelledNotificationParams extends NotificationParams {
371 > /**
372 > * The ID of the request to cancel.
373 > *
374 > * This MUST correspond to the ID of a request previously issued in the same direction.
375 > * This MUST be provided for cancelling non-task requests.
376 > * This MUST NOT be used for cancelling tasks (use the {@link CancelTaskRequest | tasks/cancel} request instead).
377 > */
378 > requestId?: RequestId;
379 >
380 > /**
381 > * An optional string describing the reason for the cancellation. This MAY be logged or presented to the user.
382 > */
383 > reason?: string;
384 > }
385 >
386 > /**
387 > * This notification can be sent by either side to indicate that it is cancelling a previously-issued request.
388 > *
389 > * The request SHOULD still be in-flight, but due to communication latency, it is always possible that this notification MAY arrive after the request has already finished.
390 > *
391 > * This notification indicates that the result will be unused, so any associated processing SHOULD cease.
392 > *
393 > * A client MUST NOT attempt to cancel its `initialize` request.
394 > *
395 > * For task cancellation, use the {@link CancelTaskRequest | tasks/cancel} request instead of this notification.
396 > *
397 > * @example User-requested cancellation
398 > * {@includeCode ./examples/CancelledNotification/user-requested-cancellation.json}
399 > *
400 > * @category `notifications/cancelled`
401 > */
402 > export interface CancelledNotification extends JSONRPCNotification {
403 > method: "notifications/cancelled";
404 > params: CancelledNotificationParams;
405 > }
406 >
407 > /* Initialization */
408 > /**
409 > * Parameters for an `initialize` request.
410 > *
411 > * @example Full client capabilities
412 > * {@includeCode ./examples/InitializeRequestParams/full-client-capabilities.json}
413 > *
414 > * @category `initialize`
415 > */
416 > export interface InitializeRequestParams extends RequestParams {
417 > /**
418 > * The latest version of the Model Context Protocol that the client supports. The client MAY decide to support older versions as well.
419 > */
420 > protocolVersion: string;
421 > capabilities: ClientCapabilities;
422 > clientInfo: Implementation;
423 > }
424 >
425 > /**
426 > * This request is sent from the client to the server when it first connects, asking it to begin initialization.
427 > *
428 > * @example Initialize request
429 > * {@includeCode ./examples/InitializeRequest/initialize-request.json}
430 > *
431 > * @category `initialize`
432 > */
433 > export interface InitializeRequest extends JSONRPCRequest {
434 > method: "initialize";
435 > params: InitializeRequestParams;
436 > }
437 >
438 > /**
439 > * The result returned by the server for an {@link InitializeRequest | initialize} request.
440 > *
441 > * @example Full server capabilities
442 > * {@includeCode ./examples/InitializeResult/full-server-capabilities.json}
443 > *
444 > * @category `initialize`
445 > */
446 > export interface InitializeResult extends Result {
447 > /**
448 > * The version of the Model Context Protocol that the server wants to use. This may not match the version that the client requested. If the client cannot support this version, it MUST disconnect.
449 > */
450 > protocolVersion: string;
451 > capabilities: ServerCapabilities;
452 > serverInfo: Implementation;
453 >
454 > /**
455 > * Instructions describing how to use the server and its features.
456 > *
457 > * This can be used by clients to improve the LLM's understanding of available tools, resources, etc. It can be thought of like a "hint" to the model. For example, this information MAY be added to the system prompt.
458 > */
459 > instructions?: string;
460 > }
461 >
462 > /**
463 > * A successful response from the server for a {@link InitializeRequest | initialize} request.
464 > *
465 > * @example Initialize result response
466 > * {@includeCode ./examples/InitializeResultResponse/initialize-result-response.json}
467 > *
468 > * @category `initialize`
469 > */
470 > export interface InitializeResultResponse extends JSONRPCResultResponse {
471 > result: InitializeResult;
472 > }
473 >
474 > /**
475 > * This notification is sent from the client to the server after initialization has finished.
476 > *
477 > * @example Initialized notification
478 > * {@includeCode ./examples/InitializedNotification/initialized-notification.json}
479 > *
480 > * @category `notifications/initialized`
481 > */
482 > export interface InitializedNotification extends JSONRPCNotification {
483 > method: "notifications/initialized";
484 > params?: NotificationParams;
485 > }
486 >
487 > /**
488 > * Capabilities a client may support. Known capabilities are defined here, in this schema, but this is not a closed set: any client can define its own, additional capabilities.
489 > *
490 > * @category `initialize`
491 > */
492 > export interface ClientCapabilities {
493 > /**
494 > * Experimental, non-standard capabilities that the client supports.
495 > */
496 > experimental?: { [key: string]: object };
497 > /**
498 > * Present if the client supports listing roots.
499 > *
500 > * @example Roots - minimum baseline support
501 > * {@includeCode ./examples/ClientCapabilities/roots-minimum-baseline-support.json}
502 > *
503 > * @example Roots - list changed notifications
504 > * {@includeCode ./examples/ClientCapabilities/roots-list-changed-notifications.json}
505 > */
506 > roots?: {
507 > /**
508 > * Whether the client supports notifications for changes to the roots list.
509 > */
510 > listChanged?: boolean;
511 > };
512 > /**
513 > * Present if the client supports sampling from an LLM.
514 > *
515 > * @example Sampling - minimum baseline support
516 > * {@includeCode ./examples/ClientCapabilities/sampling-minimum-baseline-support.json}
517 > *
518 > * @example Sampling - tool use support
519 > * {@includeCode ./examples/ClientCapabilities/sampling-tool-use-support.json}
520 > *
521 > * @example Sampling - context inclusion support (soft-deprecated)
522 > * {@includeCode ./examples/ClientCapabilities/sampling-context-inclusion-support-soft-deprecated.json}
523 > */
524 > sampling?: {
525 > /**
526 > * Whether the client supports context inclusion via `includeContext` parameter.
527 > * If not declared, servers SHOULD only use `includeContext: "none"` (or omit it).
528 > */
529 > context?: object;
530 > /**
531 > * Whether the client supports tool use via `tools` and `toolChoice` parameters.
532 > */
533 > tools?: object;
534 > };
535 > /**
536 > * Present if the client supports elicitation from the server.
537 > *
538 > * @example Elicitation - form and URL mode support
539 > * {@includeCode ./examples/ClientCapabilities/elicitation-form-and-url-mode-support.json}
540 > *
541 > * @example Elicitation - form mode only (implicit)
542 > * {@includeCode ./examples/ClientCapabilities/elicitation-form-only-implicit.json}
543 > */
544 > elicitation?: { form?: object; url?: object };
545 >
546 > /**
547 > * Present if the client supports task-augmented requests.
548 > */
549 > tasks?: {
550 > /**
551 > * Whether this client supports {@link ListTasksRequest | tasks/list}.
552 > */
553 > list?: object;
554 > /**
555 > * Whether this client supports {@link CancelTaskRequest | tasks/cancel}.
556 > */
557 > cancel?: object;
558 > /**
559 > * Specifies which request types can be augmented with tasks.
560 > */
561 > requests?: {
562 > /**
563 > * Task support for sampling-related requests.
564 > */
565 > sampling?: {
566 > /**
567 > * Whether the client supports task-augmented `sampling/createMessage` requests.
568 > */
569 > createMessage?: object;
570 > };
571 > /**
572 > * Task support for elicitation-related requests.
573 > */
574 > elicitation?: {
575 > /**
576 > * Whether the client supports task-augmented {@link ElicitRequest | elicitation/create} requests.
577 > */
578 > create?: object;
579 > };
580 > };
581 > };
582 > /**
583 > * Optional MCP extensions that the client supports. Keys are extension identifiers
584 > * (e.g., "io.modelcontextprotocol/oauth-client-credentials"), and values are
585 > * per-extension settings objects. An empty object indicates support with no settings.
586 > *
587 > * @example Extensions - UI extension with MIME type support
588 > * {@includeCode ./examples/ClientCapabilities/extensions-ui-mime-types.json}
589 > */
590 > extensions?: { [key: string]: object };
591 > }
592 >
593 > /**
594 > * Capabilities that a server may support. Known capabilities are defined here, in this schema, but this is not a closed set: any server can define its own, additional capabilities.
595 > *
596 > * @category `initialize`
597 > */
598 > export interface ServerCapabilities {
599 > /**
600 > * Experimental, non-standard capabilities that the server supports.
601 > */
602 > experimental?: { [key: string]: object };
603 > /**
604 > * Present if the server supports sending log messages to the client.
605 > *
606 > * @example Logging - minimum baseline support
607 > * {@includeCode ./examples/ServerCapabilities/logging-minimum-baseline-support.json}
608 > */
609 > logging?: object;
610 > /**
611 > * Present if the server supports argument autocompletion suggestions.
612 > *
613 > * @example Completions - minimum baseline support
614 > * {@includeCode ./examples/ServerCapabilities/completions-minimum-baseline-support.json}
615 > */
616 > completions?: object;
617 > /**
618 > * Present if the server offers any prompt templates.
619 > *
620 > * @example Prompts - minimum baseline support
621 > * {@includeCode ./examples/ServerCapabilities/prompts-minimum-baseline-support.json}
622 > *
623 > * @example Prompts - list changed notifications
624 > * {@includeCode ./examples/ServerCapabilities/prompts-list-changed-notifications.json}
625 > */
626 > prompts?: {
627 > /**
628 > * Whether this server supports notifications for changes to the prompt list.
629 > */
630 > listChanged?: boolean;
631 > };
632 > /**
633 > * Present if the server offers any resources to read.
634 > *
635 > * @example Resources - minimum baseline support
636 > * {@includeCode ./examples/ServerCapabilities/resources-minimum-baseline-support.json}
637 > *
638 > * @example Resources - subscription to individual resource updates (only)
639 > * {@includeCode ./examples/ServerCapabilities/resources-subscription-to-individual-resource-updates-only.json}
640 > *
641 > * @example Resources - list changed notifications (only)
642 > * {@includeCode ./examples/ServerCapabilities/resources-list-changed-notifications-only.json}
643 > *
644 > * @example Resources - all notifications
645 > * {@includeCode ./examples/ServerCapabilities/resources-all-notifications.json}
646 > */
647 > resources?: {
648 > /**
649 > * Whether this server supports subscribing to resource updates.
650 > */
651 > subscribe?: boolean;
652 > /**
653 > * Whether this server supports notifications for changes to the resource list.
654 > */
655 > listChanged?: boolean;
656 > };
657 > /**
658 > * Present if the server offers any tools to call.
659 > *
660 > * @example Tools - minimum baseline support
661 > * {@includeCode ./examples/ServerCapabilities/tools-minimum-baseline-support.json}
662 > *
663 > * @example Tools - list changed notifications
664 > * {@includeCode ./examples/ServerCapabilities/tools-list-changed-notifications.json}
665 > */
666 > tools?: {
667 > /**
668 > * Whether this server supports notifications for changes to the tool list.
669 > */
670 > listChanged?: boolean;
671 > };
672 > /**
673 > * Present if the server supports task-augmented requests.
674 > */
675 > tasks?: {
676 > /**
677 > * Whether this server supports {@link ListTasksRequest | tasks/list}.
678 > */
679 > list?: object;
680 > /**
681 > * Whether this server supports {@link CancelTaskRequest | tasks/cancel}.
682 > */
683 > cancel?: object;
684 > /**
685 > * Specifies which request types can be augmented with tasks.
686 > */
687 > requests?: {
688 > /**
689 > * Task support for tool-related requests.
690 > */
691 > tools?: {
692 > /**
693 > * Whether the server supports task-augmented {@link CallToolRequest | tools/call} requests.
694 > */
695 > call?: object;
696 > };
697 > };
698 > };
699 > /**
700 > * Optional MCP extensions that the server supports. Keys are extension identifiers
701 > * (e.g., "io.modelcontextprotocol/apps"), and values are per-extension settings
702 > * objects. An empty object indicates support with no settings.
703 > *
704 > * @example Extensions - UI extension support
705 > * {@includeCode ./examples/ServerCapabilities/extensions-ui.json}
706 > */
707 > extensions?: { [key: string]: object };
708 > }
709 >
710 > /**
711 > * An optionally-sized icon that can be displayed in a user interface.
712 > *
713 > * @category Common Types
714 > */
715 > export interface Icon {
716 > /**
717 > * A standard URI pointing to an icon resource. May be an HTTP/HTTPS URL or a
718 > * `data:` URI with Base64-encoded image data.
719 > *
720 > * Consumers SHOULD take steps to ensure URLs serving icons are from the
721 > * same domain as the client/server or a trusted domain.
722 > *
723 > * Consumers SHOULD take appropriate precautions when consuming SVGs as they can contain
724 > * executable JavaScript.
725 > *
726 > * @format uri
727 > */
728 > src: string;
729 >
730 > /**
731 > * Optional MIME type override if the source MIME type is missing or generic.
732 > * For example: `"image/png"`, `"image/jpeg"`, or `"image/svg+xml"`.
733 > */
734 > mimeType?: string;
735 >
736 > /**
737 > * Optional array of strings that specify sizes at which the icon can be used.
738 > * Each string should be in WxH format (e.g., `"48x48"`, `"96x96"`) or `"any"` for scalable formats like SVG.
739 > *
740 > * If not provided, the client should assume that the icon can be used at any size.
741 > */
742 > sizes?: string[];
743 >
744 > /**
745 > * Optional specifier for the theme this icon is designed for. `"light"` indicates
746 > * the icon is designed to be used with a light background, and `"dark"` indicates
747 > * the icon is designed to be used with a dark background.
748 > *
749 > * If not provided, the client should assume the icon can be used with any theme.
750 > */
751 > theme?: "light" | "dark";
752 > }
753 >
754 > /**
755 > * Base interface to add `icons` property.
756 > *
757 > * @internal
758 > */
759 > export interface Icons {
760 > /**
761 > * Optional set of sized icons that the client can display in a user interface.
762 > *
763 > * Clients that support rendering icons MUST support at least the following MIME types:
764 > * - `image/png` - PNG images (safe, universal compatibility)
765 > * - `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility)
766 > *
767 > * Clients that support rendering icons SHOULD also support:
768 > * - `image/svg+xml` - SVG images (scalable but requires security precautions)
769 > * - `image/webp` - WebP images (modern, efficient format)
770 > */
771 > icons?: Icon[];
772 > }
773 >
774 > /**
775 > * Base interface for metadata with name (identifier) and title (display name) properties.
776 > *
777 > * @internal
778 > */
779 > export interface BaseMetadata {
780 > /**
781 > * Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't present).
782 > */
783 > name: string;
784 >
785 > /**
786 > * Intended for UI and end-user contexts - optimized to be human-readable and easily understood,
787 > * even by those unfamiliar with domain-specific terminology.
788 > *
789 > * If not provided, the name should be used for display (except for {@link Tool},
790 > * where `annotations.title` should be given precedence over using `name`,
791 > * if present).
792 > */
793 > title?: string;
794 > }
795 >
796 > /**
797 > * Describes the MCP implementation.
798 > *
799 > * @category `initialize`
800 > */
801 > export interface Implementation extends BaseMetadata, Icons {
802 > /**
803 > * The version of this implementation.
804 > */
805 > version: string;
806 >
807 > /**
808 > * An optional human-readable description of what this implementation does.
809 > *
810 > * This can be used by clients or servers to provide context about their purpose
811 > * and capabilities. For example, a server might describe the types of resources
812 > * or tools it provides, while a client might describe its intended use case.
813 > */
814 > description?: string;
815 >
816 > /**
817 > * An optional URL of the website for this implementation.
818 > *
819 > * @format uri
820 > */
821 > websiteUrl?: string;
822 > }
823 >
824 > /* Ping */
825 > /**
826 > * A ping, issued by either the server or the client, to check that the other party is still alive. The receiver must promptly respond, or else may be disconnected.
827 > *
828 > * @example Ping request
829 > * {@includeCode ./examples/PingRequest/ping-request.json}
830 > *
831 > * @category `ping`
832 > */
833 > export interface PingRequest extends JSONRPCRequest {
834 > method: "ping";
835 > params?: RequestParams;
836 > }
837 >
838 > /**
839 > * A successful response for a {@link PingRequest | ping} request.
840 > *
841 > * @example Ping result response
842 > * {@includeCode ./examples/PingResultResponse/ping-result-response.json}
843 > *
844 > * @category `ping`
845 > */
846 > export interface PingResultResponse extends JSONRPCResultResponse {
847 > result: EmptyResult;
848 > }
849 >
850 > /* Progress notifications */
851 >
852 > /**
853 > * Parameters for a {@link ProgressNotification | notifications/progress} notification.
854 > *
855 > * @example Progress message
856 > * {@includeCode ./examples/ProgressNotificationParams/progress-message.json}
857 > *
858 > * @category `notifications/progress`
859 > */
860 > export interface ProgressNotificationParams extends NotificationParams {
861 > /**
862 > * The progress token which was given in the initial request, used to associate this notification with the request that is proceeding.
863 > */
864 > progressToken: ProgressToken;
865 > /**
866 > * The progress thus far. This should increase every time progress is made, even if the total is unknown.
867 > *
868 > * @TJS-type number
869 > */
870 > progress: number;
871 > /**
872 > * Total number of items to process (or total progress required), if known.
873 > *
874 > * @TJS-type number
875 > */
876 > total?: number;
877 > /**
878 > * An optional message describing the current progress.
879 > */
880 > message?: string;
881 > }
882 >
883 > /**
884 > * An out-of-band notification used to inform the receiver of a progress update for a long-running request.
885 > *
886 > * @example Progress message
887 > * {@includeCode ./examples/ProgressNotification/progress-message.json}
888 > *
889 > * @category `notifications/progress`
890 > */
891 > export interface ProgressNotification extends JSONRPCNotification {
892 > method: "notifications/progress";
893 > params: ProgressNotificationParams;
894 > }
895 >
896 > /* Pagination */
897 > /**
898 > * Common params for paginated requests.
899 > *
900 > * @example List request with cursor
901 > * {@includeCode ./examples/PaginatedRequestParams/list-with-cursor.json}
902 > *
903 > * @category Common Types
904 > */
905 > export interface PaginatedRequestParams extends RequestParams {
906 > /**
907 > * An opaque token representing the current pagination position.
908 > * If provided, the server should return results starting after this cursor.
909 > */
910 > cursor?: Cursor;
911 > }
912 >
913 > /** @internal */
914 > export interface PaginatedRequest extends JSONRPCRequest {
915 > params?: PaginatedRequestParams;
916 > }
917 >
918 > /** @internal */
919 > export interface PaginatedResult extends Result {
920 > /**
921 > * An opaque token representing the pagination position after the last returned result.
922 > * If present, there may be more results available.
923 > */
924 > nextCursor?: Cursor;
925 > }
926 >
927 > /* Resources */
928 > /**
929 > * Sent from the client to request a list of resources the server has.
930 > *
931 > * @example List resources request
932 > * {@includeCode ./examples/ListResourcesRequest/list-resources-request.json}
933 > *
934 > * @category `resources/list`
935 > */
936 > export interface ListResourcesRequest extends PaginatedRequest {
937 > method: "resources/list";
938 > }
939 >
940 > /**
941 > * The result returned by the server for a {@link ListResourcesRequest | resources/list} request.
942 > *
943 > * @example Resources list with cursor
944 > * {@includeCode ./examples/ListResourcesResult/resources-list-with-cursor.json}
945 > *
946 > * @category `resources/list`
947 > */
948 > export interface ListResourcesResult extends PaginatedResult {
949 > resources: Resource[];
950 > }
951 >
952 > /**
953 > * A successful response from the server for a {@link ListResourcesRequest | resources/list} request.
954 > *
955 > * @example List resources result response
956 > * {@includeCode ./examples/ListResourcesResultResponse/list-resources-result-response.json}
957 > *
958 > * @category `resources/list`
959 > */
960 > export interface ListResourcesResultResponse extends JSONRPCResultResponse {
961 > result: ListResourcesResult;
962 > }
963 >
964 > /**
965 > * Sent from the client to request a list of resource templates the server has.
966 > *
967 > * @example List resource templates request
968 > * {@includeCode ./examples/ListResourceTemplatesRequest/list-resource-templates-request.json}
969 > *
970 > * @category `resources/templates/list`
971 > */
972 > export interface ListResourceTemplatesRequest extends PaginatedRequest {
973 > method: "resources/templates/list";
974 > }
975 >
976 > /**
977 > * The result returned by the server for a {@link ListResourceTemplatesRequest | resources/templates/list} request.
978 > *
979 > * @example Resource templates list
980 > * {@includeCode ./examples/ListResourceTemplatesResult/resource-templates-list.json}
981 > *
982 > * @category `resources/templates/list`
983 > */
984 > export interface ListResourceTemplatesResult extends PaginatedResult {
985 > resourceTemplates: ResourceTemplate[];
986 > }
987 >
988 > /**
989 > * A successful response from the server for a {@link ListResourceTemplatesRequest | resources/templates/list} request.
990 > *
991 > * @example List resource templates result response
992 > * {@includeCode ./examples/ListResourceTemplatesResultResponse/list-resource-templates-result-response.json}
993 > *
994 > * @category `resources/templates/list`
995 > */
996 > export interface ListResourceTemplatesResultResponse extends JSONRPCResultResponse {
997 > result: ListResourceTemplatesResult;
998 > }
999 >
1000 > /**
1001 > * Common params for resource-related requests.
1002 > *
1003 > * @internal
1004 > */
1005 > export interface ResourceRequestParams extends RequestParams {
1006 > /**
1007 > * The URI of the resource. The URI can use any protocol; it is up to the server how to interpret it.
1008 > *
1009 > * @format uri
1010 > */
1011 > uri: string;
1012 > }
1013 >
1014 > /**
1015 > * Parameters for a `resources/read` request.
1016 > *
1017 > * @category `resources/read`
1018 > */
1019 > export interface ReadResourceRequestParams extends ResourceRequestParams { }
1020 >
1021 > /**
1022 > * Sent from the client to the server, to read a specific resource URI.
1023 > *
1024 > * @example Read resource request
1025 > * {@includeCode ./examples/ReadResourceRequest/read-resource-request.json}
1026 > *
1027 > * @category `resources/read`
1028 > */
1029 > export interface ReadResourceRequest extends JSONRPCRequest {
1030 > method: "resources/read";
1031 > params: ReadResourceRequestParams;
1032 > }
1033 >
1034 > /**
1035 > * The result returned by the server for a {@link ReadResourceRequest | resources/read} request.
1036 > *
1037 > * @example File resource contents
1038 > * {@includeCode ./examples/ReadResourceResult/file-resource-contents.json}
1039 > *
1040 > * @category `resources/read`
1041 > */
1042 > export interface ReadResourceResult extends Result {
1043 > contents: (TextResourceContents | BlobResourceContents)[];
1044 > }
1045 >
1046 > /**
1047 > * A successful response from the server for a {@link ReadResourceRequest | resources/read} request.
1048 > *
1049 > * @example Read resource result response
1050 > * {@includeCode ./examples/ReadResourceResultResponse/read-resource-result-response.json}
1051 > *
1052 > * @category `resources/read`
1053 > */
1054 > export interface ReadResourceResultResponse extends JSONRPCResultResponse {
1055 > result: ReadResourceResult;
1056 > }
1057 >
1058 > /**
1059 > * An optional notification from the server to the client, informing it that the list of resources it can read from has changed. This may be issued by servers without any previous subscription from the client.
1060 > *
1061 > * @example Resources list changed
1062 > * {@includeCode ./examples/ResourceListChangedNotification/resources-list-changed.json}
1063 > *
1064 > * @category `notifications/resources/list_changed`
1065 > */
1066 > export interface ResourceListChangedNotification extends JSONRPCNotification {
1067 > method: "notifications/resources/list_changed";
1068 > params?: NotificationParams;
1069 > }
1070 >
1071 > /**
1072 > * Parameters for a `resources/subscribe` request.
1073 > *
1074 > * @example Subscribe to file resource
1075 > * {@includeCode ./examples/SubscribeRequestParams/subscribe-to-file-resource.json}
1076 > *
1077 > * @category `resources/subscribe`
1078 > */
1079 > export interface SubscribeRequestParams extends ResourceRequestParams { }
1080 >
1081 > /**
1082 > * Sent from the client to request {@link ResourceUpdatedNotification | resources/updated} notifications from the server whenever a particular resource changes.
1083 > *
1084 > * @example Subscribe request
1085 > * {@includeCode ./examples/SubscribeRequest/subscribe-request.json}
1086 > *
1087 > * @category `resources/subscribe`
1088 > */
1089 > export interface SubscribeRequest extends JSONRPCRequest {
1090 > method: "resources/subscribe";
1091 > params: SubscribeRequestParams;
1092 > }
1093 >
1094 > /**
1095 > * A successful response from the server for a {@link SubscribeRequest | resources/subscribe} request.
1096 > *
1097 > * @example Subscribe result response
1098 > * {@includeCode ./examples/SubscribeResultResponse/subscribe-result-response.json}
1099 > *
1100 > * @category `resources/subscribe`
1101 > */
1102 > export interface SubscribeResultResponse extends JSONRPCResultResponse {
1103 > result: EmptyResult;
1104 > }
1105 >
1106 > /**
1107 > * Parameters for a `resources/unsubscribe` request.
1108 > *
1109 > * @category `resources/unsubscribe`
1110 > */
1111 > export interface UnsubscribeRequestParams extends ResourceRequestParams { }
1112 >
1113 > /**
1114 > * Sent from the client to request cancellation of {@link ResourceUpdatedNotification | resources/updated} notifications from the server. This should follow a previous {@link SubscribeRequest | resources/subscribe} request.
1115 > *
1116 > * @example Unsubscribe request
1117 > * {@includeCode ./examples/UnsubscribeRequest/unsubscribe-request.json}
1118 > *
1119 > * @category `resources/unsubscribe`
1120 > */
1121 > export interface UnsubscribeRequest extends JSONRPCRequest {
1122 > method: "resources/unsubscribe";
1123 > params: UnsubscribeRequestParams;
1124 > }
1125 >
1126 > /**
1127 > * A successful response from the server for a {@link UnsubscribeRequest | resources/unsubscribe} request.
1128 > *
1129 > * @example Unsubscribe result response
1130 > * {@includeCode ./examples/UnsubscribeResultResponse/unsubscribe-result-response.json}
1131 > *
1132 > * @category `resources/unsubscribe`
1133 > */
1134 > export interface UnsubscribeResultResponse extends JSONRPCResultResponse {
1135 > result: EmptyResult;
1136 > }
1137 >
1138 > /**
1139 > * Parameters for a `notifications/resources/updated` notification.
1140 > *
1141 > * @example File resource updated
1142 > * {@includeCode ./examples/ResourceUpdatedNotificationParams/file-resource-updated.json}
1143 > *
1144 > * @category `notifications/resources/updated`
1145 > */
1146 > export interface ResourceUpdatedNotificationParams extends NotificationParams {
1147 > /**
1148 > * The URI of the resource that has been updated. This might be a sub-resource of the one that the client actually subscribed to.
1149 > *
1150 > * @format uri
1151 > */
1152 > uri: string;
1153 > }
1154 >
1155 > /**
1156 > * A notification from the server to the client, informing it that a resource has changed and may need to be read again. This should only be sent if the client previously sent a {@link SubscribeRequest | resources/subscribe} request.
1157 > *
1158 > * @example File resource updated notification
1159 > * {@includeCode ./examples/ResourceUpdatedNotification/file-resource-updated-notification.json}
1160 > *
1161 > * @category `notifications/resources/updated`
1162 > */
1163 > export interface ResourceUpdatedNotification extends JSONRPCNotification {
1164 > method: "notifications/resources/updated";
1165 > params: ResourceUpdatedNotificationParams;
1166 > }
1167 >
1168 > /**
1169 > * A known resource that the server is capable of reading.
1170 > *
1171 > * @example File resource with annotations
1172 > * {@includeCode ./examples/Resource/file-resource-with-annotations.json}
1173 > *
1174 > * @category `resources/list`
1175 > */
1176 > export interface Resource extends BaseMetadata, Icons {
1177 > /**
1178 > * The URI of this resource.
1179 > *
1180 > * @format uri
1181 > */
1182 > uri: string;
1183 >
1184 > /**
1185 > * A description of what this resource represents.
1186 > *
1187 > * This can be used by clients to improve the LLM's understanding of available resources. It can be thought of like a "hint" to the model.
1188 > */
1189 > description?: string;
1190 >
1191 > /**
1192 > * The MIME type of this resource, if known.
1193 > */
1194 > mimeType?: string;
1195 >
1196 > /**
1197 > * Optional annotations for the client.
1198 > */
1199 > annotations?: Annotations;
1200 >
1201 > /**
1202 > * The size of the raw resource content, in bytes (i.e., before base64 encoding or any tokenization), if known.
1203 > *
1204 > * This can be used by Hosts to display file sizes and estimate context window usage.
1205 > */
1206 > size?: number;
1207 >
1208 > _meta?: MetaObject;
1209 > }
1210 >
1211 > /**
1212 > * A template description for resources available on the server.
1213 > *
1214 > * @category `resources/templates/list`
1215 > */
1216 > export interface ResourceTemplate extends BaseMetadata, Icons {
1217 > /**
1218 > * A URI template (according to RFC 6570) that can be used to construct resource URIs.
1219 > *
1220 > * @format uri-template
1221 > */
1222 > uriTemplate: string;
1223 >
1224 > /**
1225 > * A description of what this template is for.
1226 > *
1227 > * This can be used by clients to improve the LLM's understanding of available resources. It can be thought of like a "hint" to the model.
1228 > */
1229 > description?: string;
1230 >
1231 > /**
1232 > * The MIME type for all resources that match this template. This should only be included if all resources matching this template have the same type.
1233 > */
1234 > mimeType?: string;
1235 >
1236 > /**
1237 > * Optional annotations for the client.
1238 > */
1239 > annotations?: Annotations;
1240 >
1241 > _meta?: MetaObject;
1242 > }
1243 >
1244 > /**
1245 > * The contents of a specific resource or sub-resource.
1246 > *
1247 > * @internal
1248 > */
1249 > export interface ResourceContents {
1250 > /**
1251 > * The URI of this resource.
1252 > *
1253 > * @format uri
1254 > */
1255 > uri: string;
1256 > /**
1257 > * The MIME type of this resource, if known.
1258 > */
1259 > mimeType?: string;
1260 >
1261 > _meta?: MetaObject;
1262 > }
1263 >
1264 > /**
1265 > * @example Text file contents
1266 > * {@includeCode ./examples/TextResourceContents/text-file-contents.json}
1267 > *
1268 > * @category Content
1269 > */
1270 > export interface TextResourceContents extends ResourceContents {
1271 > /**
1272 > * The text of the item. This must only be set if the item can actually be represented as text (not binary data).
1273 > */
1274 > text: string;
1275 > }
1276 >
1277 > /**
1278 > * @example Image file contents
1279 > * {@includeCode ./examples/BlobResourceContents/image-file-contents.json}
1280 > *
1281 > * @category Content
1282 > */
1283 > export interface BlobResourceContents extends ResourceContents {
1284 > /**
1285 > * A base64-encoded string representing the binary data of the item.
1286 > *
1287 > * @format byte
1288 > */
1289 > blob: string;
1290 > }
1291 >
1292 > /* Prompts */
1293 > /**
1294 > * Sent from the client to request a list of prompts and prompt templates the server has.
1295 > *
1296 > * @example List prompts request
1297 > * {@includeCode ./examples/ListPromptsRequest/list-prompts-request.json}
1298 > *
1299 > * @category `prompts/list`
1300 > */
1301 > export interface ListPromptsRequest extends PaginatedRequest {
1302 > method: "prompts/list";
1303 > }
1304 >
1305 > /**
1306 > * The result returned by the server for a {@link ListPromptsRequest | prompts/list} request.
1307 > *
1308 > * @example Prompts list with cursor
1309 > * {@includeCode ./examples/ListPromptsResult/prompts-list-with-cursor.json}
1310 > *
1311 > * @category `prompts/list`
1312 > */
1313 > export interface ListPromptsResult extends PaginatedResult {
1314 > prompts: Prompt[];
1315 > }
1316 >
1317 > /**
1318 > * A successful response from the server for a {@link ListPromptsRequest | prompts/list} request.
1319 > *
1320 > * @example List prompts result response
1321 > * {@includeCode ./examples/ListPromptsResultResponse/list-prompts-result-response.json}
1322 > *
1323 > * @category `prompts/list`
1324 > */
1325 > export interface ListPromptsResultResponse extends JSONRPCResultResponse {
1326 > result: ListPromptsResult;
1327 > }
1328 >
1329 > /**
1330 > * Parameters for a `prompts/get` request.
1331 > *
1332 > * @example Get code review prompt
1333 > * {@includeCode ./examples/GetPromptRequestParams/get-code-review-prompt.json}
1334 > *
1335 > * @category `prompts/get`
1336 > */
1337 > export interface GetPromptRequestParams extends RequestParams {
1338 > /**
1339 > * The name of the prompt or prompt template.
1340 > */
1341 > name: string;
1342 > /**
1343 > * Arguments to use for templating the prompt.
1344 > */
1345 > arguments?: { [key: string]: string };
1346 > }
1347 >
1348 > /**
1349 > * Used by the client to get a prompt provided by the server.
1350 > *
1351 > * @example Get prompt request
1352 > * {@includeCode ./examples/GetPromptRequest/get-prompt-request.json}
1353 > *
1354 > * @category `prompts/get`
1355 > */
1356 > export interface GetPromptRequest extends JSONRPCRequest {
1357 > method: "prompts/get";
1358 > params: GetPromptRequestParams;
1359 > }
1360 >
1361 > /**
1362 > * The result returned by the server for a {@link GetPromptRequest | prompts/get} request.
1363 > *
1364 > * @example Code review prompt
1365 > * {@includeCode ./examples/GetPromptResult/code-review-prompt.json}
1366 > *
1367 > * @category `prompts/get`
1368 > */
1369 > export interface GetPromptResult extends Result {
1370 > /**
1371 > * An optional description for the prompt.
1372 > */
1373 > description?: string;
1374 > messages: PromptMessage[];
1375 > }
1376 >
1377 > /**
1378 > * A successful response from the server for a {@link GetPromptRequest | prompts/get} request.
1379 > *
1380 > * @example Get prompt result response
1381 > * {@includeCode ./examples/GetPromptResultResponse/get-prompt-result-response.json}
1382 > *
1383 > * @category `prompts/get`
1384 > */
1385 > export interface GetPromptResultResponse extends JSONRPCResultResponse {
1386 > result: GetPromptResult;
1387 > }
1388 >
1389 > /**
1390 > * A prompt or prompt template that the server offers.
1391 > *
1392 > * @category `prompts/list`
1393 > */
1394 > export interface Prompt extends BaseMetadata, Icons {
1395 > /**
1396 > * An optional description of what this prompt provides
1397 > */
1398 > description?: string;
1399 >
1400 > /**
1401 > * A list of arguments to use for templating the prompt.
1402 > */
1403 > arguments?: PromptArgument[];
1404 >
1405 > _meta?: MetaObject;
1406 > }
1407 >
1408 > /**
1409 > * Describes an argument that a prompt can accept.
1410 > *
1411 > * @category `prompts/list`
1412 > */
1413 > export interface PromptArgument extends BaseMetadata {
1414 > /**
1415 > * A human-readable description of the argument.
1416 > */
1417 > description?: string;
1418 > /**
1419 > * Whether this argument must be provided.
1420 > */
1421 > required?: boolean;
1422 > }
1423 >
1424 > /**
1425 > * The sender or recipient of messages and data in a conversation.
1426 > *
1427 > * @category Common Types
1428 > */
1429 > export type Role = "user" | "assistant";
1430 >
1431 > /**
1432 > * Describes a message returned as part of a prompt.
1433 > *
1434 > * This is similar to {@link SamplingMessage}, but also supports the embedding of
1435 > * resources from the MCP server.
1436 > *
1437 > * @category `prompts/get`
1438 > */
1439 > export interface PromptMessage {
1440 > role: Role;
1441 > content: ContentBlock;
1442 > }
1443 >
1444 > /**
1445 > * A resource that the server is capable of reading, included in a prompt or tool call result.
1446 > *
1447 > * Note: resource links returned by tools are not guaranteed to appear in the results of {@link ListResourcesRequest | resources/list} requests.
1448 > *
1449 > * @example File resource link
1450 > * {@includeCode ./examples/ResourceLink/file-resource-link.json}
1451 > *
1452 > * @category Content
1453 > */
1454 > export interface ResourceLink extends Resource {
1455 > type: "resource_link";
1456 > }
1457 >
1458 > /**
1459 > * The contents of a resource, embedded into a prompt or tool call result.
1460 > *
1461 > * It is up to the client how best to render embedded resources for the benefit
1462 > * of the LLM and/or the user.
1463 > *
1464 > * @example Embedded file resource with annotations
1465 > * {@includeCode ./examples/EmbeddedResource/embedded-file-resource-with-annotations.json}
1466 > *
1467 > * @category Content
1468 > */
1469 > export interface EmbeddedResource {
1470 > type: "resource";
1471 > resource: TextResourceContents | BlobResourceContents;
1472 >
1473 > /**
1474 > * Optional annotations for the client.
1475 > */
1476 > annotations?: Annotations;
1477 >
1478 > _meta?: MetaObject;
1479 > }
1480 > /**
1481 > * An optional notification from the server to the client, informing it that the list of prompts it offers has changed. This may be issued by servers without any previous subscription from the client.
1482 > *
1483 > * @example Prompts list changed
1484 > * {@includeCode ./examples/PromptListChangedNotification/prompts-list-changed.json}
1485 > *
1486 > * @category `notifications/prompts/list_changed`
1487 > */
1488 > export interface PromptListChangedNotification extends JSONRPCNotification {
1489 > method: "notifications/prompts/list_changed";
1490 > params?: NotificationParams;
1491 > }
1492 >
1493 > /* Tools */
1494 > /**
1495 > * Sent from the client to request a list of tools the server has.
1496 > *
1497 > * @example List tools request
1498 > * {@includeCode ./examples/ListToolsRequest/list-tools-request.json}
1499 > *
1500 > * @category `tools/list`
1501 > */
1502 > export interface ListToolsRequest extends PaginatedRequest {
1503 > method: "tools/list";
1504 > }
1505 >
1506 > /**
1507 > * The result returned by the server for a {@link ListToolsRequest | tools/list} request.
1508 > *
1509 > * @example Tools list with cursor
1510 > * {@includeCode ./examples/ListToolsResult/tools-list-with-cursor.json}
1511 > *
1512 > * @category `tools/list`
1513 > */
1514 > export interface ListToolsResult extends PaginatedResult {
1515 > tools: Tool[];
1516 > }
1517 >
1518 > /**
1519 > * A successful response from the server for a {@link ListToolsRequest | tools/list} request.
1520 > *
1521 > * @example List tools result response
1522 > * {@includeCode ./examples/ListToolsResultResponse/list-tools-result-response.json}
1523 > *
1524 > * @category `tools/list`
1525 > */
1526 > export interface ListToolsResultResponse extends JSONRPCResultResponse {
1527 > result: ListToolsResult;
1528 > }
1529 >
1530 > /**
1531 > * The result returned by the server for a {@link CallToolRequest | tools/call} request.
1532 > *
1533 > * @example Result with unstructured text
1534 > * {@includeCode ./examples/CallToolResult/result-with-unstructured-text.json}
1535 > *
1536 > * @example Result with structured content
1537 > * {@includeCode ./examples/CallToolResult/result-with-structured-content.json}
1538 > *
1539 > * @example Invalid tool input error
1540 > * {@includeCode ./examples/CallToolResult/invalid-tool-input-error.json}
1541 > *
1542 > * @category `tools/call`
1543 > */
1544 > export interface CallToolResult extends Result {
1545 > /**
1546 > * A list of content objects that represent the unstructured result of the tool call.
1547 > */
1548 > content: ContentBlock[];
1549 >
1550 > /**
1551 > * An optional JSON object that represents the structured result of the tool call.
1552 > */
1553 > structuredContent?: { [key: string]: unknown };
1554 >
1555 > /**
1556 > * Whether the tool call ended in an error.
1557 > *
1558 > * If not set, this is assumed to be false (the call was successful).
1559 > *
1560 > * Any errors that originate from the tool SHOULD be reported inside the result
1561 > * object, with `isError` set to true, _not_ as an MCP protocol-level error
1562 > * response. Otherwise, the LLM would not be able to see that an error occurred
1563 > * and self-correct.
1564 > *
1565 > * However, any errors in _finding_ the tool, an error indicating that the
1566 > * server does not support tool calls, or any other exceptional conditions,
1567 > * should be reported as an MCP error response.
1568 > */
1569 > isError?: boolean;
1570 > }
1571 >
1572 > /**
1573 > * A successful response from the server for a {@link CallToolRequest | tools/call} request.
1574 > *
1575 > * @example Call tool result response
1576 > * {@includeCode ./examples/CallToolResultResponse/call-tool-result-response.json}
1577 > *
1578 > * @category `tools/call`
1579 > */
1580 > export interface CallToolResultResponse extends JSONRPCResultResponse {
1581 > result: CallToolResult;
1582 > }
1583 >
1584 > /**
1585 > * Parameters for a `tools/call` request.
1586 > *
1587 > * @example `get_weather` tool call params
1588 > * {@includeCode ./examples/CallToolRequestParams/get-weather-tool-call-params.json}
1589 > *
1590 > * @example Tool call params with progress token
1591 > * {@includeCode ./examples/CallToolRequestParams/tool-call-params-with-progress-token.json}
1592 > *
1593 > * @category `tools/call`
1594 > */
1595 > export interface CallToolRequestParams extends TaskAugmentedRequestParams {
1596 > /**
1597 > * The name of the tool.
1598 > */
1599 > name: string;
1600 > /**
1601 > * Arguments to use for the tool call.
1602 > */
1603 > arguments?: { [key: string]: unknown };
1604 > }
1605 >
1606 > /**
1607 > * Used by the client to invoke a tool provided by the server.
1608 > *
1609 > * @example Call tool request
1610 > * {@includeCode ./examples/CallToolRequest/call-tool-request.json}
1611 > *
1612 > * @category `tools/call`
1613 > */
1614 > export interface CallToolRequest extends JSONRPCRequest {
1615 > method: "tools/call";
1616 > params: CallToolRequestParams;
1617 > }
1618 >
1619 > /**
1620 > * An optional notification from the server to the client, informing it that the list of tools it offers has changed. This may be issued by servers without any previous subscription from the client.
1621 > *
1622 > * @example Tools list changed
1623 > * {@includeCode ./examples/ToolListChangedNotification/tools-list-changed.json}
1624 > *
1625 > * @category `notifications/tools/list_changed`
1626 > */
1627 > export interface ToolListChangedNotification extends JSONRPCNotification {
1628 > method: "notifications/tools/list_changed";
1629 > params?: NotificationParams;
1630 > }
1631 >
1632 > /**
1633 > * Additional properties describing a {@link Tool} to clients.
1634 > *
1635 > * NOTE: all properties in `ToolAnnotations` are **hints**.
1636 > * They are not guaranteed to provide a faithful description of
1637 > * tool behavior (including descriptive properties like `title`).
1638 > *
1639 > * Clients should never make tool use decisions based on `ToolAnnotations`
1640 > * received from untrusted servers.
1641 > *
1642 > * @category `tools/list`
1643 > */
1644 > export interface ToolAnnotations {
1645 > /**
1646 > * A human-readable title for the tool.
1647 > */
1648 > title?: string;
1649 >
1650 > /**
1651 > * If true, the tool does not modify its environment.
1652 > *
1653 > * Default: false
1654 > */
1655 > readOnlyHint?: boolean;
1656 >
1657 > /**
1658 > * If true, the tool may perform destructive updates to its environment.
1659 > * If false, the tool performs only additive updates.
1660 > *
1661 > * (This property is meaningful only when `readOnlyHint == false`)
1662 > *
1663 > * Default: true
1664 > */
1665 > destructiveHint?: boolean;
1666 >
1667 > /**
1668 > * If true, calling the tool repeatedly with the same arguments
1669 > * will have no additional effect on its environment.
1670 > *
1671 > * (This property is meaningful only when `readOnlyHint == false`)
1672 > *
1673 > * Default: false
1674 > */
1675 > idempotentHint?: boolean;
1676 >
1677 > /**
1678 > * If true, this tool may interact with an "open world" of external
1679 > * entities. If false, the tool's domain of interaction is closed.
1680 > * For example, the world of a web search tool is open, whereas that
1681 > * of a memory tool is not.
1682 > *
1683 > * Default: true
1684 > */
1685 > openWorldHint?: boolean;
1686 > }
1687 >
1688 > /**
1689 > * Execution-related properties for a tool.
1690 > *
1691 > * @category `tools/list`
1692 > */
1693 > export interface ToolExecution {
1694 > /**
1695 > * Indicates whether this tool supports task-augmented execution.
1696 > * This allows clients to handle long-running operations through polling
1697 > * the task system.
1698 > *
1699 > * - `"forbidden"`: Tool does not support task-augmented execution (default when absent)
1700 > * - `"optional"`: Tool may support task-augmented execution
1701 > * - `"required"`: Tool requires task-augmented execution
1702 > *
1703 > * Default: `"forbidden"`
1704 > */
1705 > taskSupport?: "forbidden" | "optional" | "required";
1706 > }
1707 >
1708 > /**
1709 > * Definition for a tool the client can call.
1710 > *
1711 > * @example With default 2020-12 input schema
1712 > * {@includeCode ./examples/Tool/with-default-2020-12-input-schema.json}
1713 > *
1714 > * @example With explicit draft-07 input schema
1715 > * {@includeCode ./examples/Tool/with-explicit-draft-07-input-schema.json}
1716 > *
1717 > * @example With no parameters
1718 > * {@includeCode ./examples/Tool/with-no-parameters.json}
1719 > *
1720 > * @example With output schema for structured content
1721 > * {@includeCode ./examples/Tool/with-output-schema-for-structured-content.json}
1722 > *
1723 > * @category `tools/list`
1724 > */
1725 > export interface Tool extends BaseMetadata, Icons {
1726 > /**
1727 > * A human-readable description of the tool.
1728 > *
1729 > * This can be used by clients to improve the LLM's understanding of available tools. It can be thought of like a "hint" to the model.
1730 > */
1731 > description?: string;
1732 >
1733 > /**
1734 > * A JSON Schema object defining the expected parameters for the tool.
1735 > */
1736 > inputSchema: {
1737 > $schema?: string;
1738 > type: "object";
1739 > properties?: { [key: string]: object };
1740 > required?: string[];
1741 > };
1742 >
1743 > /**
1744 > * Execution-related properties for this tool.
1745 > */
1746 > execution?: ToolExecution;
1747 >
1748 > /**
1749 > * An optional JSON Schema object defining the structure of the tool's output returned in
1750 > * the structuredContent field of a {@link CallToolResult}.
1751 > *
1752 > * Defaults to JSON Schema 2020-12 when no explicit `$schema` is provided.
1753 > * Currently restricted to `type: "object"` at the root level.
1754 > */
1755 > outputSchema?: {
1756 > $schema?: string;
1757 > type: "object";
1758 > properties?: { [key: string]: object };
1759 > required?: string[];
1760 > };
1761 >
1762 > /**
1763 > * Optional additional tool information.
1764 > *
1765 > * Display name precedence order is: `title`, `annotations.title`, then `name`.
1766 > */
1767 > annotations?: ToolAnnotations;
1768 >
1769 > _meta?: MetaObject;
1770 > }
1771 >
1772 > /* Tasks */
1773 >
1774 > /**
1775 > * The status of a task.
1776 > *
1777 > * @category `tasks`
1778 > */
1779 > export type TaskStatus =
1780 > | "working" // The request is currently being processed
1781 > | "input_required" // The task is waiting for input (e.g., elicitation or sampling)
1782 > | "completed" // The request completed successfully and results are available
1783 > | "failed" // The associated request did not complete successfully. For tool calls specifically, this includes cases where the tool call result has `isError` set to true.
1784 > | "cancelled"; // The request was cancelled before completion
1785 >
1786 > /**
1787 > * Metadata for augmenting a request with task execution.
1788 > * Include this in the `task` field of the request parameters.
1789 > *
1790 > * @category `tasks`
1791 > */
1792 > export interface TaskMetadata {
1793 > /**
1794 > * Requested duration in milliseconds to retain task from creation.
1795 > */
1796 > ttl?: number;
1797 > }
1798 >
1799 > /**
1800 > * Metadata for associating messages with a task.
1801 > * Include this in the `_meta` field under the key `io.modelcontextprotocol/related-task`.
1802 > *
1803 > * @category `tasks`
1804 > */
1805 > export interface RelatedTaskMetadata {
1806 > /**
1807 > * The task identifier this message is associated with.
1808 > */
1809 > taskId: string;
1810 > }
1811 >
1812 > /**
1813 > * Data associated with a task.
1814 > *
1815 > * @category `tasks`
1816 > */
1817 > export interface Task {
1818 > /**
1819 > * The task identifier.
1820 > */
1821 > taskId: string;
1822 >
1823 > /**
1824 > * Current task state.
1825 > */
1826 > status: TaskStatus;
1827 >
1828 > /**
1829 > * Optional human-readable message describing the current task state.
1830 > * This can provide context for any status, including:
1831 > * - Reasons for "cancelled" status
1832 > * - Summaries for "completed" status
1833 > * - Diagnostic information for "failed" status (e.g., error details, what went wrong)
1834 > */
1835 > statusMessage?: string;
1836 >
1837 > /**
1838 > * ISO 8601 timestamp when the task was created.
1839 > */
1840 > createdAt: string;
1841 >
1842 > /**
1843 > * ISO 8601 timestamp when the task was last updated.
1844 > */
1845 > lastUpdatedAt: string;
1846 >
1847 > /**
1848 > * Actual retention duration from creation in milliseconds, null for unlimited.
1849 > */
1850 > ttl: number | null;
1851 >
1852 > /**
1853 > * Suggested polling interval in milliseconds.
1854 > */
1855 > pollInterval?: number;
1856 > }
1857 >
1858 > /**
1859 > * The result returned for a task-augmented request.
1860 > *
1861 > * @category `tasks`
1862 > */
1863 > export interface CreateTaskResult extends Result {
1864 > task: Task;
1865 > }
1866 >
1867 > /**
1868 > * A successful response for a task-augmented request.
1869 > *
1870 > * @category `tasks`
1871 > */
1872 > export interface CreateTaskResultResponse extends JSONRPCResultResponse {
1873 > result: CreateTaskResult;
1874 > }
1875 >
1876 > /**
1877 > * A request to retrieve the state of a task.
1878 > *
1879 > * @category `tasks/get`
1880 > */
1881 > export interface GetTaskRequest extends JSONRPCRequest {
1882 > method: "tasks/get";
1883 > params: {
1884 > /**
1885 > * The task identifier to query.
1886 > */
1887 > taskId: string;
1888 > };
1889 > }
1890 >
1891 > /**
1892 > * The result returned for a {@link GetTaskRequest | tasks/get} request.
1893 > *
1894 > * @category `tasks/get`
1895 > */
1896 > export type GetTaskResult = Result & Task;
1897 >
1898 > /**
1899 > * A successful response for a {@link GetTaskRequest | tasks/get} request.
1900 > *
1901 > * @category `tasks/get`
1902 > */
1903 > export interface GetTaskResultResponse extends JSONRPCResultResponse {
1904 > result: GetTaskResult;
1905 > }
1906 >
1907 > /**
1908 > * A request to retrieve the result of a completed task.
1909 > *
1910 > * @category `tasks/result`
1911 > */
1912 > export interface GetTaskPayloadRequest extends JSONRPCRequest {
1913 > method: "tasks/result";
1914 > params: {
1915 > /**
1916 > * The task identifier to retrieve results for.
1917 > */
1918 > taskId: string;
1919 > };
1920 > }
1921 >
1922 > /**
1923 > * The result returned for a {@link GetTaskPayloadRequest | tasks/result} request.
1924 > * The structure matches the result type of the original request.
1925 > * For example, a {@link CallToolRequest | tools/call} task would return the {@link CallToolResult} structure.
1926 > *
1927 > * @category `tasks/result`
1928 > */
1929 > export interface GetTaskPayloadResult extends Result {
1930 > [key: string]: unknown;
1931 > }
1932 >
1933 > /**
1934 > * A successful response for a {@link GetTaskPayloadRequest | tasks/result} request.
1935 > *
1936 > * @category `tasks/result`
1937 > */
1938 > export interface GetTaskPayloadResultResponse extends JSONRPCResultResponse {
1939 > result: GetTaskPayloadResult;
1940 > }
1941 >
1942 > /**
1943 > * A request to cancel a task.
1944 > *
1945 > * @category `tasks/cancel`
1946 > */
1947 > export interface CancelTaskRequest extends JSONRPCRequest {
1948 > method: "tasks/cancel";
1949 > params: {
1950 > /**
1951 > * The task identifier to cancel.
1952 > */
1953 > taskId: string;
1954 > };
1955 > }
1956 >
1957 > /**
1958 > * The result returned for a {@link CancelTaskRequest | tasks/cancel} request.
1959 > *
1960 > * @category `tasks/cancel`
1961 > */
1962 > export type CancelTaskResult = Result & Task;
1963 >
1964 > /**
1965 > * A successful response for a {@link CancelTaskRequest | tasks/cancel} request.
1966 > *
1967 > * @category `tasks/cancel`
1968 > */
1969 > export interface CancelTaskResultResponse extends JSONRPCResultResponse {
1970 > result: CancelTaskResult;
1971 > }
1972 >
1973 > /**
1974 > * A request to retrieve a list of tasks.
1975 > *
1976 > * @category `tasks/list`
1977 > */
1978 > export interface ListTasksRequest extends PaginatedRequest {
1979 > method: "tasks/list";
1980 > }
1981 >
1982 > /**
1983 > * The result returned for a {@link ListTasksRequest | tasks/list} request.
1984 > *
1985 > * @category `tasks/list`
1986 > */
1987 > export interface ListTasksResult extends PaginatedResult {
1988 > tasks: Task[];
1989 > }
1990 >
1991 > /**
1992 > * A successful response for a {@link ListTasksRequest | tasks/list} request.
1993 > *
1994 > * @category `tasks/list`
1995 > */
1996 > export interface ListTasksResultResponse extends JSONRPCResultResponse {
1997 > result: ListTasksResult;
1998 > }
1999 >
2000 > /**
2001 > * Parameters for a `notifications/tasks/status` notification.
2002 > *
2003 > * @category `notifications/tasks/status`
2004 > */
2005 > export type TaskStatusNotificationParams = NotificationParams & Task;
2006 >
2007 > /**
2008 > * An optional notification from the receiver to the requestor, informing them that a task's status has changed. Receivers are not required to send these notifications.
2009 > *
2010 > * @category `notifications/tasks/status`
2011 > */
2012 > export interface TaskStatusNotification extends JSONRPCNotification {
2013 > method: "notifications/tasks/status";
2014 > params: TaskStatusNotificationParams;
2015 > }
2016 >
2017 > /* Logging */
2018 >
2019 > /**
2020 > * Parameters for a `logging/setLevel` request.
2021 > *
2022 > * @example Set log level to "info"
2023 > * {@includeCode ./examples/SetLevelRequestParams/set-log-level-to-info.json}
2024 > *
2025 > * @category `logging/setLevel`
2026 > */
2027 > export interface SetLevelRequestParams extends RequestParams {
2028 > /**
2029 > * The level of logging that the client wants to receive from the server. The server should send all logs at this level and higher (i.e., more severe) to the client as {@link LoggingMessageNotification | notifications/message}.
2030 > */
2031 > level: LoggingLevel;
2032 > }
2033 >
2034 > /**
2035 > * A request from the client to the server, to enable or adjust logging.
2036 > *
2037 > * @example Set logging level request
2038 > * {@includeCode ./examples/SetLevelRequest/set-logging-level-request.json}
2039 > *
2040 > * @category `logging/setLevel`
2041 > */
2042 > export interface SetLevelRequest extends JSONRPCRequest {
2043 > method: "logging/setLevel";
2044 > params: SetLevelRequestParams;
2045 > }
2046 >
2047 > /**
2048 > * A successful response from the server for a {@link SetLevelRequest | logging/setLevel} request.
2049 > *
2050 > * @example Set logging level result response
2051 > * {@includeCode ./examples/SetLevelResultResponse/set-logging-level-result-response.json}
2052 > *
2053 > * @category `logging/setLevel`
2054 > */
2055 > export interface SetLevelResultResponse extends JSONRPCResultResponse {
2056 > result: EmptyResult;
2057 > }
2058 >
2059 > /**
2060 > * Parameters for a `notifications/message` notification.
2061 > *
2062 > * @example Log database connection failed
2063 > * {@includeCode ./examples/LoggingMessageNotificationParams/log-database-connection-failed.json}
2064 > *
2065 > * @category `notifications/message`
2066 > */
2067 > export interface LoggingMessageNotificationParams extends NotificationParams {
2068 > /**
2069 > * The severity of this log message.
2070 > */
2071 > level: LoggingLevel;
2072 > /**
2073 > * An optional name of the logger issuing this message.
2074 > */
2075 > logger?: string;
2076 > /**
2077 > * The data to be logged, such as a string message or an object. Any JSON serializable type is allowed here.
2078 > */
2079 > data: unknown;
2080 > }
2081 >
2082 > /**
2083 > * JSONRPCNotification of a log message passed from server to client. If no `logging/setLevel` request has been sent from the client, the server MAY decide which messages to send automatically.
2084 > *
2085 > * @example Log database connection failed
2086 > * {@includeCode ./examples/LoggingMessageNotification/log-database-connection-failed.json}
2087 > *
2088 > * @category `notifications/message`
2089 > */
2090 > export interface LoggingMessageNotification extends JSONRPCNotification {
2091 > method: "notifications/message";
2092 > params: LoggingMessageNotificationParams;
2093 > }
2094 >
2095 > /**
2096 > * The severity of a log message.
2097 > *
2098 > * These map to syslog message severities, as specified in RFC-5424:
2099 > * https://datatracker.ietf.org/doc/html/rfc5424#section-6.2.1
2100 > *
2101 > * @category Common Types
2102 > */
2103 > export type LoggingLevel =
2104 > | "debug"
2105 > | "info"
2106 > | "notice"
2107 > | "warning"
2108 > | "error"
2109 > | "critical"
2110 > | "alert"
2111 > | "emergency";
2112 >
2113 > /* Sampling */
2114 > /**
2115 > * Parameters for a `sampling/createMessage` request.
2116 > *
2117 > * @example Basic request
2118 > * {@includeCode ./examples/CreateMessageRequestParams/basic-request.json}
2119 > *
2120 > * @example Request with tools
2121 > * {@includeCode ./examples/CreateMessageRequestParams/request-with-tools.json}
2122 > *
2123 > * @example Follow-up request with tool results
2124 > * {@includeCode ./examples/CreateMessageRequestParams/follow-up-with-tool-results.json}
2125 > *
2126 > * @category `sampling/createMessage`
2127 > */
2128 > export interface CreateMessageRequestParams extends TaskAugmentedRequestParams {
2129 > messages: SamplingMessage[];
2130 > /**
2131 > * The server's preferences for which model to select. The client MAY ignore these preferences.
2132 > */
2133 > modelPreferences?: ModelPreferences;
2134 > /**
2135 > * An optional system prompt the server wants to use for sampling. The client MAY modify or omit this prompt.
2136 > */
2137 > systemPrompt?: string;
2138 > /**
2139 > * A request to include context from one or more MCP servers (including the caller), to be attached to the prompt.
2140 > * The client MAY ignore this request.
2141 > *
2142 > * Default is `"none"`. Values `"thisServer"` and `"allServers"` are soft-deprecated. Servers SHOULD only use these values if the client
2143 > * declares {@link ClientCapabilities.sampling.context}. These values may be removed in future spec releases.
2144 > */
2145 > includeContext?: "none" | "thisServer" | "allServers";
2146 > /**
2147 > * @TJS-type number
2148 > */
2149 > temperature?: number;
2150 > /**
2151 > * The requested maximum number of tokens to sample (to prevent runaway completions).
2152 > *
2153 > * The client MAY choose to sample fewer tokens than the requested maximum.
2154 > */
2155 > maxTokens: number;
2156 > stopSequences?: string[];
2157 > /**
2158 > * Optional metadata to pass through to the LLM provider. The format of this metadata is provider-specific.
2159 > */
2160 > metadata?: object;
2161 > /**
2162 > * Tools that the model may use during generation.
2163 > * The client MUST return an error if this field is provided but {@link ClientCapabilities.sampling.tools} is not declared.
2164 > */
2165 > tools?: Tool[];
2166 > /**
2167 > * Controls how the model uses tools.
2168 > * The client MUST return an error if this field is provided but {@link ClientCapabilities.sampling.tools} is not declared.
2169 > * Default is `{ mode: "auto" }`.
2170 > */
2171 > toolChoice?: ToolChoice;
2172 > }
2173 >
2174 > /**
2175 > * Controls tool selection behavior for sampling requests.
2176 > *
2177 > * @category `sampling/createMessage`
2178 > */
2179 > export interface ToolChoice {
2180 > /**
2181 > * Controls the tool use ability of the model:
2182 > * - `"auto"`: Model decides whether to use tools (default)
2183 > * - `"required"`: Model MUST use at least one tool before completing
2184 > * - `"none"`: Model MUST NOT use any tools
2185 > */
2186 > mode?: "auto" | "required" | "none";
2187 > }
2188 >
2189 > /**
2190 > * A request from the server to sample an LLM via the client. The client has full discretion over which model to select. The client should also inform the user before beginning sampling, to allow them to inspect the request (human in the loop) and decide whether to approve it.
2191 > *
2192 > * @example Sampling request
2193 > * {@includeCode ./examples/CreateMessageRequest/sampling-request.json}
2194 > *
2195 > * @category `sampling/createMessage`
2196 > */
2197 > export interface CreateMessageRequest extends JSONRPCRequest {
2198 > method: "sampling/createMessage";
2199 > params: CreateMessageRequestParams;
2200 > }
2201 >
2202 > /**
2203 > * The result returned by the client for a {@link CreateMessageRequest | sampling/createMessage} request.
2204 > * The client should inform the user before returning the sampled message, to allow them
2205 > * to inspect the response (human in the loop) and decide whether to allow the server to see it.
2206 > *
2207 > * @example Text response
2208 > * {@includeCode ./examples/CreateMessageResult/text-response.json}
2209 > *
2210 > * @example Tool use response
2211 > * {@includeCode ./examples/CreateMessageResult/tool-use-response.json}
2212 > *
2213 > * @example Final response after tool use
2214 > * {@includeCode ./examples/CreateMessageResult/final-response.json}
2215 > *
2216 > * @category `sampling/createMessage`
2217 > */
2218 > export interface CreateMessageResult extends Result, SamplingMessage {
2219 > /**
2220 > * The name of the model that generated the message.
2221 > */
2222 > model: string;
2223 >
2224 > /**
2225 > * The reason why sampling stopped, if known.
2226 > *
2227 > * Standard values:
2228 > * - `"endTurn"`: Natural end of the assistant's turn
2229 > * - `"stopSequence"`: A stop sequence was encountered
2230 > * - `"maxTokens"`: Maximum token limit was reached
2231 > * - `"toolUse"`: The model wants to use one or more tools
2232 > *
2233 > * This field is an open string to allow for provider-specific stop reasons.
2234 > */
2235 > stopReason?: "endTurn" | "stopSequence" | "maxTokens" | "toolUse" | string;
2236 > }
2237 >
2238 > /**
2239 > * A successful response from the client for a {@link CreateMessageRequest | sampling/createMessage} request.
2240 > *
2241 > * @example Sampling result response
2242 > * {@includeCode ./examples/CreateMessageResultResponse/sampling-result-response.json}
2243 > *
2244 > * @category `sampling/createMessage`
2245 > */
2246 > export interface CreateMessageResultResponse extends JSONRPCResultResponse {
2247 > result: CreateMessageResult;
2248 > }
2249 >
2250 > /**
2251 > * Describes a message issued to or received from an LLM API.
2252 > *
2253 > * @example Single content block
2254 > * {@includeCode ./examples/SamplingMessage/single-content-block.json}
2255 > *
2256 > * @example Multiple content blocks
2257 > * {@includeCode ./examples/SamplingMessage/multiple-content-blocks.json}
2258 > *
2259 > * @category `sampling/createMessage`
2260 > */
2261 > export interface SamplingMessage {
2262 > role: Role;
2263 > content: SamplingMessageContentBlock | SamplingMessageContentBlock[];
2264 > _meta?: MetaObject;
2265 > }
2266 >
2267 > /**
2268 > * @category `sampling/createMessage`
2269 > */
2270 > export type SamplingMessageContentBlock =
2271 > | TextContent
2272 > | ImageContent
2273 > | AudioContent
2274 > | ToolUseContent
2275 > | ToolResultContent;
2276 >
2277 > /**
2278 > * Optional annotations for the client. The client can use annotations to inform how objects are used or displayed
2279 > *
2280 > * @category Common Types
2281 > */
2282 > export interface Annotations {
2283 > /**
2284 > * Describes who the intended audience of this object or data is.
2285 > *
2286 > * It can include multiple entries to indicate content useful for multiple audiences (e.g., `["user", "assistant"]`).
2287 > */
2288 > audience?: Role[];
2289 >
2290 > /**
2291 > * Describes how important this data is for operating the server.
2292 > *
2293 > * A value of 1 means "most important," and indicates that the data is
2294 > * effectively required, while 0 means "least important," and indicates that
2295 > * the data is entirely optional.
2296 > *
2297 > * @TJS-type number
2298 > * @minimum 0
2299 > * @maximum 1
2300 > */
2301 > priority?: number;
2302 >
2303 > /**
2304 > * The moment the resource was last modified, as an ISO 8601 formatted string.
2305 > *
2306 > * Should be an ISO 8601 formatted string (e.g., "2025-01-12T15:00:58Z").
2307 > *
2308 > * Examples: last activity timestamp in an open file, timestamp when the resource
2309 > * was attached, etc.
2310 > */
2311 > lastModified?: string;
2312 > }
2313 >
2314 > /**
2315 > * @category Content
2316 > */
2317 > export type ContentBlock =
2318 > | TextContent
2319 > | ImageContent
2320 > | AudioContent
2321 > | ResourceLink
2322 > | EmbeddedResource;
2323 >
2324 > /**
2325 > * Text provided to or from an LLM.
2326 > *
2327 > * @example Text content
2328 > * {@includeCode ./examples/TextContent/text-content.json}
2329 > *
2330 > * @category Content
2331 > */
2332 > export interface TextContent {
2333 > type: "text";
2334 >
2335 > /**
2336 > * The text content of the message.
2337 > */
2338 > text: string;
2339 >
2340 > /**
2341 > * Optional annotations for the client.
2342 > */
2343 > annotations?: Annotations;
2344 >
2345 > _meta?: MetaObject;
2346 > }
2347 >
2348 > /**
2349 > * An image provided to or from an LLM.
2350 > *
2351 > * @example `image/png` content with annotations
2352 > * {@includeCode ./examples/ImageContent/image-png-content-with-annotations.json}
2353 > *
2354 > * @category Content
2355 > */
2356 > export interface ImageContent {
2357 > type: "image";
2358 >
2359 > /**
2360 > * The base64-encoded image data.
2361 > *
2362 > * @format byte
2363 > */
2364 > data: string;
2365 >
2366 > /**
2367 > * The MIME type of the image. Different providers may support different image types.
2368 > */
2369 > mimeType: string;
2370 >
2371 > /**
2372 > * Optional annotations for the client.
2373 > */
2374 > annotations?: Annotations;
2375 >
2376 > _meta?: MetaObject;
2377 > }
2378 >
2379 > /**
2380 > * Audio provided to or from an LLM.
2381 > *
2382 > * @example `audio/wav` content
2383 > * {@includeCode ./examples/AudioContent/audio-wav-content.json}
2384 > *
2385 > * @category Content
2386 > */
2387 > export interface AudioContent {
2388 > type: "audio";
2389 >
2390 > /**
2391 > * The base64-encoded audio data.
2392 > *
2393 > * @format byte
2394 > */
2395 > data: string;
2396 >
2397 > /**
2398 > * The MIME type of the audio. Different providers may support different audio types.
2399 > */
2400 > mimeType: string;
2401 >
2402 > /**
2403 > * Optional annotations for the client.
2404 > */
2405 > annotations?: Annotations;
2406 >
2407 > _meta?: MetaObject;
2408 > }
2409 >
2410 > /**
2411 > * A request from the assistant to call a tool.
2412 > *
2413 > * @example `get_weather` tool use
2414 > * {@includeCode ./examples/ToolUseContent/get-weather-tool-use.json}
2415 > *
2416 > * @category `sampling/createMessage`
2417 > */
2418 > export interface ToolUseContent {
2419 > type: "tool_use";
2420 >
2421 > /**
2422 > * A unique identifier for this tool use.
2423 > *
2424 > * This ID is used to match tool results to their corresponding tool uses.
2425 > */
2426 > id: string;
2427 >
2428 > /**
2429 > * The name of the tool to call.
2430 > */
2431 > name: string;
2432 >
2433 > /**
2434 > * The arguments to pass to the tool, conforming to the tool's input schema.
2435 > */
2436 > input: { [key: string]: unknown };
2437 >
2438 > /**
2439 > * Optional metadata about the tool use. Clients SHOULD preserve this field when
2440 > * including tool uses in subsequent sampling requests to enable caching optimizations.
2441 > */
2442 > _meta?: MetaObject;
2443 > }
2444 >
2445 > /**
2446 > * The result of a tool use, provided by the user back to the assistant.
2447 > *
2448 > * @example `get_weather` tool result
2449 > * {@includeCode ./examples/ToolResultContent/get-weather-tool-result.json}
2450 > *
2451 > * @category `sampling/createMessage`
2452 > */
2453 > export interface ToolResultContent {
2454 > type: "tool_result";
2455 >
2456 > /**
2457 > * The ID of the tool use this result corresponds to.
2458 > *
2459 > * This MUST match the ID from a previous {@link ToolUseContent}.
2460 > */
2461 > toolUseId: string;
2462 >
2463 > /**
2464 > * The unstructured result content of the tool use.
2465 > *
2466 > * This has the same format as {@link CallToolResult.content} and can include text, images,
2467 > * audio, resource links, and embedded resources.
2468 > */
2469 > content: ContentBlock[];
2470 >
2471 > /**
2472 > * An optional structured result object.
2473 > *
2474 > * If the tool defined an {@link Tool.outputSchema}, this SHOULD conform to that schema.
2475 > */
2476 > structuredContent?: { [key: string]: unknown };
2477 >
2478 > /**
2479 > * Whether the tool use resulted in an error.
2480 > *
2481 > * If true, the content typically describes the error that occurred.
2482 > * Default: false
2483 > */
2484 > isError?: boolean;
2485 >
2486 > /**
2487 > * Optional metadata about the tool result. Clients SHOULD preserve this field when
2488 > * including tool results in subsequent sampling requests to enable caching optimizations.
2489 > */
2490 > _meta?: MetaObject;
2491 > }
2492 >
2493 > /**
2494 > * The server's preferences for model selection, requested of the client during sampling.
2495 > *
2496 > * Because LLMs can vary along multiple dimensions, choosing the "best" model is
2497 > * rarely straightforward. Different models excel in different areas-some are
2498 > * faster but less capable, others are more capable but more expensive, and so
2499 > * on. This interface allows servers to express their priorities across multiple
2500 > * dimensions to help clients make an appropriate selection for their use case.
2501 > *
2502 > * These preferences are always advisory. The client MAY ignore them. It is also
2503 > * up to the client to decide how to interpret these preferences and how to
2504 > * balance them against other considerations.
2505 > *
2506 > * @example With hints and priorities
2507 > * {@includeCode ./examples/ModelPreferences/with-hints-and-priorities.json}
2508 > *
2509 > * @category `sampling/createMessage`
2510 > */
2511 > export interface ModelPreferences {
2512 > /**
2513 > * Optional hints to use for model selection.
2514 > *
2515 > * If multiple hints are specified, the client MUST evaluate them in order
2516 > * (such that the first match is taken).
2517 > *
2518 > * The client SHOULD prioritize these hints over the numeric priorities, but
2519 > * MAY still use the priorities to select from ambiguous matches.
2520 > */
2521 > hints?: ModelHint[];
2522 >
2523 > /**
2524 > * How much to prioritize cost when selecting a model. A value of 0 means cost
2525 > * is not important, while a value of 1 means cost is the most important
2526 > * factor.
2527 > *
2528 > * @TJS-type number
2529 > * @minimum 0
2530 > * @maximum 1
2531 > */
2532 > costPriority?: number;
2533 >
2534 > /**
2535 > * How much to prioritize sampling speed (latency) when selecting a model. A
2536 > * value of 0 means speed is not important, while a value of 1 means speed is
2537 > * the most important factor.
2538 > *
2539 > * @TJS-type number
2540 > * @minimum 0
2541 > * @maximum 1
2542 > */
2543 > speedPriority?: number;
2544 >
2545 > /**
2546 > * How much to prioritize intelligence and capabilities when selecting a
2547 > * model. A value of 0 means intelligence is not important, while a value of 1
2548 > * means intelligence is the most important factor.
2549 > *
2550 > * @TJS-type number
2551 > * @minimum 0
2552 > * @maximum 1
2553 > */
2554 > intelligencePriority?: number;
2555 > }
2556 >
2557 > /**
2558 > * Hints to use for model selection.
2559 > *
2560 > * Keys not declared here are currently left unspecified by the spec and are up
2561 > * to the client to interpret.
2562 > *
2563 > * @category `sampling/createMessage`
2564 > */
2565 > export interface ModelHint {
2566 > /**
2567 > * A hint for a model name.
2568 > *
2569 > * The client SHOULD treat this as a substring of a model name; for example:
2570 > * - `claude-3-5-sonnet` should match `claude-3-5-sonnet-20241022`
2571 > * - `sonnet` should match `claude-3-5-sonnet-20241022`, `claude-3-sonnet-20240229`, etc.
2572 > * - `claude` should match any Claude model
2573 > *
2574 > * The client MAY also map the string to a different provider's model name or a different model family, as long as it fills a similar niche; for example:
2575 > * - `gemini-1.5-flash` could match `claude-3-haiku-20240307`
2576 > */
2577 > name?: string;
2578 > }
2579 >
2580 > /* Autocomplete */
2581 > /**
2582 > * Parameters for a `completion/complete` request.
2583 > *
2584 > * @category `completion/complete`
2585 > *
2586 > * @example Prompt argument completion
2587 > * {@includeCode ./examples/CompleteRequestParams/prompt-argument-completion.json}
2588 > *
2589 > * @example Prompt argument completion with context
2590 > * {@includeCode ./examples/CompleteRequestParams/prompt-argument-completion-with-context.json}
2591 > */
2592 > export interface CompleteRequestParams extends RequestParams {
2593 > ref: PromptReference | ResourceTemplateReference;
2594 > /**
2595 > * The argument's information
2596 > */
2597 > argument: {
2598 > /**
2599 > * The name of the argument
2600 > */
2601 > name: string;
2602 > /**
2603 > * The value of the argument to use for completion matching.
2604 > */
2605 > value: string;
2606 > };
2607 >
2608 > /**
2609 > * Additional, optional context for completions
2610 > */
2611 > context?: {
2612 > /**
2613 > * Previously-resolved variables in a URI template or prompt.
2614 > */
2615 > arguments?: { [key: string]: string };
2616 > };
2617 > }
2618 >
2619 > /**
2620 > * A request from the client to the server, to ask for completion options.
2621 > *
2622 > * @example Completion request
2623 > * {@includeCode ./examples/CompleteRequest/completion-request.json}
2624 > *
2625 > * @category `completion/complete`
2626 > */
2627 > export interface CompleteRequest extends JSONRPCRequest {
2628 > method: "completion/complete";
2629 > params: CompleteRequestParams;
2630 > }
2631 >
2632 > /**
2633 > * The result returned by the server for a {@link CompleteRequest | completion/complete} request.
2634 > *
2635 > * @category `completion/complete`
2636 > *
2637 > * @example Single completion value
2638 > * {@includeCode ./examples/CompleteResult/single-completion-value.json}
2639 > *
2640 > * @example Multiple completion values with more available
2641 > * {@includeCode ./examples/CompleteResult/multiple-completion-values-with-more-available.json}
2642 > */
2643 > export interface CompleteResult extends Result {
2644 > completion: {
2645 > /**
2646 > * An array of completion values. Must not exceed 100 items.
2647 > */
2648 > values: string[];
2649 > /**
2650 > * The total number of completion options available. This can exceed the number of values actually sent in the response.
2651 > */
2652 > total?: number;
2653 > /**
2654 > * Indicates whether there are additional completion options beyond those provided in the current response, even if the exact total is unknown.
2655 > */
2656 > hasMore?: boolean;
2657 > };
2658 > }
2659 >
2660 > /**
2661 > * A successful response from the server for a {@link CompleteRequest | completion/complete} request.
2662 > *
2663 > * @example Completion result response
2664 > * {@includeCode ./examples/CompleteResultResponse/completion-result-response.json}
2665 > *
2666 > * @category `completion/complete`
2667 > */
2668 > export interface CompleteResultResponse extends JSONRPCResultResponse {
2669 > result: CompleteResult;
2670 > }
2671 >
2672 > /**
2673 > * A reference to a resource or resource template definition.
2674 > *
2675 > * @category `completion/complete`
2676 > */
2677 > export interface ResourceTemplateReference {
2678 > type: "ref/resource";
2679 > /**
2680 > * The URI or URI template of the resource.
2681 > *
2682 > * @format uri-template
2683 > */
2684 > uri: string;
2685 > }
2686 >
2687 > /**
2688 > * Identifies a prompt.
2689 > *
2690 > * @category `completion/complete`
2691 > */
2692 > export interface PromptReference extends BaseMetadata {
2693 > type: "ref/prompt";
2694 > }
2695 >
2696 > /* Roots */
2697 > /**
2698 > * Sent from the server to request a list of root URIs from the client. Roots allow
2699 > * servers to ask for specific directories or files to operate on. A common example
2700 > * for roots is providing a set of repositories or directories a server should operate
2701 > * on.
2702 > *
2703 > * This request is typically used when the server needs to understand the file system
2704 > * structure or access specific locations that the client has permission to read from.
2705 > *
2706 > * @example List roots request
2707 > * {@includeCode ./examples/ListRootsRequest/list-roots-request.json}
2708 > *
2709 > * @category `roots/list`
2710 > */
2711 > export interface ListRootsRequest extends JSONRPCRequest {
2712 > method: "roots/list";
2713 > params?: RequestParams;
2714 > }
2715 >
2716 > /**
2717 > * The result returned by the client for a {@link ListRootsRequest | roots/list} request.
2718 > * This result contains an array of {@link Root} objects, each representing a root directory
2719 > * or file that the server can operate on.
2720 > *
2721 > * @example Single root directory
2722 > * {@includeCode ./examples/ListRootsResult/single-root-directory.json}
2723 > *
2724 > * @example Multiple root directories
2725 > * {@includeCode ./examples/ListRootsResult/multiple-root-directories.json}
2726 > *
2727 > * @category `roots/list`
2728 > */
2729 > export interface ListRootsResult extends Result {
2730 > roots: Root[];
2731 > }
2732 >
2733 > /**
2734 > * A successful response from the client for a {@link ListRootsRequest | roots/list} request.
2735 > *
2736 > * @example List roots result response
2737 > * {@includeCode ./examples/ListRootsResultResponse/list-roots-result-response.json}
2738 > *
2739 > * @category `roots/list`
2740 > */
2741 > export interface ListRootsResultResponse extends JSONRPCResultResponse {
2742 > result: ListRootsResult;
2743 > }
2744 >
2745 > /**
2746 > * Represents a root directory or file that the server can operate on.
2747 > *
2748 > * @example Project directory root
2749 > * {@includeCode ./examples/Root/project-directory.json}
2750 > *
2751 > * @category `roots/list`
2752 > */
2753 > export interface Root {
2754 > /**
2755 > * The URI identifying the root. This *must* start with `file://` for now.
2756 > * This restriction may be relaxed in future versions of the protocol to allow
2757 > * other URI schemes.
2758 > *
2759 > * @format uri
2760 > */
2761 > uri: string;
2762 > /**
2763 > * An optional name for the root. This can be used to provide a human-readable
2764 > * identifier for the root, which may be useful for display purposes or for
2765 > * referencing the root in other parts of the application.
2766 > */
2767 > name?: string;
2768 >
2769 > _meta?: MetaObject;
2770 > }
2771 >
2772 > /**
2773 > * A notification from the client to the server, informing it that the list of roots has changed.
2774 > * This notification should be sent whenever the client adds, removes, or modifies any root.
2775 > * The server should then request an updated list of roots using the {@link ListRootsRequest}.
2776 > *
2777 > * @example Roots list changed
2778 > * {@includeCode ./examples/RootsListChangedNotification/roots-list-changed.json}
2779 > *
2780 > * @category `notifications/roots/list_changed`
2781 > */
2782 > export interface RootsListChangedNotification extends JSONRPCNotification {
2783 > method: "notifications/roots/list_changed";
2784 > params?: NotificationParams;
2785 > }
2786 >
2787 > /**
2788 > * The parameters for a request to elicit non-sensitive information from the user via a form in the client.
2789 > *
2790 > * @example Elicit single field
2791 > * {@includeCode ./examples/ElicitRequestFormParams/elicit-single-field.json}
2792 > *
2793 > * @example Elicit multiple fields
2794 > * {@includeCode ./examples/ElicitRequestFormParams/elicit-multiple-fields.json}
2795 > *
2796 > * @category `elicitation/create`
2797 > */
2798 > export interface ElicitRequestFormParams extends TaskAugmentedRequestParams {
2799 > /**
2800 > * The elicitation mode.
2801 > */
2802 > mode?: "form";
2803 >
2804 > /**
2805 > * The message to present to the user describing what information is being requested.
2806 > */
2807 > message: string;
2808 >
2809 > /**
2810 > * A restricted subset of JSON Schema.
2811 > * Only top-level properties are allowed, without nesting.
2812 > */
2813 > requestedSchema: {
2814 > $schema?: string;
2815 > type: "object";
2816 > properties: {
2817 > [key: string]: PrimitiveSchemaDefinition;
2818 > };
2819 > required?: string[];
2820 > };
2821 > }
2822 >
2823 > /**
2824 > * The parameters for a request to elicit information from the user via a URL in the client.
2825 > *
2826 > * @example Elicit sensitive data
2827 > * {@includeCode ./examples/ElicitRequestURLParams/elicit-sensitive-data.json}
2828 > *
2829 > * @category `elicitation/create`
2830 > */
2831 > export interface ElicitRequestURLParams extends TaskAugmentedRequestParams {
2832 > /**
2833 > * The elicitation mode.
2834 > */
2835 > mode: "url";
2836 >
2837 > /**
2838 > * The message to present to the user explaining why the interaction is needed.
2839 > */
2840 > message: string;
2841 >
2842 > /**
2843 > * The ID of the elicitation, which must be unique within the context of the server.
2844 > * The client MUST treat this ID as an opaque value.
2845 > */
2846 > elicitationId: string;
2847 >
2848 > /**
2849 > * The URL that the user should navigate to.
2850 > *
2851 > * @format uri
2852 > */
2853 > url: string;
2854 > }
2855 >
2856 > /**
2857 > * The parameters for a request to elicit additional information from the user via the client.
2858 > *
2859 > * @category `elicitation/create`
2860 > */
2861 > export type ElicitRequestParams =
2862 > | ElicitRequestFormParams
2863 > | ElicitRequestURLParams;
2864 >
2865 > /**
2866 > * A request from the server to elicit additional information from the user via the client.
2867 > *
2868 > * @example Elicitation request
2869 > * {@includeCode ./examples/ElicitRequest/elicitation-request.json}
2870 > *
2871 > * @category `elicitation/create`
2872 > */
2873 > export interface ElicitRequest extends JSONRPCRequest {
2874 > method: "elicitation/create";
2875 > params: ElicitRequestParams;
2876 > }
2877 >
2878 > /**
2879 > * Restricted schema definitions that only allow primitive types
2880 > * without nested objects or arrays.
2881 > *
2882 > * @category `elicitation/create`
2883 > */
2884 > export type PrimitiveSchemaDefinition =
2885 > | StringSchema
2886 > | NumberSchema
2887 > | BooleanSchema
2888 > | EnumSchema;
2889 >
2890 > /**
2891 > * @example Email input schema
2892 > * {@includeCode ./examples/StringSchema/email-input-schema.json}
2893 > *
2894 > * @category `elicitation/create`
2895 > */
2896 > export interface StringSchema {
2897 > type: "string";
2898 > title?: string;
2899 > description?: string;
2900 > minLength?: number;
2901 > maxLength?: number;
2902 > format?: "email" | "uri" | "date" | "date-time";
2903 > default?: string;
2904 > }
2905 >
2906 > /**
2907 > * @example Number input schema
2908 > * {@includeCode ./examples/NumberSchema/number-input-schema.json}
2909 > *
2910 > * @category `elicitation/create`
2911 > */
2912 > export interface NumberSchema {
2913 > type: "number" | "integer";
2914 > title?: string;
2915 > description?: string;
2916 > minimum?: number;
2917 > maximum?: number;
2918 > default?: number;
2919 > }
2920 >
2921 > /**
2922 > * @example Boolean input schema
2923 > * {@includeCode ./examples/BooleanSchema/boolean-input-schema.json}
2924 > *
2925 > * @category `elicitation/create`
2926 > */
2927 > export interface BooleanSchema {
2928 > type: "boolean";
2929 > title?: string;
2930 > description?: string;
2931 > default?: boolean;
2932 > }
2933 >
2934 > /**
2935 > * Schema for single-selection enumeration without display titles for options.
2936 > *
2937 > * @example Color select schema
2938 > * {@includeCode ./examples/UntitledSingleSelectEnumSchema/color-select-schema.json}
2939 > *
2940 > * @category `elicitation/create`
2941 > */
2942 > export interface UntitledSingleSelectEnumSchema {
2943 > type: "string";
2944 > /**
2945 > * Optional title for the enum field.
2946 > */
2947 > title?: string;
2948 > /**
2949 > * Optional description for the enum field.
2950 > */
2951 > description?: string;
2952 > /**
2953 > * Array of enum values to choose from.
2954 > */
2955 > enum: string[];
2956 > /**
2957 > * Optional default value.
2958 > */
2959 > default?: string;
2960 > }
2961 >
2962 > /**
2963 > * Schema for single-selection enumeration with display titles for each option.
2964 > *
2965 > * @example Titled color select schema
2966 > * {@includeCode ./examples/TitledSingleSelectEnumSchema/titled-color-select-schema.json}
2967 > *
2968 > * @category `elicitation/create`
2969 > */
2970 > export interface TitledSingleSelectEnumSchema {
2971 > type: "string";
2972 > /**
2973 > * Optional title for the enum field.
2974 > */
2975 > title?: string;
2976 > /**
2977 > * Optional description for the enum field.
2978 > */
2979 > description?: string;
2980 > /**
2981 > * Array of enum options with values and display labels.
2982 > */
2983 > oneOf: Array<{
2984 > /**
2985 > * The enum value.
2986 > */
2987 > const: string;
2988 > /**
2989 > * Display label for this option.
2990 > */
2991 > title: string;
2992 > }>;
2993 > /**
2994 > * Optional default value.
2995 > */
2996 > default?: string;
2997 > }
2998 >
2999 > /**
3000 > * @category `elicitation/create`
3001 > */
3002 > // Combined single selection enumeration
3003 > export type SingleSelectEnumSchema =
3004 > | UntitledSingleSelectEnumSchema
3005 > | TitledSingleSelectEnumSchema;
3006 >
3007 > /**
3008 > * Schema for multiple-selection enumeration without display titles for options.
3009 > *
3010 > * @example Color multi-select schema
3011 > * {@includeCode ./examples/UntitledMultiSelectEnumSchema/color-multi-select-schema.json}
3012 > *
3013 > * @category `elicitation/create`
3014 > */
3015 > export interface UntitledMultiSelectEnumSchema {
3016 > type: "array";
3017 > /**
3018 > * Optional title for the enum field.
3019 > */
3020 > title?: string;
3021 > /**
3022 > * Optional description for the enum field.
3023 > */
3024 > description?: string;
3025 > /**
3026 > * Minimum number of items to select.
3027 > */
3028 > minItems?: number;
3029 > /**
3030 > * Maximum number of items to select.
3031 > */
3032 > maxItems?: number;
3033 > /**
3034 > * Schema for the array items.
3035 > */
3036 > items: {
3037 > type: "string";
3038 > /**
3039 > * Array of enum values to choose from.
3040 > */
3041 > enum: string[];
3042 > };
3043 > /**
3044 > * Optional default value.
3045 > */
3046 > default?: string[];
3047 > }
3048 >
3049 > /**
3050 > * Schema for multiple-selection enumeration with display titles for each option.
3051 > *
3052 > * @example Titled color multi-select schema
3053 > * {@includeCode ./examples/TitledMultiSelectEnumSchema/titled-color-multi-select-schema.json}
3054 > *
3055 > * @category `elicitation/create`
3056 > */
3057 > export interface TitledMultiSelectEnumSchema {
3058 > type: "array";
3059 > /**
3060 > * Optional title for the enum field.
3061 > */
3062 > title?: string;
3063 > /**
3064 > * Optional description for the enum field.
3065 > */
3066 > description?: string;
3067 > /**
3068 > * Minimum number of items to select.
3069 > */
3070 > minItems?: number;
3071 > /**
3072 > * Maximum number of items to select.
3073 > */
3074 > maxItems?: number;
3075 > /**
3076 > * Schema for array items with enum options and display labels.
3077 > */
3078 > items: {
3079 > /**
3080 > * Array of enum options with values and display labels.
3081 > */
3082 > anyOf: Array<{
3083 > /**
3084 > * The constant enum value.
3085 > */
3086 > const: string;
3087 > /**
3088 > * Display title for this option.
3089 > */
3090 > title: string;
3091 > }>;
3092 > };
3093 > /**
3094 > * Optional default value.
3095 > */
3096 > default?: string[];
3097 > }
3098 >
3099 > /**
3100 > * @category `elicitation/create`
3101 > */
3102 > // Combined multiple selection enumeration
3103 > export type MultiSelectEnumSchema =
3104 > | UntitledMultiSelectEnumSchema
3105 > | TitledMultiSelectEnumSchema;
3106 >
3107 > /**
3108 > * Use {@link TitledSingleSelectEnumSchema} instead.
3109 > * This interface will be removed in a future version.
3110 > *
3111 > * @category `elicitation/create`
3112 > */
3113 > export interface LegacyTitledEnumSchema {
3114 > type: "string";
3115 > title?: string;
3116 > description?: string;
3117 > enum: string[];
3118 > /**
3119 > * (Legacy) Display names for enum values.
3120 > * Non-standard according to JSON schema 2020-12.
3121 > */
3122 > enumNames?: string[];
3123 > default?: string;
3124 > }
3125 >
3126 > /**
3127 > * @category `elicitation/create`
3128 > */
3129 > // Union type for all enum schemas
3130 > export type EnumSchema =
3131 > | SingleSelectEnumSchema
3132 > | MultiSelectEnumSchema
3133 > | LegacyTitledEnumSchema;
3134 >
3135 > /**
3136 > * The result returned by the client for an {@link ElicitRequest | elicitation/create} request.
3137 > *
3138 > * @example Input single field
3139 > * {@includeCode ./examples/ElicitResult/input-single-field.json}
3140 > *
3141 > * @example Input multiple fields
3142 > * {@includeCode ./examples/ElicitResult/input-multiple-fields.json}
3143 > *
3144 > * @example Accept URL mode (no content)
3145 > * {@includeCode ./examples/ElicitResult/accept-url-mode-no-content.json}
3146 > *
3147 > * @category `elicitation/create`
3148 > */
3149 > export interface ElicitResult extends Result {
3150 > /**
3151 > * The user action in response to the elicitation.
3152 > * - `"accept"`: User submitted the form/confirmed the action
3153 > * - `"decline"`: User explicitly declined the action
3154 > * - `"cancel"`: User dismissed without making an explicit choice
3155 > */
3156 > action: "accept" | "decline" | "cancel";
3157 >
3158 > /**
3159 > * The submitted form data, only present when action is `"accept"` and mode was `"form"`.
3160 > * Contains values matching the requested schema.
3161 > * Omitted for out-of-band mode responses.
3162 > */
3163 > content?: { [key: string]: string | number | boolean | string[] };
3164 > }
3165 >
3166 > /**
3167 > * A successful response from the client for a {@link ElicitRequest | elicitation/create} request.
3168 > *
3169 > * @example Elicitation result response
3170 > * {@includeCode ./examples/ElicitResultResponse/elicitation-result-response.json}
3171 > *
3172 > * @category `elicitation/create`
3173 > */
3174 > export interface ElicitResultResponse extends JSONRPCResultResponse {
3175 > result: ElicitResult;
3176 > }
3177 >
3178 > /**
3179 > * An optional notification from the server to the client, informing it of a completion of a out-of-band elicitation request.
3180 > *
3181 > * @example Elicitation complete
3182 > * {@includeCode ./examples/ElicitationCompleteNotification/elicitation-complete.json}
3183 > *
3184 > * @category `notifications/elicitation/complete`
3185 > */
3186 > export interface ElicitationCompleteNotification extends JSONRPCNotification {
3187 > method: "notifications/elicitation/complete";
3188 > params: {
3189 > /**
3190 > * The ID of the elicitation that completed.
3191 > */
3192 > elicitationId: string;
3193 > };
3194 > }
3195 >
3196 > /* Client messages */
3197 > /** @internal */
3198 > export type ClientRequest =
3199 > | PingRequest
3200 > | InitializeRequest
3201 > | CompleteRequest
3202 > | SetLevelRequest
3203 > | GetPromptRequest
3204 > | ListPromptsRequest
3205 > | ListResourcesRequest
3206 > | ListResourceTemplatesRequest
3207 > | ReadResourceRequest
3208 > | SubscribeRequest
3209 > | UnsubscribeRequest
3210 > | CallToolRequest
3211 > | ListToolsRequest
3212 > | GetTaskRequest
3213 > | GetTaskPayloadRequest
3214 > | ListTasksRequest
3215 > | CancelTaskRequest;
3216 >
3217 > /** @internal */
3218 > export type ClientNotification =
3219 > | CancelledNotification
3220 > | ProgressNotification
3221 > | InitializedNotification
3222 > | RootsListChangedNotification
3223 > | TaskStatusNotification;
3224 >
3225 > /** @internal */
3226 > export type ClientResult =
3227 > | EmptyResult
3228 > | CreateMessageResult
3229 > | ListRootsResult
3230 > | ElicitResult
3231 > | GetTaskResult
3232 > | GetTaskPayloadResult
3233 > | ListTasksResult
3234 > | CancelTaskResult;
3235 >
3236 > /* Server messages */
3237 > /** @internal */
3238 > export type ServerRequest =
3239 > | PingRequest
3240 > | CreateMessageRequest
3241 > | ListRootsRequest
3242 > | ElicitRequest
3243 > | GetTaskRequest
3244 > | GetTaskPayloadRequest
3245 > | ListTasksRequest
3246 > | CancelTaskRequest;
3247 >
3248 > /** @internal */
3249 > export type ServerNotification =
3250 > | CancelledNotification
3251 > | ProgressNotification
3252 > | LoggingMessageNotification
3253 > | ResourceUpdatedNotification
3254 > | ResourceListChangedNotification
3255 > | ToolListChangedNotification
3256 > | PromptListChangedNotification
3257 > | ElicitationCompleteNotification
3258 > | TaskStatusNotification;
3259 >
3260 > /** @internal */
3261 > export type ServerResult =
3262 > | EmptyResult
3263 > | InitializeResult
3264 > | CompleteResult
3265 > | GetPromptResult
3266 > | ListPromptsResult
3267 > | ListResourceTemplatesResult
3268 > | ListResourcesResult
3269 > | ReadResourceResult
3270 > | CallToolResult
3271 > | CreateTaskResult
3272 > | ListToolsResult
3273 > | GetTaskResult
3274 > | GetTaskPayloadResult
3275 > | ListTasksResult
3276 > | CancelTaskResult;
3277 > }
src/vs/workbench/api/common/extHostTypes.ts 2894 covered LOC · 270 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostTypes.ts
2 > * Copyright (c) Microsoft 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 * as vscode from 'vscode';
7 > import { asArray } from '../../../base/common/arrays.js';
8 > import { encodeBase64, VSBuffer } from '../../../base/common/buffer.js';
9 > import { illegalArgument, SerializedError } from '../../../base/common/errors.js';
10 > import { IRelativePattern } from '../../../base/common/glob.js';
11 > import { MarshalledId } from '../../../base/common/marshallingIds.js';
12 > import { Mimes } from '../../../base/common/mime.js';
13 > import { nextCharLength } from '../../../base/common/strings.js';
14 > import { isNumber, isObject, isString, isStringArray } from '../../../base/common/types.js';
15 > import { isUriComponents, URI } from '../../../base/common/uri.js';
16 > import { generateUuid } from '../../../base/common/uuid.js';
17 > import { TextEditorSelectionSource } from '../../../platform/editor/common/editor.js';
18 > import { ExtensionIdentifier, IExtensionDescription } from '../../../platform/extensions/common/extensions.js';
19 > import { FileSystemProviderErrorCode, markAsFileSystemProviderError } from '../../../platform/files/common/files.js';
20 > import { RemoteAuthorityResolverErrorCode } from '../../../platform/remote/common/remoteAuthorityResolver.js';
21 > import { IRelativePatternDto } from './extHost.protocol.js';
22 > import { CodeActionKind } from './extHostTypes/codeActionKind.js';
23 > import { Diagnostic } from './extHostTypes/diagnostic.js';
24 > import { es5ClassCompat } from './extHostTypes/es5ClassCompat.js';
25 > import { Location } from './extHostTypes/location.js';
26 > import { MarkdownString } from './extHostTypes/markdownString.js';
27 > import { Position } from './extHostTypes/position.js';
28 > import { Range } from './extHostTypes/range.js';
29 > import { SnippetString } from './extHostTypes/snippetString.js';
30 > import { SymbolKind, SymbolTag } from './extHostTypes/symbolInformation.js';
31 > import { TextEdit } from './extHostTypes/textEdit.js';
32 > import { WorkspaceEdit } from './extHostTypes/workspaceEdit.js';
33 > import { HookTypeValue } from '../../contrib/chat/common/promptSyntax/hookTypes.js';
34 >
35 > export { CodeActionKind } from './extHostTypes/codeActionKind.js';
36 > export {
37 > Diagnostic, DiagnosticRelatedInformation,
38 > DiagnosticSeverity, DiagnosticTag
39 > } from './extHostTypes/diagnostic.js';
40 > export { Location } from './extHostTypes/location.js';
41 > export { MarkdownString } from './extHostTypes/markdownString.js';
42 > export { NotebookCellData, NotebookCellKind, NotebookCellOutput, NotebookCellOutputItem, NotebookData, NotebookEdit, NotebookRange } from './extHostTypes/notebooks.js';
43 > export { Position } from './extHostTypes/position.js';
44 > export { Range } from './extHostTypes/range.js';
45 > export { Selection } from './extHostTypes/selection.js';
46 > export { SnippetString } from './extHostTypes/snippetString.js';
47 > export { SnippetTextEdit } from './extHostTypes/snippetTextEdit.js';
48 > export { SymbolInformation, SymbolKind, SymbolTag } from './extHostTypes/symbolInformation.js';
49 > export { EndOfLine, TextEdit } from './extHostTypes/textEdit.js';
50 > export { FileEditType, WorkspaceEdit } from './extHostTypes/workspaceEdit.js';
51 >
52 > export enum TerminalOutputAnchor {
53 > Top = 0,
54 > Bottom = 1
55 > }
56 >
57 > export enum TerminalQuickFixType {
58 > TerminalCommand = 0,
59 > Opener = 1,
60 > Command = 3
61 > }
62 >
63 > @es5ClassCompat
64 > export class Disposable {
65 >
66 > static from(...inDisposables: { dispose(): any }[]): Disposable {
67 > let disposables: ReadonlyArray<{ dispose(): any }> | undefined = inDisposables;
68 > return new Disposable(function () {
69 > if (disposables) {
70 > for (const disposable of disposables) {
71 > if (disposable && typeof disposable.dispose === 'function') {
72 > disposable.dispose();
73 > }
74 > }
75 > disposables = undefined;
76 > }
77 > });
78 > }
79 >
80 > #callOnDispose?: () => any;
81 >
82 > constructor(callOnDispose: () => any) {
83 this.#callOnDispose = callOnDispose;
84 }
86 > dispose(): any {
87 if (typeof this.#callOnDispose === 'function') {
88 this.#callOnDispose();
90 }
91 }
93 >
94 > const validateConnectionToken = (connectionToken: string) => {
95 if (typeof connectionToken !== 'string' || connectionToken.length === 0 || !/^[0-9A-Za-z_\-]+$/.test(connectionToken)) {
96 throw illegalArgument('connectionToken');
97 }
98 };
100 >
101 > export class ResolvedAuthority {
102 > public static isResolvedAuthority(resolvedAuthority: any): resolvedAuthority is ResolvedAuthority {
103 return resolvedAuthority
104 && typeof resolvedAuthority === 'object'
107 && (resolvedAuthority.connectionToken === undefined || typeof resolvedAuthority.connectionToken === 'string');
108 }
110 > readonly host: string;
111 > readonly port: number;
112 > readonly connectionToken: string | undefined;
113 >
114 > constructor(host: string, port: number, connectionToken?: string) {
115 if (typeof host !== 'string' || host.length === 0) {
116 throw illegalArgument('host');
126 this.connectionToken = connectionToken;
127 }
128 > } extHostTypes.ts
129 >
130 >
131 > export class ManagedResolvedAuthority {
132 >
133 > public static isManagedResolvedAuthority(resolvedAuthority: any): resolvedAuthority is ManagedResolvedAuthority {
134 > return resolvedAuthority
135 > && typeof resolvedAuthority === 'object'
136 > && typeof resolvedAuthority.makeConnection === 'function'
137 > && (resolvedAuthority.connectionToken === undefined || typeof resolvedAuthority.connectionToken === 'string');
138 > }
139 >
140 > constructor(public readonly makeConnection: () => Thenable<vscode.ManagedMessagePassing>, public readonly connectionToken?: string) {
141 if (typeof connectionToken !== 'undefined') {
142 validateConnectionToken(connectionToken);
143 }
144 }
145 > } extHostTypes.ts
146 >
147 > export class RemoteAuthorityResolverError extends Error {
148 >
149 > static NotAvailable(message?: string, handled?: boolean): RemoteAuthorityResolverError {
150 return new RemoteAuthorityResolverError(message, RemoteAuthorityResolverErrorCode.NotAvailable, handled);
151 }
153 > static TemporarilyNotAvailable(message?: string): RemoteAuthorityResolverError {
154 return new RemoteAuthorityResolverError(message, RemoteAuthorityResolverErrorCode.TemporarilyNotAvailable);
155 }
157 > public readonly _message: string | undefined;
158 > public readonly _code: RemoteAuthorityResolverErrorCode;
159 > public readonly _detail: unknown;
160 >
161 > constructor(message?: string, code: RemoteAuthorityResolverErrorCode = RemoteAuthorityResolverErrorCode.Unknown, detail?: unknown) {
162 super(message);
163
170 Object.setPrototypeOf(this, RemoteAuthorityResolverError.prototype);
171 }
172 > } extHostTypes.ts
173 >
174 > export enum EnvironmentVariableMutatorType {
175 > Replace = 1,
176 > Append = 2,
177 > Prepend = 3
178 > }
179 >
180 > @es5ClassCompat
181 > export class Hover {
182 >
183 > public contents: (vscode.MarkdownString | vscode.MarkedString)[];
184 > public range: Range | undefined;
185 >
186 > constructor(
187 contents: vscode.MarkdownString | vscode.MarkedString | (vscode.MarkdownString | vscode.MarkedString)[],
188 range?: Range
198 this.range = range;
199 }
200 > } extHostTypes.ts
201 >
202 > @es5ClassCompat
203 > export class VerboseHover extends Hover {
204 >
205 > public canIncreaseVerbosity: boolean | undefined;
206 > public canDecreaseVerbosity: boolean | undefined;
207 >
208 > constructor(
209 contents: vscode.MarkdownString | vscode.MarkedString | (vscode.MarkdownString | vscode.MarkedString)[],
210 range?: Range,
216 this.canDecreaseVerbosity = canDecreaseVerbosity;
217 }
218 > } extHostTypes.ts
219 >
220 > export enum HoverVerbosityAction {
221 > Increase = 0,
222 > Decrease = 1
223 > }
224 >
225 > export enum DocumentHighlightKind {
226 > Text = 0,
227 > Read = 1,
228 > Write = 2
229 > }
230 >
231 > @es5ClassCompat
232 > export class DocumentHighlight {
233 >
234 > range: Range;
235 > kind: DocumentHighlightKind;
236 >
237 > constructor(range: Range, kind: DocumentHighlightKind = DocumentHighlightKind.Text) {
238 this.range = range;
239 this.kind = kind;
240 }
242 > toJSON(): any {
243 return {
244 range: this.range,
246 };
247 }
248 > } extHostTypes.ts
249 >
250 > @es5ClassCompat
251 > export class MultiDocumentHighlight {
252 >
253 > uri: URI;
254 > highlights: DocumentHighlight[];
255 >
256 > constructor(uri: URI, highlights: DocumentHighlight[]) {
257 this.uri = uri;
258 this.highlights = highlights;
259 }
261 > toJSON(): any {
262 return {
263 uri: this.uri,
265 };
266 }
267 > } extHostTypes.ts
268 >
269 > @es5ClassCompat
270 > export class DocumentSymbol {
271 >
272 > static validate(candidate: DocumentSymbol): void {
273 if (!candidate.name) {
274 throw new Error('name must not be falsy');
279 candidate.children?.forEach(DocumentSymbol.validate);
280 }
282 > name: string;
283 > detail: string;
284 > kind: SymbolKind;
285 > tags?: SymbolTag[];
286 > range: Range;
287 > selectionRange: Range;
288 > children: DocumentSymbol[];
289 >
290 > constructor(name: string, detail: string, kind: SymbolKind, range: Range, selectionRange: Range) {
291 this.name = name;
292 this.detail = detail;
298 DocumentSymbol.validate(this);
299 }
300 > } extHostTypes.ts
301 >
302 >
303 > export enum CodeActionTriggerKind {
304 > Invoke = 1,
305 > Automatic = 2,
306 > }
307 >
308 > @es5ClassCompat
309 > export class CodeAction {
310 > title: string;
311 >
312 > command?: vscode.Command;
313 >
314 > edit?: WorkspaceEdit;
315 >
316 > diagnostics?: Diagnostic[];
317 >
318 > kind?: CodeActionKind;
319 >
320 > isPreferred?: boolean;
321 >
322 > constructor(title: string, kind?: CodeActionKind) {
323 this.title = title;
324 this.kind = kind;
325 }
326 > } extHostTypes.ts
327 >
328 > @es5ClassCompat
329 > export class SelectionRange {
330 >
331 > range: Range;
332 > parent?: SelectionRange;
333 >
334 > constructor(range: Range, parent?: SelectionRange) {
335 this.range = range;
336 this.parent = parent;
340 }
341 }
342 > } extHostTypes.ts
343 >
344 > export class CallHierarchyItem {
345 >
346 > _sessionId?: string;
347 > _itemId?: string;
348 >
349 > kind: SymbolKind;
350 > tags?: SymbolTag[];
351 > name: string;
352 > detail?: string;
353 > uri: URI;
354 > range: Range;
355 > selectionRange: Range;
356 >
357 > constructor(kind: SymbolKind, name: string, detail: string, uri: URI, range: Range, selectionRange: Range) {
358 this.kind = kind;
359 this.name = name;
363 this.selectionRange = selectionRange;
364 }
365 > } extHostTypes.ts
366 >
367 > export class CallHierarchyIncomingCall {
368 >
369 > from: vscode.CallHierarchyItem;
370 > fromRanges: vscode.Range[];
371 >
372 > constructor(item: vscode.CallHierarchyItem, fromRanges: vscode.Range[]) {
373 this.fromRanges = fromRanges;
374 this.from = item;
375 }
376 > } extHostTypes.ts
377 > export class CallHierarchyOutgoingCall {
378 >
379 > to: vscode.CallHierarchyItem;
380 > fromRanges: vscode.Range[];
381 >
382 > constructor(item: vscode.CallHierarchyItem, fromRanges: vscode.Range[]) {
383 this.fromRanges = fromRanges;
384 this.to = item;
385 }
386 > } extHostTypes.ts
387 >
388 > export enum LanguageStatusSeverity {
389 > Information = 0,
390 > Warning = 1,
391 > Error = 2
392 > }
393 >
394 >
395 > @es5ClassCompat
396 > export class CodeLens {
397 >
398 > range: Range;
399 >
400 > command: vscode.Command | undefined;
401 >
402 > constructor(range: Range, command?: vscode.Command) {
403 this.range = range;
404 this.command = command;
405 }
407 > get isResolved(): boolean {
408 return !!this.command;
409 }
410 > } extHostTypes.ts
411 >
412 > @es5ClassCompat
413 > export class ParameterInformation {
414 >
415 > label: string | [number, number];
416 > documentation?: string | vscode.MarkdownString;
417 >
418 > constructor(label: string | [number, number], documentation?: string | vscode.MarkdownString) {
419 this.label = label;
420 this.documentation = documentation;
421 }
422 > } extHostTypes.ts
423 >
424 > @es5ClassCompat
425 > export class SignatureInformation {
426 >
427 > label: string;
428 > documentation?: string | vscode.MarkdownString;
429 > parameters: ParameterInformation[];
430 > activeParameter?: number;
431 >
432 > constructor(label: string, documentation?: string | vscode.MarkdownString) {
433 this.label = label;
434 this.documentation = documentation;
435 this.parameters = [];
436 }
437 > } extHostTypes.ts
438 >
439 > @es5ClassCompat
440 > export class SignatureHelp {
441 >
442 > signatures: SignatureInformation[];
443 > activeSignature: number = 0;
444 > activeParameter: number = 0;
445 >
446 > constructor() {
447 this.signatures = [];
448 }
449 > } extHostTypes.ts
450 >
451 > export enum SignatureHelpTriggerKind {
452 > Invoke = 1,
453 > TriggerCharacter = 2,
454 > ContentChange = 3,
455 > }
456 >
457 >
458 > export enum InlayHintKind {
459 > Type = 1,
460 > Parameter = 2,
461 > }
462 >
463 > @es5ClassCompat
464 > export class InlayHintLabelPart {
465 >
466 > value: string;
467 > tooltip?: string | vscode.MarkdownString;
468 > location?: Location;
469 > command?: vscode.Command;
470 >
471 > constructor(value: string) {
472 this.value = value;
473 }
474 > } extHostTypes.ts
475 >
476 > @es5ClassCompat
477 > export class InlayHint implements vscode.InlayHint {
478 >
479 > label: string | InlayHintLabelPart[];
480 > tooltip?: string | vscode.MarkdownString;
481 > position: Position;
482 > textEdits?: TextEdit[];
483 > kind?: vscode.InlayHintKind;
484 > paddingLeft?: boolean;
485 > paddingRight?: boolean;
486 >
487 > constructor(position: Position, label: string | InlayHintLabelPart[], kind?: vscode.InlayHintKind) {
488 this.position = position;
489 this.label = label;
490 this.kind = kind;
491 }
492 > } extHostTypes.ts
493 >
494 > export enum CompletionTriggerKind {
495 > Invoke = 0,
496 > TriggerCharacter = 1,
497 > TriggerForIncompleteCompletions = 2
498 > }
499 >
500 > export interface CompletionContext {
501 > readonly triggerKind: CompletionTriggerKind;
502 > readonly triggerCharacter: string | undefined;
503 > }
504 >
505 > export enum CompletionItemKind {
506 > Text = 0,
507 > Method = 1,
508 > Function = 2,
509 > Constructor = 3,
510 > Field = 4,
511 > Variable = 5,
512 > Class = 6,
513 > Interface = 7,
514 > Module = 8,
515 > Property = 9,
516 > Unit = 10,
517 > Value = 11,
518 > Enum = 12,
519 > Keyword = 13,
520 > Snippet = 14,
521 > Color = 15,
522 > File = 16,
523 > Reference = 17,
524 > Folder = 18,
525 > EnumMember = 19,
526 > Constant = 20,
527 > Struct = 21,
528 > Event = 22,
529 > Operator = 23,
530 > TypeParameter = 24,
531 > User = 25,
532 > Issue = 26
533 > }
534 >
535 > export enum CompletionItemTag {
536 > Deprecated = 1,
537 > }
538 >
539 > export interface CompletionItemLabel {
540 > label: string;
541 > detail?: string;
542 > description?: string;
543 > }
544 >
545 > @es5ClassCompat
546 > export class CompletionItem implements vscode.CompletionItem {
547 >
548 > label: string | CompletionItemLabel;
549 > kind?: CompletionItemKind;
550 > tags?: CompletionItemTag[];
551 > detail?: string;
552 > documentation?: string | vscode.MarkdownString;
553 > sortText?: string;
554 > filterText?: string;
555 > preselect?: boolean;
556 > insertText?: string | SnippetString;
557 > keepWhitespace?: boolean;
558 > range?: Range | { inserting: Range; replacing: Range };
559 > commitCharacters?: string[];
560 > textEdit?: TextEdit;
561 > additionalTextEdits?: TextEdit[];
562 > command?: vscode.Command;
563 >
564 > constructor(label: string | CompletionItemLabel, kind?: CompletionItemKind) {
565 this.label = label;
566 this.kind = kind;
567 }
569 > toJSON(): any {
570 return {
571 label: this.label,
580 };
581 }
582 > } extHostTypes.ts
583 >
584 > @es5ClassCompat
585 > export class CompletionList {
586 >
587 > isIncomplete?: boolean;
588 > items: vscode.CompletionItem[];
589 >
590 > constructor(items: vscode.CompletionItem[] = [], isIncomplete: boolean = false) {
591 this.items = items;
592 this.isIncomplete = isIncomplete;
593 }
594 > } extHostTypes.ts
595 >
596 > @es5ClassCompat
597 > export class InlineSuggestion implements vscode.InlineCompletionItem {
598 >
599 > filterText?: string;
600 > insertText: string;
601 > range?: Range;
602 > command?: vscode.Command;
603 >
604 > constructor(insertText: string, range?: Range, command?: vscode.Command) {
605 this.insertText = insertText;
606 this.range = range;
607 this.command = command;
608 }
609 > } extHostTypes.ts
610 >
611 > @es5ClassCompat
612 > export class InlineSuggestionList implements vscode.InlineCompletionList {
613 > items: vscode.InlineCompletionItem[];
614 >
615 > commands: (vscode.Command | { command: vscode.Command; icon: vscode.ThemeIcon })[] | undefined = undefined;
616 >
617 > suppressSuggestions: boolean | undefined = undefined;
618 >
619 > constructor(items: vscode.InlineCompletionItem[]) {
620 this.items = items;
621 }
622 > } extHostTypes.ts
623 >
624 > export interface PartialAcceptInfo {
625 > kind: PartialAcceptTriggerKind;
626 > acceptedLength: number;
627 > }
628 >
629 > export enum PartialAcceptTriggerKind {
630 > Unknown = 0,
631 > Word = 1,
632 > Line = 2,
633 > Suggest = 3,
634 > }
635 >
636 > export enum InlineCompletionEndOfLifeReasonKind {
637 > Accepted = 0,
638 > Rejected = 1,
639 > Ignored = 2,
640 > }
641 >
642 > export enum InlineCompletionDisplayLocationKind {
643 > Code = 1,
644 > Label = 2
645 > }
646 >
647 > export enum ViewColumn {
648 > Active = -1,
649 > Beside = -2,
650 > One = 1,
651 > Two = 2,
652 > Three = 3,
653 > Four = 4,
654 > Five = 5,
655 > Six = 6,
656 > Seven = 7,
657 > Eight = 8,
658 > Nine = 9
659 > }
660 >
661 > export enum StatusBarAlignment {
662 > Left = 1,
663 > Right = 2
664 > }
665 >
666 > export function asStatusBarItemIdentifier(extension: ExtensionIdentifier, id: string): string {
667 return `${ExtensionIdentifier.toKey(extension)}.${id}`;
668 }
670 > export enum TextEditorLineNumbersStyle {
671 > Off = 0,
672 > On = 1,
673 > Relative = 2,
674 > Interval = 3
675 > }
676 >
677 > export enum TextDocumentSaveReason {
678 > Manual = 1,
679 > AfterDelay = 2,
680 > FocusOut = 3
681 > }
682 >
683 > export enum TextEditorRevealType {
684 > Default = 0,
685 > InCenter = 1,
686 > InCenterIfOutsideViewport = 2,
687 > AtTop = 3
688 > }
689 >
690 > export enum TextEditorSelectionChangeKind {
691 > Keyboard = 1,
692 > Mouse = 2,
693 > Command = 3
694 > }
695 >
696 > export enum TextEditorChangeKind {
697 > Addition = 1,
698 > Deletion = 2,
699 > Modification = 3
700 > }
701 >
702 > export enum TextDocumentChangeReason {
703 > Undo = 1,
704 > Redo = 2,
705 > }
706 >
707 > /**
708 > * These values match very carefully the values of `TrackedRangeStickiness`
709 > */
710 > export enum DecorationRangeBehavior {
711 > /**
712 > * TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges
713 > */
714 > OpenOpen = 0,
715 > /**
716 > * TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges
717 > */
718 > ClosedClosed = 1,
719 > /**
720 > * TrackedRangeStickiness.GrowsOnlyWhenTypingBefore
721 > */
722 > OpenClosed = 2,
723 > /**
724 > * TrackedRangeStickiness.GrowsOnlyWhenTypingAfter
725 > */
726 > ClosedOpen = 3
727 > }
728 >
729 > export namespace TextEditorSelectionChangeKind {
730 > export function fromValue(s: TextEditorSelectionSource | string | undefined) {
731 switch (s) {
732 case 'keyboard': return TextEditorSelectionChangeKind.Keyboard;
739 return undefined;
740 }
741 > } extHostTypes.ts
742 >
743 > export enum SyntaxTokenType {
744 > Other = 0,
745 > Comment = 1,
746 > String = 2,
747 > RegEx = 3
748 > }
749 > export namespace SyntaxTokenType {
750 > export function toString(v: SyntaxTokenType | unknown): 'other' | 'comment' | 'string' | 'regex' {
751 switch (v) {
752 case SyntaxTokenType.Other: return 'other';
757 return 'other';
758 }
759 > } extHostTypes.ts
760 >
761 > @es5ClassCompat
762 > export class DocumentLink {
763 >
764 > range: Range;
765 >
766 > target?: URI;
767 >
768 > tooltip?: string;
769 >
770 > constructor(range: Range, target: URI | undefined) {
771 if (target && !(URI.isUri(target))) {
772 throw illegalArgument('target');
778 this.target = target;
779 }
780 > } extHostTypes.ts
781 >
782 > @es5ClassCompat
783 > export class Color {
784 > readonly red: number;
785 > readonly green: number;
786 > readonly blue: number;
787 > readonly alpha: number;
788 >
789 > constructor(red: number, green: number, blue: number, alpha: number) {
790 this.red = red;
791 this.green = green;
793 this.alpha = alpha;
794 }
795 > } extHostTypes.ts
796 >
797 > export type IColorFormat = string | { opaque: string; transparent: string };
798 >
799 > @es5ClassCompat
800 > export class ColorInformation {
801 > range: Range;
802 >
803 > color: Color;
804 >
805 > constructor(range: Range, color: Color) {
806 if (color && !(color instanceof Color)) {
807 throw illegalArgument('color');
813 this.color = color;
814 }
815 > } extHostTypes.ts
816 >
817 > @es5ClassCompat
818 > export class ColorPresentation {
819 > label: string;
820 > textEdit?: TextEdit;
821 > additionalTextEdits?: TextEdit[];
822 >
823 > constructor(label: string) {
824 if (!label || typeof label !== 'string') {
825 throw illegalArgument('label');
827 this.label = label;
828 }
829 > } extHostTypes.ts
830 >
831 > export enum ColorFormat {
832 > RGB = 0,
833 > HEX = 1,
834 > HSL = 2
835 > }
836 >
837 > export enum SourceControlInputBoxValidationType {
838 > Error = 0,
839 > Warning = 1,
840 > Information = 2
841 > }
842 >
843 > export enum TerminalExitReason {
844 > Unknown = 0,
845 > Shutdown = 1,
846 > Process = 2,
847 > User = 3,
848 > Extension = 4
849 > }
850 >
851 > export enum TerminalShellExecutionCommandLineConfidence {
852 > Low = 0,
853 > Medium = 1,
854 > High = 2
855 > }
856 >
857 > export enum TerminalShellType {
858 > Sh = 1,
859 > Bash = 2,
860 > Fish = 3,
861 > Csh = 4,
862 > Ksh = 5,
863 > Zsh = 6,
864 > CommandPrompt = 7,
865 > GitBash = 8,
866 > PowerShell = 9,
867 > Python = 10,
868 > Julia = 11,
869 > NuShell = 12,
870 > Node = 13,
871 > Xonsh = 14
872 > }
873 >
874 > export class TerminalLink implements vscode.TerminalLink {
875 > constructor(
876 public startIndex: number,
877 public length: number,
888 }
889 }
890 > } extHostTypes.ts
891 >
892 > export class TerminalQuickFixOpener {
893 > uri: vscode.Uri;
894 > constructor(uri: vscode.Uri) {
895 this.uri = uri;
896 }
897 > } extHostTypes.ts
898 >
899 > export class TerminalQuickFixCommand {
900 > terminalCommand: string;
901 > constructor(terminalCommand: string) {
902 this.terminalCommand = terminalCommand;
903 }
904 > } extHostTypes.ts
905 >
906 > export enum TerminalLocation {
907 > Panel = 1,
908 > Editor = 2,
909 > }
910 >
911 > export class TerminalProfile implements vscode.TerminalProfile {
912 > constructor(
913 public options: vscode.TerminalOptions | vscode.ExtensionTerminalOptions
914 ) {
917 }
918 }
919 > } extHostTypes.ts
920 >
921 > export enum TerminalCompletionItemKind {
922 > File = 0,
923 > Folder = 1,
924 > Method = 2,
925 > Alias = 3,
926 > Argument = 4,
927 > Option = 5,
928 > OptionValue = 6,
929 > Flag = 7,
930 > SymbolicLinkFile = 8,
931 > SymbolicLinkFolder = 9,
932 > ScmCommit = 10,
933 > ScmBranch = 11,
934 > ScmTag = 12,
935 > ScmStash = 13,
936 > ScmRemote = 14,
937 > PullRequest = 15,
938 > PullRequestDone = 16,
939 > }
940 >
941 > export class TerminalCompletionItem implements vscode.TerminalCompletionItem {
942 > label: string | CompletionItemLabel;
943 > replacementRange: readonly [number, number];
944 > detail?: string | undefined;
945 > documentation?: string | vscode.MarkdownString | undefined;
946 > kind?: TerminalCompletionItemKind | undefined;
947 > isFile?: boolean | undefined;
948 > isDirectory?: boolean | undefined;
949 > isKeyword?: boolean | undefined;
950 >
951 > constructor(label: string | CompletionItemLabel, replacementRange: readonly [number, number], kind?: TerminalCompletionItemKind, detail?: string, documentation?: string | vscode.MarkdownString, isFile?: boolean, isDirectory?: boolean, isKeyword?: boolean) {
952 this.label = label;
953 this.replacementRange = replacementRange;
959 this.isKeyword = isKeyword;
960 }
961 > } extHostTypes.ts
962 >
963 > /**
964 > * Represents a collection of {@link CompletionItem completion items} to be presented
965 > * in the editor.
966 > */
967 > export class TerminalCompletionList<T extends TerminalCompletionItem = TerminalCompletionItem> {
968 >
969 > /**
970 > * Resources should be shown in the completions list
971 > */
972 > resourceOptions?: TerminalCompletionResourceOptions;
973 >
974 > /**
975 > * The completion items.
976 > */
977 > items: T[];
978 >
979 > /**
980 > * Creates a new completion list.
981 > *
982 > * @param items The completion items.
983 > * @param isIncomplete The list is not complete.
984 > */
985 > constructor(items?: T[], resourceOptions?: TerminalCompletionResourceOptions) {
986 this.items = items ?? [];
987 this.resourceOptions = resourceOptions;
988 }
989 > } extHostTypes.ts
990 >
991 > export interface TerminalCompletionResourceOptions {
992 > showFiles?: boolean;
993 > showDirectories?: boolean;
994 > fileExtensions?: string[];
995 > cwd?: vscode.Uri;
996 > }
997 >
998 > export enum TaskRevealKind {
999 > Always = 1,
1000 >
1001 > Silent = 2,
1002 >
1003 > Never = 3
1004 > }
1005 >
1006 > export enum TaskEventKind {
1007 > /** Indicates a task's properties or configuration have changed */
1008 > Changed = 'changed',
1009 >
1010 > /** Indicates a task has begun executing */
1011 > ProcessStarted = 'processStarted',
1012 >
1013 > /** Indicates a task process has completed */
1014 > ProcessEnded = 'processEnded',
1015 >
1016 > /** Indicates a task was terminated, either by user action or by the system */
1017 > Terminated = 'terminated',
1018 >
1019 > /** Indicates a task has started running */
1020 > Start = 'start',
1021 >
1022 > /** Indicates a task has acquired all needed input/variables to execute */
1023 > AcquiredInput = 'acquiredInput',
1024 >
1025 > /** Indicates a dependent task has started */
1026 > DependsOnStarted = 'dependsOnStarted',
1027 >
1028 > /** Indicates a task is actively running/processing */
1029 > Active = 'active',
1030 >
1031 > /** Indicates a task is paused/waiting but not complete */
1032 > Inactive = 'inactive',
1033 >
1034 > /** Indicates a task has completed fully */
1035 > End = 'end',
1036 >
1037 > /** Indicates the task's problem matcher has started */
1038 > ProblemMatcherStarted = 'problemMatcherStarted',
1039 >
1040 > /** Indicates the task's problem matcher has ended without errors */
1041 > ProblemMatcherEnded = 'problemMatcherEnded',
1042 >
1043 > /** Indicates the task's problem matcher has ended with errors */
1044 > ProblemMatcherFoundErrors = 'problemMatcherFoundErrors'
1045 > }
1046 >
1047 >
1048 > export enum TaskPanelKind {
1049 > Shared = 1,
1050 >
1051 > Dedicated = 2,
1052 >
1053 > New = 3
1054 > }
1055 >
1056 > @es5ClassCompat
1057 > export class TaskGroup implements vscode.TaskGroup {
1058 >
1059 > isDefault: boolean | undefined;
1060 > private _id: string;
1061 >
1062 > public static Clean: TaskGroup = new TaskGroup('clean', 'Clean');
1063 >
1064 > public static Build: TaskGroup = new TaskGroup('build', 'Build');
1065 >
1066 > public static Rebuild: TaskGroup = new TaskGroup('rebuild', 'Rebuild');
1067 >
1068 > public static Test: TaskGroup = new TaskGroup('test', 'Test');
1069 >
1070 > public static from(value: string) {
1071 > switch (value) {
1072 > case 'clean':
1073 > return TaskGroup.Clean;
1074 > case 'build':
1075 > return TaskGroup.Build;
1076 > case 'rebuild':
1077 > return TaskGroup.Rebuild;
1078 > case 'test':
1079 > return TaskGroup.Test;
1080 > default:
1081 > return undefined;
1082 > }
1083 > }
1084 >
1085 > constructor(id: string, public readonly label: string) {
1086 > if (typeof id !== 'string') {
1087 throw illegalArgument('name');
1088 }
1089 > if (typeof label !== 'string') { extHostTypes.ts
1090 throw illegalArgument('name');
1091 }
1092 > this._id = id; extHostTypes.ts
1093 > }
1094 >
1095 > get id(): string {
1096 return this._id;
1097 }
1098 > } extHostTypes.ts
1099 >
1100 function computeTaskExecutionId(values: string[]): string {
1101 let id: string = '';
1105 return id;
1106 }
1108 > @es5ClassCompat
1109 > export class ProcessExecution implements vscode.ProcessExecution {
1110 >
1111 > private _process: string;
1112 > private _args: string[];
1113 > private _options: vscode.ProcessExecutionOptions | undefined;
1114 >
1115 > constructor(process: string, options?: vscode.ProcessExecutionOptions);
1116 > constructor(process: string, args: string[], options?: vscode.ProcessExecutionOptions);
1117 > constructor(process: string, varg1?: string[] | vscode.ProcessExecutionOptions, varg2?: vscode.ProcessExecutionOptions) {
1118 if (typeof process !== 'string') {
1119 throw illegalArgument('process');
1130 }
1131 }
1133 >
1134 > get process(): string {
1135 return this._process;
1136 }
1138 > set process(value: string) {
1139 if (typeof value !== 'string') {
1140 throw illegalArgument('process');
1142 this._process = value;
1143 }
1145 > get args(): string[] {
1146 return this._args;
1147 }
1149 > set args(value: string[]) {
1150 if (!Array.isArray(value)) {
1151 value = [];
1153 this._args = value;
1154 }
1156 > get options(): vscode.ProcessExecutionOptions | undefined {
1157 return this._options;
1158 }
1160 > set options(value: vscode.ProcessExecutionOptions | undefined) {
1161 this._options = value;
1162 }
1164 > public computeId(): string {
1165 const props: string[] = [];
1166 props.push('process');
1175 return computeTaskExecutionId(props);
1176 }
1177 > } extHostTypes.ts
1178 >
1179 > @es5ClassCompat
1180 > export class ShellExecution implements vscode.ShellExecution {
1181 >
1182 > private _commandLine: string | undefined;
1183 > private _command: string | vscode.ShellQuotedString | undefined;
1184 > private _args: (string | vscode.ShellQuotedString)[] = [];
1185 > private _options: vscode.ShellExecutionOptions | undefined;
1186 >
1187 > constructor(commandLine: string, options?: vscode.ShellExecutionOptions);
1188 > constructor(command: string | vscode.ShellQuotedString, args: (string | vscode.ShellQuotedString)[], options?: vscode.ShellExecutionOptions);
1189 > constructor(arg0: string | vscode.ShellQuotedString, arg1?: vscode.ShellExecutionOptions | (string | vscode.ShellQuotedString)[], arg2?: vscode.ShellExecutionOptions) {
1190 if (Array.isArray(arg1)) {
1191 if (!arg0) {
1208 }
1209 }
1211 > get commandLine(): string | undefined {
1212 return this._commandLine;
1213 }
1215 > set commandLine(value: string | undefined) {
1216 if (typeof value !== 'string') {
1217 throw illegalArgument('commandLine');
1219 this._commandLine = value;
1220 }
1222 > get command(): string | vscode.ShellQuotedString {
1223 return this._command ? this._command : '';
1224 }
1226 > set command(value: string | vscode.ShellQuotedString) {
1227 if (typeof value !== 'string' && typeof value.value !== 'string') {
1228 throw illegalArgument('command');
1230 this._command = value;
1231 }
1233 > get args(): (string | vscode.ShellQuotedString)[] {
1234 return this._args;
1235 }
1237 > set args(value: (string | vscode.ShellQuotedString)[] | undefined) {
1238 this._args = value || [];
1239 }
1241 > get options(): vscode.ShellExecutionOptions | undefined {
1242 return this._options;
1243 }
1245 > set options(value: vscode.ShellExecutionOptions | undefined) {
1246 this._options = value;
1247 }
1249 > public computeId(): string {
1250 const props: string[] = [];
1251 props.push('shell');
1263 return computeTaskExecutionId(props);
1264 }
1265 > } extHostTypes.ts
1266 >
1267 > export enum ShellQuoting {
1268 > Escape = 1,
1269 > Strong = 2,
1270 > Weak = 3
1271 > }
1272 >
1273 > export enum TaskScope {
1274 > Global = 1,
1275 > Workspace = 2
1276 > }
1277 >
1278 > export enum TaskRunOn {
1279 > Default = 1,
1280 > FolderOpen = 2,
1281 > WorktreeCreated = 3,
1282 > }
1283 >
1284 > export class CustomExecution implements vscode.CustomExecution {
1285 > private _callback: (resolvedDefinition: vscode.TaskDefinition) => Thenable<vscode.Pseudoterminal>;
1286 > constructor(callback: (resolvedDefinition: vscode.TaskDefinition) => Thenable<vscode.Pseudoterminal>) {
1287 this._callback = callback;
1288 }
1289 > public computeId(): string { extHostTypes.ts
1290 return 'customExecution' + generateUuid();
1291 }
1293 > public set callback(value: (resolvedDefinition: vscode.TaskDefinition) => Thenable<vscode.Pseudoterminal>) {
1294 this._callback = value;
1295 }
1297 > public get callback(): ((resolvedDefinition: vscode.TaskDefinition) => Thenable<vscode.Pseudoterminal>) {
1298 return this._callback;
1299 }
1300 > } extHostTypes.ts
1301 >
1302 > @es5ClassCompat
1303 > export class Task implements vscode.Task {
1304 >
1305 > private static ExtensionCallbackType: string = 'customExecution';
1306 > private static ProcessType: string = 'process';
1307 > private static ShellType: string = 'shell';
1308 > private static EmptyType: string = '$empty';
1309 >
1310 > private __id: string | undefined;
1311 > private __deprecated: boolean = false;
1312 >
1313 > private _definition: vscode.TaskDefinition;
1314 > private _scope: vscode.TaskScope.Global | vscode.TaskScope.Workspace | vscode.WorkspaceFolder | undefined;
1315 > private _name: string;
1316 > private _execution: ProcessExecution | ShellExecution | CustomExecution | undefined;
1317 > private _problemMatchers: string[];
1318 > private _hasDefinedMatchers: boolean;
1319 > private _isBackground: boolean;
1320 > private _source: string;
1321 > private _group: TaskGroup | undefined;
1322 > private _presentationOptions: vscode.TaskPresentationOptions;
1323 > private _runOptions: vscode.RunOptions;
1324 > private _detail: string | undefined;
1325 >
1326 > constructor(definition: vscode.TaskDefinition, name: string, source: string, execution?: ProcessExecution | ShellExecution | CustomExecution, problemMatchers?: string | string[]);
1327 > constructor(definition: vscode.TaskDefinition, scope: vscode.TaskScope.Global | vscode.TaskScope.Workspace | vscode.WorkspaceFolder, name: string, source: string, execution?: ProcessExecution | ShellExecution | CustomExecution, problemMatchers?: string | string[]);
1328 > constructor(definition: vscode.TaskDefinition, arg2: string | (vscode.TaskScope.Global | vscode.TaskScope.Workspace) | vscode.WorkspaceFolder, arg3: any, arg4?: any, arg5?: any, arg6?: any) {
1329 this._definition = this.definition = definition;
1330 let problemMatchers: string | string[];
1362 this._runOptions = Object.create(null);
1363 }
1365 > get _id(): string | undefined {
1366 return this.__id;
1367 }
1369 > set _id(value: string | undefined) {
1370 this.__id = value;
1371 }
1373 > get _deprecated(): boolean {
1374 return this.__deprecated;
1375 }
1377 > private clear(): void {
1378 if (this.__id === undefined) {
1379 return;
1383 this.computeDefinitionBasedOnExecution();
1384 }
1386 > private computeDefinitionBasedOnExecution(): void {
1387 if (this._execution instanceof ProcessExecution) {
1388 this._definition = {
1407 }
1408 }
1410 > get definition(): vscode.TaskDefinition {
1411 return this._definition;
1412 }
1414 > set definition(value: vscode.TaskDefinition) {
1415 if (value === undefined || value === null) {
1416 throw illegalArgument('Kind can\'t be undefined or null');
1419 this._definition = value;
1420 }
1422 > get scope(): vscode.TaskScope.Global | vscode.TaskScope.Workspace | vscode.WorkspaceFolder | undefined {
1423 return this._scope;
1424 }
1426 > set target(value: vscode.TaskScope.Global | vscode.TaskScope.Workspace | vscode.WorkspaceFolder) {
1427 this.clear();
1428 this._scope = value;
1429 }
1431 > get name(): string {
1432 return this._name;
1433 }
1435 > set name(value: string) {
1436 if (typeof value !== 'string') {
1437 throw illegalArgument('name');
1440 this._name = value;
1441 }
1443 > get execution(): ProcessExecution | ShellExecution | CustomExecution | undefined {
1444 return this._execution;
1445 }
1447 > set execution(value: ProcessExecution | ShellExecution | CustomExecution | undefined) {
1448 if (value === null) {
1449 value = undefined;
1456 }
1457 }
1459 > get problemMatchers(): string[] {
1460 return this._problemMatchers;
1461 }
1463 > set problemMatchers(value: string[]) {
1464 if (!Array.isArray(value)) {
1465 this.clear();
1473 }
1474 }
1476 > get hasDefinedMatchers(): boolean {
1477 return this._hasDefinedMatchers;
1478 }
1480 > get isBackground(): boolean {
1481 return this._isBackground;
1482 }
1484 > set isBackground(value: boolean) {
1485 if (value !== true && value !== false) {
1486 value = false;
1489 this._isBackground = value;
1490 }
1492 > get source(): string {
1493 return this._source;
1494 }
1496 > set source(value: string) {
1497 if (typeof value !== 'string' || value.length === 0) {
1498 throw illegalArgument('source must be a string of length > 0');
1501 this._source = value;
1502 }
1504 > get group(): TaskGroup | undefined {
1505 return this._group;
1506 }
1508 > set group(value: TaskGroup | undefined) {
1509 if (value === null) {
1510 value = undefined;
1513 this._group = value;
1514 }
1516 > get detail(): string | undefined {
1517 return this._detail;
1518 }
1520 > set detail(value: string | undefined) {
1521 if (value === null) {
1522 value = undefined;
1524 this._detail = value;
1525 }
1527 > get presentationOptions(): vscode.TaskPresentationOptions {
1528 return this._presentationOptions;
1529 }
1531 > set presentationOptions(value: vscode.TaskPresentationOptions) {
1532 if (value === null || value === undefined) {
1533 value = Object.create(null);
1536 this._presentationOptions = value;
1537 }
1539 > get runOptions(): vscode.RunOptions {
1540 return this._runOptions;
1541 }
1543 > set runOptions(value: vscode.RunOptions) {
1544 if (value === null || value === undefined) {
1545 value = Object.create(null);
1548 this._runOptions = value;
1549 }
1550 > } extHostTypes.ts
1551 >
1552 >
1553 > export enum ProgressLocation {
1554 > SourceControl = 1,
1555 > Window = 10,
1556 > Notification = 15
1557 > }
1558 >
1559 > export namespace ViewBadge {
1560 > export function isViewBadge(thing: any): thing is vscode.ViewBadge {
1561 const viewBadgeThing = thing as vscode.ViewBadge;
1562
1571 return true;
1572 }
1573 > } extHostTypes.ts
1574 >
1575 > @es5ClassCompat
1576 > export class TreeItem {
1577 >
1578 > label?: string | vscode.TreeItemLabel;
1579 > resourceUri?: URI;
1580 > iconPath?: string | URI | { light: string | URI; dark: string | URI } | ThemeIcon;
1581 > command?: vscode.Command;
1582 > contextValue?: string;
1583 > tooltip?: string | vscode.MarkdownString;
1584 > checkboxState?: vscode.TreeItemCheckboxState;
1585 >
1586 > static isTreeItem(thing: any, extension: IExtensionDescription): thing is TreeItem {
1587 > const treeItemThing = thing as vscode.TreeItem;
1588 >
1589 > if (treeItemThing.checkboxState !== undefined) {
1590 > const checkbox = isNumber(treeItemThing.checkboxState) ? treeItemThing.checkboxState :
1591 > isObject(treeItemThing.checkboxState) && isNumber(treeItemThing.checkboxState.state) ? treeItemThing.checkboxState.state : undefined;
1592 > const tooltip = !isNumber(treeItemThing.checkboxState) && isObject(treeItemThing.checkboxState) ? treeItemThing.checkboxState.tooltip : undefined;
1593 > if (checkbox === undefined || (checkbox !== TreeItemCheckboxState.Checked && checkbox !== TreeItemCheckboxState.Unchecked) || (tooltip !== undefined && !isString(tooltip))) {
1594 > console.log('INVALID tree item, invalid checkboxState', treeItemThing.checkboxState);
1595 > return false;
1596 > }
1597 > }
1598 >
1599 > if (thing instanceof TreeItem) {
1600 > return true;
1601 > }
1602 >
1603 > if (treeItemThing.label !== undefined && !isString(treeItemThing.label) && !(treeItemThing.label?.label)) {
1604 > console.log('INVALID tree item, invalid label', treeItemThing.label);
1605 > return false;
1606 > }
1607 > if ((treeItemThing.id !== undefined) && !isString(treeItemThing.id)) {
1608 > console.log('INVALID tree item, invalid id', treeItemThing.id);
1609 > return false;
1610 > }
1611 > if ((treeItemThing.iconPath !== undefined) && !isString(treeItemThing.iconPath) && !URI.isUri(treeItemThing.iconPath) && (!treeItemThing.iconPath || !isString((treeItemThing.iconPath as vscode.ThemeIcon).id))) {
1612 > const asLightAndDarkThing = treeItemThing.iconPath as { light: string | URI; dark: string | URI } | null;
1613 > if (!asLightAndDarkThing || (!isString(asLightAndDarkThing.light) && !URI.isUri(asLightAndDarkThing.light) && !isString(asLightAndDarkThing.dark) && !URI.isUri(asLightAndDarkThing.dark))) {
1614 > console.log('INVALID tree item, invalid iconPath', treeItemThing.iconPath);
1615 > return false;
1616 > }
1617 > }
1618 > if ((treeItemThing.description !== undefined) && !isString(treeItemThing.description) && (typeof treeItemThing.description !== 'boolean')) {
1619 > console.log('INVALID tree item, invalid description', treeItemThing.description);
1620 > return false;
1621 > }
1622 > if ((treeItemThing.resourceUri !== undefined) && !URI.isUri(treeItemThing.resourceUri)) {
1623 > console.log('INVALID tree item, invalid resourceUri', treeItemThing.resourceUri);
1624 > return false;
1625 > }
1626 > if ((treeItemThing.tooltip !== undefined) && !isString(treeItemThing.tooltip) && !(treeItemThing.tooltip instanceof MarkdownString)) {
1627 > console.log('INVALID tree item, invalid tooltip', treeItemThing.tooltip);
1628 > return false;
1629 > }
1630 > if ((treeItemThing.command !== undefined) && !treeItemThing.command.command) {
1631 > console.log('INVALID tree item, invalid command', treeItemThing.command);
1632 > return false;
1633 > }
1634 > if ((treeItemThing.collapsibleState !== undefined) && (treeItemThing.collapsibleState < TreeItemCollapsibleState.None) && (treeItemThing.collapsibleState > TreeItemCollapsibleState.Expanded)) {
1635 > console.log('INVALID tree item, invalid collapsibleState', treeItemThing.collapsibleState);
1636 > return false;
1637 > }
1638 > if ((treeItemThing.contextValue !== undefined) && !isString(treeItemThing.contextValue)) {
1639 > console.log('INVALID tree item, invalid contextValue', treeItemThing.contextValue);
1640 > return false;
1641 > }
1642 > if ((treeItemThing.accessibilityInformation !== undefined) && !treeItemThing.accessibilityInformation?.label) {
1643 > console.log('INVALID tree item, invalid accessibilityInformation', treeItemThing.accessibilityInformation);
1644 > return false;
1645 > }
1646 >
1647 > return true;
1648 > }
1649 >
1650 > constructor(label: string | vscode.TreeItemLabel, collapsibleState?: vscode.TreeItemCollapsibleState);
1651 > constructor(resourceUri: URI, collapsibleState?: vscode.TreeItemCollapsibleState);
1652 > constructor(arg1: string | vscode.TreeItemLabel | URI, public collapsibleState: vscode.TreeItemCollapsibleState = TreeItemCollapsibleState.None) {
1653 if (URI.isUri(arg1)) {
1654 this.resourceUri = arg1;
1657 }
1658 }
1660 > }
1661 >
1662 > export enum TreeItemCollapsibleState {
1663 > None = 0,
1664 > Collapsed = 1,
1665 > Expanded = 2
1666 > }
1667 >
1668 > export enum TreeItemCheckboxState {
1669 > Unchecked = 0,
1670 > Checked = 1
1671 > }
1672 >
1673 > @es5ClassCompat
1674 > export class DataTransferItem implements vscode.DataTransferItem {
1675 >
1676 > async asString(): Promise<string> {
1677 > return typeof this.value === 'string' ? this.value : JSON.stringify(this.value);
1678 > }
1679 >
1680 > asFile(): undefined | vscode.DataTransferFile {
1681 return undefined;
1682 }
1684 > constructor(
1685 public readonly value: any,
1686 ) { }
1687 > } extHostTypes.ts
1688 >
1689 > /**
1690 > * A data transfer item that has been created by VS Code instead of by a extension.
1691 > *
1692 > * Intentionally not exported to extensions.
1693 > */
1694 > export class InternalDataTransferItem extends DataTransferItem { }
1695 >
1696 > /**
1697 > * A data transfer item for a file.
1698 > *
1699 > * Intentionally not exported to extensions as only we can create these.
1700 > */
1701 > export class InternalFileDataTransferItem extends InternalDataTransferItem {
1702 >
1703 > readonly #file: vscode.DataTransferFile;
1704 >
1705 > constructor(file: vscode.DataTransferFile) {
1706 super('');
1707 this.#file = file;
1708 }
1710 > override asFile() {
1711 return this.#file;
1712 }
1713 > } extHostTypes.ts
1714 >
1715 > /**
1716 > * Intentionally not exported to extensions
1717 > */
1718 > export class DataTransferFile implements vscode.DataTransferFile {
1719 >
1720 > public readonly name: string;
1721 > public readonly uri: vscode.Uri | undefined;
1722 >
1723 > public readonly _itemId: string;
1724 > private readonly _getData: () => Promise<Uint8Array>;
1725 >
1726 > constructor(name: string, uri: vscode.Uri | undefined, itemId: string, getData: () => Promise<Uint8Array>) {
1727 this.name = name;
1728 this.uri = uri;
1730 this._getData = getData;
1731 }
1733 > data(): Promise<Uint8Array> {
1734 return this._getData();
1735 }
1736 > } extHostTypes.ts
1737 >
1738 > @es5ClassCompat
1739 > export class DataTransfer implements vscode.DataTransfer {
1740 > #items = new Map<string, vscode.DataTransferItem[]>();
1741 >
1742 > constructor(init?: Iterable<readonly [string, vscode.DataTransferItem]>) {
1743 for (const [mime, item] of init ?? []) {
1744 const existing = this.#items.get(this.#normalizeMime(mime));
1750 }
1751 }
1753 > get(mimeType: string): vscode.DataTransferItem | undefined {
1754 return this.#items.get(this.#normalizeMime(mimeType))?.[0];
1755 }
1757 > set(mimeType: string, value: vscode.DataTransferItem): void {
1758 // This intentionally overwrites all entries for a given mimetype.
1759 // This is similar to how the DOM DataTransfer type works
1760 this.#items.set(this.#normalizeMime(mimeType), [value]);
1761 }
1763 > forEach(callbackfn: (value: vscode.DataTransferItem, key: string, dataTransfer: DataTransfer) => void, thisArg?: unknown): void {
1764 for (const [mime, items] of this.#items) {
1765 for (const item of items) {
1768 }
1769 }
1771 > *[Symbol.iterator](): IterableIterator<[mimeType: string, item: vscode.DataTransferItem]> {
1772 for (const [mime, items] of this.#items) {
1773 for (const item of items) {
1776 }
1777 }
1779 > #normalizeMime(mimeType: string): string {
1780 return mimeType.toLowerCase();
1781 }
1782 > } extHostTypes.ts
1783 >
1784 > @es5ClassCompat
1785 > export class DocumentDropEdit {
1786 > title?: string;
1787 >
1788 > id: string | undefined;
1789 >
1790 > insertText: string | SnippetString;
1791 >
1792 > additionalEdit?: WorkspaceEdit;
1793 >
1794 > kind?: DocumentDropOrPasteEditKind;
1795 >
1796 > constructor(insertText: string | SnippetString, title?: string, kind?: DocumentDropOrPasteEditKind) {
1797 this.insertText = insertText;
1798 this.title = title;
1799 this.kind = kind;
1800 }
1801 > } extHostTypes.ts
1802 >
1803 > export enum DocumentPasteTriggerKind {
1804 > Automatic = 0,
1805 > PasteAs = 1,
1806 > }
1807 >
1808 > export class DocumentDropOrPasteEditKind {
1809 > static Empty: DocumentDropOrPasteEditKind;
1810 > static Text: DocumentDropOrPasteEditKind;
1811 > static TextUpdateImports: DocumentDropOrPasteEditKind;
1812 >
1813 > private static sep = '.';
1814 >
1815 > constructor(
1816 > public readonly value: string
1817 > ) { }
1818 >
1819 > public append(...parts: string[]): DocumentDropOrPasteEditKind {
1820 > return new DocumentDropOrPasteEditKind((this.value ? [this.value, ...parts] : parts).join(DocumentDropOrPasteEditKind.sep));
1821 > }
1822 >
1823 > public intersects(other: DocumentDropOrPasteEditKind): boolean {
1824 return this.contains(other) || other.contains(this);
1825 }
1827 > public contains(other: DocumentDropOrPasteEditKind): boolean {
1828 return this.value === other.value || other.value.startsWith(this.value + DocumentDropOrPasteEditKind.sep);
1829 }
1830 > } extHostTypes.ts
1831 > DocumentDropOrPasteEditKind.Empty = new DocumentDropOrPasteEditKind('');
1832 > DocumentDropOrPasteEditKind.Text = new DocumentDropOrPasteEditKind('text');
1833 > DocumentDropOrPasteEditKind.TextUpdateImports = DocumentDropOrPasteEditKind.Text.append('updateImports');
1834 >
1835 > export class DocumentPasteEdit {
1836 >
1837 > title: string;
1838 > insertText: string | SnippetString;
1839 > additionalEdit?: WorkspaceEdit;
1840 > kind: DocumentDropOrPasteEditKind;
1841 >
1842 > constructor(insertText: string | SnippetString, title: string, kind: DocumentDropOrPasteEditKind) {
1843 this.title = title;
1844 this.insertText = insertText;
1845 this.kind = kind;
1846 }
1847 > } extHostTypes.ts
1848 >
1849 > @es5ClassCompat
1850 > export class ThemeIcon {
1851 >
1852 > static File: ThemeIcon;
1853 > static Folder: ThemeIcon;
1854 >
1855 > readonly id: string;
1856 > readonly color?: ThemeColor;
1857 >
1858 > constructor(id: string, color?: ThemeColor) {
1859 > this.id = id;
1860 > this.color = color;
1861 > }
1862 >
1863 > static isThemeIcon(thing: any) {
1864 if (typeof thing.id !== 'string') {
1865 console.log('INVALID ThemeIcon, invalid id', thing.id);
1868 return true;
1869 }
1870 > } extHostTypes.ts
1871 > ThemeIcon.File = new ThemeIcon('file');
1872 > ThemeIcon.Folder = new ThemeIcon('folder');
1873 >
1874 >
1875 > @es5ClassCompat
1876 > export class ThemeColor {
1877 > id: string;
1878 > constructor(id: string) {
1879 this.id = id;
1880 }
1881 > } extHostTypes.ts
1882 >
1883 > export enum ConfigurationTarget {
1884 > Global = 1,
1885 >
1886 > Workspace = 2,
1887 >
1888 > WorkspaceFolder = 3
1889 > }
1890 >
1891 > @es5ClassCompat
1892 > export class RelativePattern implements IRelativePattern {
1893 >
1894 > pattern: string;
1895 >
1896 > private _base!: string;
1897 > get base(): string {
1898 return this._base;
1899 }
1900 > set base(base: string) { extHostTypes.ts
1901 this._base = base;
1902 this._baseUri = URI.file(base);
1903 }
1905 > private _baseUri!: URI;
1906 > get baseUri(): URI {
1907 return this._baseUri;
1908 }
1909 > set baseUri(baseUri: URI) { extHostTypes.ts
1910 this._baseUri = baseUri;
1911 this._base = baseUri.fsPath;
1912 }
1914 > constructor(base: vscode.WorkspaceFolder | URI | string, pattern: string) {
1915 if (typeof base !== 'string') {
1916 if (!base || !URI.isUri(base) && !URI.isUri(base.uri)) {
1933 this.pattern = pattern;
1934 }
1936 > toJSON(): IRelativePatternDto {
1937 return {
1938 pattern: this.pattern,
1941 };
1942 }
1943 > } extHostTypes.ts
1944 >
1945 > const breakpointIds = new WeakMap<Breakpoint, string>();
1946 >
1947 > /**
1948 > * We want to be able to construct Breakpoints internally that have a particular id, but we don't want extensions to be
1949 > * able to do this with the exposed Breakpoint classes in extension API.
1950 > * We also want "instanceof" to work with debug.breakpoints and the exposed breakpoint classes.
1951 > * And private members will be renamed in the built js, so casting to any and setting a private member is not safe.
1952 > * So, we store internal breakpoint IDs in a WeakMap. This function must be called after constructing a Breakpoint
1953 > * with a known id.
1954 > */
1955 > export function setBreakpointId(bp: Breakpoint, id: string) {
1956 breakpointIds.set(bp, id);
1957 }
1959 > @es5ClassCompat
1960 > export class Breakpoint {
1961 >
1962 > private _id: string | undefined;
1963 >
1964 > readonly enabled: boolean;
1965 > readonly condition?: string;
1966 > readonly hitCondition?: string;
1967 > readonly logMessage?: string;
1968 > readonly mode?: string;
1969 >
1970 > protected constructor(enabled?: boolean, condition?: string, hitCondition?: string, logMessage?: string, mode?: string) {
1971 this.enabled = typeof enabled === 'boolean' ? enabled : true;
1972 if (typeof condition === 'string') {
1983 }
1984 }
1986 > get id(): string {
1987 if (!this._id) {
1988 this._id = breakpointIds.get(this) ?? generateUuid();
1990 return this._id;
1991 }
1992 > } extHostTypes.ts
1993 >
1994 > @es5ClassCompat
1995 > export class SourceBreakpoint extends Breakpoint {
1996 > readonly location: Location;
1997 >
1998 > constructor(location: Location, enabled?: boolean, condition?: string, hitCondition?: string, logMessage?: string, mode?: string) {
1999 super(enabled, condition, hitCondition, logMessage, mode);
2000 if (location === null) {
2003 this.location = location;
2004 }
2005 > } extHostTypes.ts
2006 >
2007 > @es5ClassCompat
2008 > export class FunctionBreakpoint extends Breakpoint {
2009 > readonly functionName: string;
2010 >
2011 > constructor(functionName: string, enabled?: boolean, condition?: string, hitCondition?: string, logMessage?: string, mode?: string) {
2012 super(enabled, condition, hitCondition, logMessage, mode);
2013 this.functionName = functionName;
2014 }
2015 > } extHostTypes.ts
2016 >
2017 > @es5ClassCompat
2018 > export class DataBreakpoint extends Breakpoint {
2019 > readonly label: string;
2020 > readonly dataId: string;
2021 > readonly canPersist: boolean;
2022 >
2023 > constructor(label: string, dataId: string, canPersist: boolean, enabled?: boolean, condition?: string, hitCondition?: string, logMessage?: string, mode?: string) {
2024 super(enabled, condition, hitCondition, logMessage, mode);
2025 if (!dataId) {
2030 this.canPersist = canPersist;
2031 }
2032 > } extHostTypes.ts
2033 >
2034 > @es5ClassCompat
2035 > export class DebugAdapterExecutable implements vscode.DebugAdapterExecutable {
2036 > readonly command: string;
2037 > readonly args: string[];
2038 > readonly options?: vscode.DebugAdapterExecutableOptions;
2039 >
2040 > constructor(command: string, args: string[], options?: vscode.DebugAdapterExecutableOptions) {
2041 this.command = command;
2042 this.args = args || [];
2043 this.options = options;
2044 }
2045 > } extHostTypes.ts
2046 >
2047 > @es5ClassCompat
2048 > export class DebugAdapterServer implements vscode.DebugAdapterServer {
2049 > readonly port: number;
2050 > readonly host?: string;
2051 >
2052 > constructor(port: number, host?: string) {
2053 this.port = port;
2054 this.host = host;
2055 }
2056 > } extHostTypes.ts
2057 >
2058 > @es5ClassCompat
2059 > export class DebugAdapterNamedPipeServer implements vscode.DebugAdapterNamedPipeServer {
2060 > constructor(public readonly path: string) {
2061 }
2062 > } extHostTypes.ts
2063 >
2064 > @es5ClassCompat
2065 > export class DebugAdapterInlineImplementation implements vscode.DebugAdapterInlineImplementation {
2066 > readonly implementation: vscode.DebugAdapter;
2067 >
2068 > constructor(impl: vscode.DebugAdapter) {
2069 this.implementation = impl;
2070 }
2071 > } extHostTypes.ts
2072 >
2073 >
2074 > export class DebugStackFrame implements vscode.DebugStackFrame {
2075 > constructor(
2076 public readonly session: vscode.DebugSession,
2077 readonly threadId: number,
2078 readonly frameId: number) { }
2079 > } extHostTypes.ts
2080 >
2081 > export class DebugThread implements vscode.DebugThread {
2082 > constructor(
2083 public readonly session: vscode.DebugSession,
2084 readonly threadId: number) { }
2085 > } extHostTypes.ts
2086 >
2087 >
2088 > @es5ClassCompat
2089 > export class EvaluatableExpression implements vscode.EvaluatableExpression {
2090 > readonly range: vscode.Range;
2091 > readonly expression?: string;
2092 >
2093 > constructor(range: vscode.Range, expression?: string) {
2094 this.range = range;
2095 this.expression = expression;
2096 }
2097 > } extHostTypes.ts
2098 >
2099 > export enum InlineCompletionTriggerKind {
2100 > Invoke = 0,
2101 > Automatic = 1,
2102 > }
2103 >
2104 > export enum InlineCompletionsDisposeReasonKind {
2105 > Other = 0,
2106 > Empty = 1,
2107 > TokenCancellation = 2,
2108 > LostRace = 3,
2109 > NotTaken = 4,
2110 > }
2111 >
2112 > @es5ClassCompat
2113 > export class InlineValueText implements vscode.InlineValueText {
2114 > readonly range: Range;
2115 > readonly text: string;
2116 >
2117 > constructor(range: Range, text: string) {
2118 this.range = range;
2119 this.text = text;
2120 }
2121 > } extHostTypes.ts
2122 >
2123 > @es5ClassCompat
2124 > export class InlineValueVariableLookup implements vscode.InlineValueVariableLookup {
2125 > readonly range: Range;
2126 > readonly variableName?: string;
2127 > readonly caseSensitiveLookup: boolean;
2128 >
2129 > constructor(range: Range, variableName?: string, caseSensitiveLookup: boolean = true) {
2130 this.range = range;
2131 this.variableName = variableName;
2132 this.caseSensitiveLookup = caseSensitiveLookup;
2133 }
2134 > } extHostTypes.ts
2135 >
2136 > @es5ClassCompat
2137 > export class InlineValueEvaluatableExpression implements vscode.InlineValueEvaluatableExpression {
2138 > readonly range: Range;
2139 > readonly expression?: string;
2140 >
2141 > constructor(range: Range, expression?: string) {
2142 this.range = range;
2143 this.expression = expression;
2144 }
2145 > } extHostTypes.ts
2146 >
2147 > @es5ClassCompat
2148 > export class InlineValueContext implements vscode.InlineValueContext {
2149 >
2150 > readonly frameId: number;
2151 > readonly stoppedLocation: vscode.Range;
2152 >
2153 > constructor(frameId: number, range: vscode.Range) {
2154 this.frameId = frameId;
2155 this.stoppedLocation = range;
2156 }
2157 > } extHostTypes.ts
2158 >
2159 > export enum NewSymbolNameTag {
2160 > AIGenerated = 1
2161 > }
2162 >
2163 > export enum NewSymbolNameTriggerKind {
2164 > Invoke = 0,
2165 > Automatic = 1,
2166 > }
2167 >
2168 > export class NewSymbolName implements vscode.NewSymbolName {
2169 > readonly newSymbolName: string;
2170 > readonly tags?: readonly vscode.NewSymbolNameTag[] | undefined;
2171 >
2172 > constructor(
2173 newSymbolName: string,
2174 tags?: readonly NewSymbolNameTag[]
2177 this.tags = tags;
2178 }
2179 > } extHostTypes.ts
2180 >
2181 > //#region file api
2182 >
2183 > export enum FileChangeType {
2184 > Changed = 1,
2185 > Created = 2,
2186 > Deleted = 3,
2187 > }
2188 >
2189 > @es5ClassCompat
2190 > export class FileSystemError extends Error {
2191 >
2192 > static FileExists(messageOrUri?: string | URI): FileSystemError {
2193 return new FileSystemError(messageOrUri, FileSystemProviderErrorCode.FileExists, FileSystemError.FileExists);
2194 }
2195 > static FileNotFound(messageOrUri?: string | URI): FileSystemError { extHostTypes.ts
2196 return new FileSystemError(messageOrUri, FileSystemProviderErrorCode.FileNotFound, FileSystemError.FileNotFound);
2197 }
2198 > static FileNotADirectory(messageOrUri?: string | URI): FileSystemError { extHostTypes.ts
2199 return new FileSystemError(messageOrUri, FileSystemProviderErrorCode.FileNotADirectory, FileSystemError.FileNotADirectory);
2200 }
2201 > static FileIsADirectory(messageOrUri?: string | URI): FileSystemError { extHostTypes.ts
2202 return new FileSystemError(messageOrUri, FileSystemProviderErrorCode.FileIsADirectory, FileSystemError.FileIsADirectory);
2203 }
2204 > static NoPermissions(messageOrUri?: string | URI): FileSystemError { extHostTypes.ts
2205 return new FileSystemError(messageOrUri, FileSystemProviderErrorCode.NoPermissions, FileSystemError.NoPermissions);
2206 }
2207 > static Unavailable(messageOrUri?: string | URI): FileSystemError { extHostTypes.ts
2208 return new FileSystemError(messageOrUri, FileSystemProviderErrorCode.Unavailable, FileSystemError.Unavailable);
2209 }
2211 > readonly code: string;
2212 >
2213 > constructor(uriOrMessage?: string | URI, code: FileSystemProviderErrorCode = FileSystemProviderErrorCode.Unknown, terminator?: Function) {
2214 super(URI.isUri(uriOrMessage) ? uriOrMessage.toString(true) : uriOrMessage);
2215
2229 }
2230 }
2231 > } extHostTypes.ts
2232 >
2233 > //#endregion
2234 >
2235 > //#region folding api
2236 >
2237 > @es5ClassCompat
2238 > export class FoldingRange {
2239 >
2240 > start: number;
2241 >
2242 > end: number;
2243 >
2244 > kind?: FoldingRangeKind;
2245 >
2246 > constructor(start: number, end: number, kind?: FoldingRangeKind) {
2247 this.start = start;
2248 this.end = end;
2249 this.kind = kind;
2250 }
2251 > } extHostTypes.ts
2252 >
2253 > export enum FoldingRangeKind {
2254 > Comment = 1,
2255 > Imports = 2,
2256 > Region = 3
2257 > }
2258 >
2259 > //#endregion
2260 >
2261 > //#region Comment
2262 > export enum CommentThreadCollapsibleState {
2263 > /**
2264 > * Determines an item is collapsed
2265 > */
2266 > Collapsed = 0,
2267 > /**
2268 > * Determines an item is expanded
2269 > */
2270 > Expanded = 1
2271 > }
2272 >
2273 > export enum CommentMode {
2274 > Editing = 0,
2275 > Preview = 1
2276 > }
2277 >
2278 > export enum CommentState {
2279 > Published = 0,
2280 > Draft = 1
2281 > }
2282 >
2283 > export enum CommentThreadState {
2284 > Unresolved = 0,
2285 > Resolved = 1
2286 > }
2287 >
2288 > export enum CommentThreadApplicability {
2289 > Current = 0,
2290 > Outdated = 1
2291 > }
2292 >
2293 > export enum CommentThreadFocus {
2294 > Reply = 1,
2295 > Comment = 2
2296 > }
2297 >
2298 > //#endregion
2299 >
2300 > //#region Semantic Coloring
2301 >
2302 > export class SemanticTokensLegend {
2303 > public readonly tokenTypes: string[];
2304 > public readonly tokenModifiers: string[];
2305 >
2306 > constructor(tokenTypes: string[], tokenModifiers: string[] = []) {
2307 this.tokenTypes = tokenTypes;
2308 this.tokenModifiers = tokenModifiers;
2309 }
2310 > } extHostTypes.ts
2311 >
2312 function isStrArrayOrUndefined(arg: any): arg is string[] | undefined {
2313 return ((typeof arg === 'undefined') || isStringArray(arg));
2314 }
2316 > export class SemanticTokensBuilder {
2317 >
2318 > private _prevLine: number;
2319 > private _prevChar: number;
2320 > private _dataIsSortedAndDeltaEncoded: boolean;
2321 > private _data: number[];
2322 > private _dataLen: number;
2323 > private _tokenTypeStrToInt: Map<string, number>;
2324 > private _tokenModifierStrToInt: Map<string, number>;
2325 > private _hasLegend: boolean;
2326 >
2327 > constructor(legend?: vscode.SemanticTokensLegend) {
2328 this._prevLine = 0;
2329 this._prevChar = 0;
2344 }
2345 }
2347 > public push(line: number, char: number, length: number, tokenType: number, tokenModifiers?: number): void;
2348 > public push(range: Range, tokenType: string, tokenModifiers?: string[]): void;
2349 > public push(arg0: any, arg1: any, arg2: any, arg3?: any, arg4?: any): void {
2350 if (typeof arg0 === 'number' && typeof arg1 === 'number' && typeof arg2 === 'number' && typeof arg3 === 'number' && (typeof arg4 === 'number' || typeof arg4 === 'undefined')) {
2351 if (typeof arg4 === 'undefined') {
2361 throw illegalArgument();
2362 }
2364 > private _push(range: vscode.Range, tokenType: string, tokenModifiers?: string[]): void {
2365 if (!this._hasLegend) {
2366 throw new Error('Legend must be provided in constructor');
2388 this._pushEncoded(line, char, length, nTokenType, nTokenModifiers);
2389 }
2391 > private _pushEncoded(line: number, char: number, length: number, tokenType: number, tokenModifiers: number): void {
2392 if (this._dataIsSortedAndDeltaEncoded && (line < this._prevLine || (line === this._prevLine && char < this._prevChar))) {
2393 // push calls were ordered and are no longer ordered
2437 this._prevChar = char;
2438 }
2440 > private static _sortAndDeltaEncode(data: number[]): Uint32Array {
2441 const pos: number[] = [];
2442 const tokenCount = (data.length / 5) | 0;
2481 return result;
2482 }
2484 > public build(resultId?: string): SemanticTokens {
2485 if (!this._dataIsSortedAndDeltaEncoded) {
2486 return new SemanticTokens(SemanticTokensBuilder._sortAndDeltaEncode(this._data), resultId);
2488 return new SemanticTokens(new Uint32Array(this._data), resultId);
2489 }
2490 > } extHostTypes.ts
2491 >
2492 > export class SemanticTokens {
2493 > readonly resultId: string | undefined;
2494 > readonly data: Uint32Array;
2495 >
2496 > constructor(data: Uint32Array, resultId?: string) {
2497 this.resultId = resultId;
2498 this.data = data;
2499 }
2500 > } extHostTypes.ts
2501 >
2502 > export class SemanticTokensEdit {
2503 > readonly start: number;
2504 > readonly deleteCount: number;
2505 > readonly data: Uint32Array | undefined;
2506 >
2507 > constructor(start: number, deleteCount: number, data?: Uint32Array) {
2508 this.start = start;
2509 this.deleteCount = deleteCount;
2510 this.data = data;
2511 }
2512 > } extHostTypes.ts
2513 >
2514 > export class SemanticTokensEdits {
2515 > readonly resultId: string | undefined;
2516 > readonly edits: SemanticTokensEdit[];
2517 >
2518 > constructor(edits: SemanticTokensEdit[], resultId?: string) {
2519 this.resultId = resultId;
2520 this.edits = edits;
2521 }
2522 > } extHostTypes.ts
2523 >
2524 > //#endregion
2525 >
2526 > //#region debug
2527 > export enum DebugConsoleMode {
2528 > /**
2529 > * Debug session should have a separate debug console.
2530 > */
2531 > Separate = 0,
2532 >
2533 > /**
2534 > * Debug session should share debug console with its parent session.
2535 > * This value has no effect for sessions which do not have a parent session.
2536 > */
2537 > MergeWithParent = 1
2538 > }
2539 >
2540 > export class DebugVisualization {
2541 > iconPath?: URI | { light: URI; dark: URI } | ThemeIcon;
2542 > visualization?: vscode.Command | vscode.TreeDataProvider<unknown>;
2543 >
2544 > constructor(public name: string) { }
2545 > }
2546 >
2547 > //#endregion
2548 >
2549 > export enum QuickInputButtonLocation {
2550 > Title = 1,
2551 > Inline = 2,
2552 > Input = 3
2553 > }
2554 >
2555 > @es5ClassCompat
2556 > export class QuickInputButtons {
2557 >
2558 > static readonly Back: vscode.QuickInputButton = { iconPath: new ThemeIcon('arrow-left') };
2559 >
2560 > private constructor() { }
2561 > }
2562 >
2563 > export enum QuickPickItemKind {
2564 > Separator = -1,
2565 > Default = 0,
2566 > }
2567 >
2568 > export enum InputBoxValidationSeverity {
2569 > Info = 1,
2570 > Warning = 2,
2571 > Error = 3
2572 > }
2573 >
2574 > export enum ExtensionKind {
2575 > UI = 1,
2576 > Workspace = 2
2577 > }
2578 >
2579 > export class FileDecoration {
2580 >
2581 > static validate(d: FileDecoration): boolean {
2582 if (typeof d.badge === 'string') {
2583 let len = nextCharLength(d.badge, 0);
2598 return true;
2599 }
2601 > badge?: string | vscode.ThemeIcon;
2602 > tooltip?: string;
2603 > color?: vscode.ThemeColor;
2604 > propagate?: boolean;
2605 >
2606 > constructor(badge?: string | ThemeIcon, tooltip?: string, color?: ThemeColor) {
2607 this.badge = badge;
2608 this.tooltip = tooltip;
2609 this.color = color;
2610 }
2611 > } extHostTypes.ts
2612 >
2613 > //#region Theming
2614 >
2615 > @es5ClassCompat
2616 > export class ColorTheme implements vscode.ColorTheme {
2617 > constructor(public readonly kind: ColorThemeKind) {
2618 }
2619 > } extHostTypes.ts
2620 >
2621 > export enum ColorThemeKind {
2622 > Light = 1,
2623 > Dark = 2,
2624 > HighContrast = 3,
2625 > HighContrastLight = 4
2626 > }
2627 >
2628 > //#endregion Theming
2629 > //#region Notebook
2630 >
2631 > export class CellErrorStackFrame {
2632 > /**
2633 > * @param label The name of the stack frame
2634 > * @param file The file URI of the stack frame
2635 > * @param position The position of the stack frame within the file
2636 > */
2637 > constructor(
2638 public label: string,
2639 public uri?: vscode.Uri,
2640 public position?: Position,
2641 ) { }
2642 > } extHostTypes.ts
2643 >
2644 > export enum NotebookCellExecutionState {
2645 > Idle = 1,
2646 > Pending = 2,
2647 > Executing = 3,
2648 > }
2649 >
2650 > export enum NotebookCellStatusBarAlignment {
2651 > Left = 1,
2652 > Right = 2
2653 > }
2654 >
2655 > export enum NotebookEditorRevealType {
2656 > Default = 0,
2657 > InCenter = 1,
2658 > InCenterIfOutsideViewport = 2,
2659 > AtTop = 3
2660 > }
2661 >
2662 > export class NotebookCellStatusBarItem {
2663 > constructor(
2664 public text: string,
2665 public alignment: NotebookCellStatusBarAlignment) { }
2666 > } extHostTypes.ts
2667 >
2668 >
2669 > export enum NotebookControllerAffinity {
2670 > Default = 1,
2671 > Preferred = 2
2672 > }
2673 >
2674 > export enum NotebookControllerAffinity2 {
2675 > Default = 1,
2676 > Preferred = 2,
2677 > Hidden = -1
2678 > }
2679 >
2680 > export class NotebookRendererScript {
2681 >
2682 > public provides: readonly string[];
2683 >
2684 > constructor(
2685 public uri: vscode.Uri,
2686 provides: string | readonly string[] = []
2688 this.provides = asArray(provides);
2689 }
2690 > } extHostTypes.ts
2691 >
2692 > export class NotebookKernelSourceAction {
2693 > description?: string;
2694 > detail?: string;
2695 > command?: vscode.Command;
2696 > constructor(
2697 public label: string
2698 ) { }
2699 > } extHostTypes.ts
2700 >
2701 > export enum NotebookVariablesRequestKind {
2702 > Named = 1,
2703 > Indexed = 2
2704 > }
2705 >
2706 > //#endregion
2707 >
2708 > //#region Timeline
2709 >
2710 > @es5ClassCompat
2711 > export class TimelineItem implements vscode.TimelineItem {
2712 > constructor(public label: string, public timestamp: number) { }
2713 > }
2714 >
2715 > //#endregion Timeline
2716 >
2717 > //#region ExtensionContext
2718 >
2719 > export enum ExtensionMode {
2720 > /**
2721 > * The extension is installed normally (for example, from the marketplace
2722 > * or VSIX) in VS Code.
2723 > */
2724 > Production = 1,
2725 >
2726 > /**
2727 > * The extension is running from an `--extensionDevelopmentPath` provided
2728 > * when launching VS Code.
2729 > */
2730 > Development = 2,
2731 >
2732 > /**
2733 > * The extension is running from an `--extensionDevelopmentPath` and
2734 > * the extension host is running unit tests.
2735 > */
2736 > Test = 3,
2737 > }
2738 >
2739 > export enum ExtensionRuntime {
2740 > /**
2741 > * The extension is running in a NodeJS extension host. Runtime access to NodeJS APIs is available.
2742 > */
2743 > Node = 1,
2744 > /**
2745 > * The extension is running in a Webworker extension host. Runtime access is limited to Webworker APIs.
2746 > */
2747 > Webworker = 2
2748 > }
2749 >
2750 > //#endregion ExtensionContext
2751 >
2752 > export enum StandardTokenType {
2753 > Other = 0,
2754 > Comment = 1,
2755 > String = 2,
2756 > RegEx = 3
2757 > }
2758 >
2759 > export enum SyntaxHighlightingTokenFontStyle {
2760 > None = 0,
2761 > Italic = 1,
2762 > Bold = 2,
2763 > Underline = 4,
2764 > Strikethrough = 8,
2765 > }
2766 >
2767 >
2768 > export class LinkedEditingRanges {
2769 > constructor(public readonly ranges: Range[], public readonly wordPattern?: RegExp) {
2770 }
2771 > } extHostTypes.ts
2772 >
2773 > //#region ports
2774 > export class PortAttributes {
2775 > private _autoForwardAction: PortAutoForwardAction;
2776 >
2777 > constructor(autoForwardAction: PortAutoForwardAction) {
2778 this._autoForwardAction = autoForwardAction;
2779 }
2781 > get autoForwardAction(): PortAutoForwardAction {
2782 return this._autoForwardAction;
2783 }
2784 > } extHostTypes.ts
2785 > //#endregion ports
2786 >
2787 > //#region Testing
2788 > export enum TestResultState {
2789 > Queued = 1,
2790 > Running = 2,
2791 > Passed = 3,
2792 > Failed = 4,
2793 > Skipped = 5,
2794 > Errored = 6
2795 > }
2796 >
2797 > export enum TestRunProfileKind {
2798 > Run = 1,
2799 > Debug = 2,
2800 > Coverage = 3,
2801 > }
2802 >
2803 > export class TestRunProfileBase {
2804 > constructor(
2805 public readonly controllerId: string,
2806 public readonly profileId: number,
2807 public readonly kind: vscode.TestRunProfileKind,
2808 ) { }
2809 > } extHostTypes.ts
2810 >
2811 > @es5ClassCompat
2812 > export class TestRunRequest implements vscode.TestRunRequest {
2813 > constructor(
2814 public readonly include: vscode.TestItem[] | undefined = undefined,
2815 public readonly exclude: vscode.TestItem[] | undefined = undefined,
2818 public readonly preserveFocus = true,
2819 ) { }
2820 > } extHostTypes.ts
2821 >
2822 > @es5ClassCompat
2823 > export class TestMessage implements vscode.TestMessage {
2824 > public expectedOutput?: string;
2825 > public actualOutput?: string;
2826 > public location?: vscode.Location;
2827 > public contextValue?: string;
2828 >
2829 > /** proposed: */
2830 > public stackTrace?: TestMessageStackFrame[];
2831 >
2832 > public static diff(message: string | vscode.MarkdownString, expected: string, actual: string) {
2833 > const msg = new TestMessage(message);
2834 > msg.expectedOutput = expected;
2835 > msg.actualOutput = actual;
2836 > return msg;
2837 > }
2838 >
2839 > constructor(public message: string | vscode.MarkdownString) { }
2840 > }
2841 >
2842 > @es5ClassCompat
2843 > export class TestTag implements vscode.TestTag {
2844 > constructor(public readonly id: string) { }
2845 > }
2846 >
2847 > export class TestMessageStackFrame {
2848 > /**
2849 > * @param label The name of the stack frame
2850 > * @param file The file URI of the stack frame
2851 > * @param position The position of the stack frame within the file
2852 > */
2853 > constructor(
2854 public label: string,
2855 public uri?: vscode.Uri,
2856 public position?: Position,
2857 ) { }
2858 > } extHostTypes.ts
2859 >
2860 > //#endregion
2861 >
2862 > //#region Test Coverage
2863 > export class TestCoverageCount implements vscode.TestCoverageCount {
2864 > constructor(public covered: number, public total: number) {
2865 validateTestCoverageCount(this);
2866 }
2867 > } extHostTypes.ts
2868 >
2869 > export function validateTestCoverageCount(cc?: vscode.TestCoverageCount) {
2870 if (!cc) {
2871 return;
2880 }
2881 }
2883 > export class FileCoverage implements vscode.FileCoverage {
2884 > public static fromDetails(uri: vscode.Uri, details: vscode.FileCoverageDetail[]): vscode.FileCoverage {
2885 > const statements = new TestCoverageCount(0, 0);
2886 > const branches = new TestCoverageCount(0, 0);
2887 > const decl = new TestCoverageCount(0, 0);
2888 >
2889 > for (const detail of details) {
2890 > if ('branches' in detail) {
2891 > statements.total += 1;
2892 > statements.covered += detail.executed ? 1 : 0;
2893 >
2894 > for (const branch of detail.branches) {
2895 > branches.total += 1;
2896 > branches.covered += branch.executed ? 1 : 0;
2897 > }
2898 > } else {
2899 > decl.total += 1;
2900 > decl.covered += detail.executed ? 1 : 0;
2901 > }
2902 > }
2903 >
2904 > const coverage = new FileCoverage(
2905 > uri,
2906 > statements,
2907 > branches.total > 0 ? branches : undefined,
2908 > decl.total > 0 ? decl : undefined,
2909 > );
2910 >
2911 > coverage.detailedCoverage = details;
2912 >
2913 > return coverage;
2914 > }
2915 >
2916 > detailedCoverage?: vscode.FileCoverageDetail[];
2917 >
2918 > constructor(
2919 public readonly uri: vscode.Uri,
2920 public statementCoverage: vscode.TestCoverageCount,
2924 ) {
2925 }
2926 > } extHostTypes.ts
2927 >
2928 > export class StatementCoverage implements vscode.StatementCoverage {
2929 > // back compat until finalization:
2930 > get executionCount() { return +this.executed; }
2931 > set executionCount(n: number) { this.executed = n; }
2932 >
2933 > constructor(
2934 public executed: number | boolean,
2935 public location: Position | Range,
2936 public branches: vscode.BranchCoverage[] = [],
2937 ) { }
2938 > } extHostTypes.ts
2939 >
2940 > export class BranchCoverage implements vscode.BranchCoverage {
2941 > // back compat until finalization:
2942 > get executionCount() { return +this.executed; }
2943 > set executionCount(n: number) { this.executed = n; }
2944 >
2945 > constructor(
2946 public executed: number | boolean,
2947 public location: Position | Range,
2948 public label?: string,
2949 ) { }
2950 > } extHostTypes.ts
2951 >
2952 > export class DeclarationCoverage implements vscode.DeclarationCoverage {
2953 > // back compat until finalization:
2954 > get executionCount() { return +this.executed; }
2955 > set executionCount(n: number) { this.executed = n; }
2956 >
2957 > constructor(
2958 public readonly name: string,
2959 public executed: number | boolean,
2960 public location: Position | Range,
2961 ) { }
2962 > } extHostTypes.ts
2963 > //#endregion
2964 >
2965 > export enum ExternalUriOpenerPriority {
2966 > None = 0,
2967 > Option = 1,
2968 > Default = 2,
2969 > Preferred = 3,
2970 > }
2971 >
2972 > export enum WorkspaceTrustState {
2973 > Untrusted = 0,
2974 > Trusted = 1,
2975 > Unspecified = 2
2976 > }
2977 >
2978 > export enum PortAutoForwardAction {
2979 > Notify = 1,
2980 > OpenBrowser = 2,
2981 > OpenPreview = 3,
2982 > Silent = 4,
2983 > Ignore = 5,
2984 > OpenBrowserOnce = 6
2985 > }
2986 >
2987 > export class TypeHierarchyItem {
2988 > _sessionId?: string;
2989 > _itemId?: string;
2990 >
2991 > kind: SymbolKind;
2992 > tags?: SymbolTag[];
2993 > name: string;
2994 > detail?: string;
2995 > uri: URI;
2996 > range: Range;
2997 > selectionRange: Range;
2998 >
2999 > constructor(kind: SymbolKind, name: string, detail: string, uri: URI, range: Range, selectionRange: Range) {
3000 this.kind = kind;
3001 this.name = name;
3005 this.selectionRange = selectionRange;
3006 }
3007 > } extHostTypes.ts
3008 >
3009 > //#region Tab Inputs
3010 >
3011 > export class TextTabInput {
3012 > constructor(readonly uri: URI) { }
3013 > }
3014 >
3015 > export class TextDiffTabInput {
3016 > constructor(readonly original: URI, readonly modified: URI) { }
3017 > }
3018 >
3019 > export class TextMergeTabInput {
3020 > constructor(readonly base: URI, readonly input1: URI, readonly input2: URI, readonly result: URI) { }
3021 > }
3022 >
3023 > export class CustomEditorTabInput {
3024 > constructor(readonly uri: URI, readonly viewType: string) { }
3025 > }
3026 >
3027 > export class WebviewEditorTabInput {
3028 > constructor(readonly viewType: string) { }
3029 > }
3030 >
3031 > export class NotebookEditorTabInput {
3032 > constructor(readonly uri: URI, readonly notebookType: string) { }
3033 > }
3034 >
3035 > export class NotebookDiffEditorTabInput {
3036 > constructor(readonly original: URI, readonly modified: URI, readonly notebookType: string) { }
3037 > }
3038 >
3039 > export class TerminalEditorTabInput {
3040 > constructor() { }
3041 > }
3042 > export class InteractiveWindowInput {
3043 > constructor(readonly uri: URI, readonly inputBoxUri: URI) { }
3044 > }
3045 >
3046 > export class ChatEditorTabInput {
3047 > constructor() { }
3048 > }
3049 >
3050 > export class TextMultiDiffTabInput {
3051 > constructor(readonly textDiffs: TextDiffTabInput[]) { }
3052 > }
3053 > //#endregion
3054 >
3055 > //#region Chat
3056 >
3057 > export enum InteractiveSessionVoteDirection {
3058 > Down = 0,
3059 > Up = 1
3060 > }
3061 >
3062 > export enum ChatCopyKind {
3063 > Action = 1,
3064 > Toolbar = 2
3065 > }
3066 >
3067 > export enum ChatVariableLevel {
3068 > Short = 1,
3069 > Medium = 2,
3070 > Full = 3
3071 > }
3072 >
3073 > export class ChatCompletionItem implements vscode.ChatCompletionItem {
3074 > id: string;
3075 > label: string | CompletionItemLabel;
3076 > fullName?: string | undefined;
3077 > icon?: vscode.ThemeIcon;
3078 > insertText?: string;
3079 > values: vscode.ChatVariableValue[];
3080 > detail?: string;
3081 > documentation?: string | MarkdownString;
3082 > command?: vscode.Command;
3083 >
3084 > constructor(id: string, label: string | CompletionItemLabel, values: vscode.ChatVariableValue[]) {
3085 this.id = id;
3086 this.label = label;
3087 this.values = values;
3088 }
3089 > } extHostTypes.ts
3090 >
3091 > export enum ChatEditingSessionActionOutcome {
3092 > Accepted = 1,
3093 > Rejected = 2,
3094 > Saved = 3
3095 > }
3096 >
3097 > export enum ChatRequestEditedFileEventKind {
3098 > Keep = 1,
3099 > Undo = 2,
3100 > UserModification = 3,
3101 > }
3102 >
3103 > //#endregion
3104 >
3105 > //#region Interactive Editor
3106 >
3107 > export enum InteractiveEditorResponseFeedbackKind {
3108 > Unhelpful = 0,
3109 > Helpful = 1,
3110 > Undone = 2,
3111 > Accepted = 3,
3112 > Bug = 4
3113 > }
3114 >
3115 > export enum ChatResultFeedbackKind {
3116 > Unhelpful = 0,
3117 > Helpful = 1,
3118 > }
3119 >
3120 > export class ChatResponseMarkdownPart {
3121 > value: vscode.MarkdownString;
3122 > constructor(value: string | vscode.MarkdownString) {
3123 if (typeof value !== 'string' && value.isTrusted === true) {
3124 throw new Error('The boolean form of MarkdownString.isTrusted is NOT supported for chat participants.');
3127 this.value = typeof value === 'string' ? new MarkdownString(value) : value;
3128 }
3129 > } extHostTypes.ts
3130 >
3131 > /**
3132 > * TODO if 'vulnerabilities' is finalized, this should be merged with the base ChatResponseMarkdownPart. I just don't see how to do that while keeping
3133 > * vulnerabilities in a seperate API proposal in a clean way.
3134 > */
3135 > export class ChatResponseMarkdownWithVulnerabilitiesPart {
3136 > value: vscode.MarkdownString;
3137 > vulnerabilities: vscode.ChatVulnerability[];
3138 > constructor(value: string | vscode.MarkdownString, vulnerabilities: vscode.ChatVulnerability[]) {
3139 if (typeof value !== 'string' && value.isTrusted === true) {
3140 throw new Error('The boolean form of MarkdownString.isTrusted is NOT supported for chat participants.');
3144 this.vulnerabilities = vulnerabilities;
3145 }
3146 > } extHostTypes.ts
3147 >
3148 > export class ChatResponseConfirmationPart {
3149 > title: string;
3150 > message: string | vscode.MarkdownString;
3151 > data: any;
3152 > buttons?: string[];
3153 >
3154 > constructor(title: string, message: string | vscode.MarkdownString, data: any, buttons?: string[]) {
3155 this.title = title;
3156 this.message = message;
3158 this.buttons = buttons;
3159 }
3160 > } extHostTypes.ts
3161 >
3162 > export class ChatResponseFileTreePart {
3163 > value: vscode.ChatResponseFileTree[];
3164 > baseUri: vscode.Uri;
3165 > constructor(value: vscode.ChatResponseFileTree[], baseUri: vscode.Uri) {
3166 this.value = value;
3167 this.baseUri = baseUri;
3168 }
3169 > } extHostTypes.ts
3170 >
3171 > export class ChatResponseMultiDiffPart {
3172 > value: vscode.ChatResponseDiffEntry[];
3173 > title: string;
3174 > readOnly?: boolean;
3175 > constructor(value: vscode.ChatResponseDiffEntry[], title: string, readOnly?: boolean) {
3176 this.value = value;
3177 this.title = title;
3178 this.readOnly = readOnly;
3179 }
3180 > } extHostTypes.ts
3181 >
3182 > export class McpToolInvocationContentData {
3183 > mimeType: string;
3184 > data: Uint8Array;
3185 > constructor(data: Uint8Array, mimeType: string) {
3186 this.data = data;
3187 this.mimeType = mimeType;
3188 }
3189 > } extHostTypes.ts
3190 >
3191 > export class ChatSubagentToolInvocationData {
3192 > description?: string;
3193 > agentName?: string;
3194 > prompt?: string;
3195 > result?: string;
3196 > modelName?: string;
3197 > constructor(description?: string, agentName?: string, prompt?: string, result?: string) {
3198 this.description = description;
3199 this.agentName = agentName;
3201 this.result = result;
3202 }
3203 > } extHostTypes.ts
3204 >
3205 > export class ChatResponseExternalEditPart {
3206 > applied: Thenable<string>;
3207 > didGetApplied!: (value: string) => void;
3208 >
3209 > constructor(
3210 public uris: vscode.Uri[],
3211 public callback: () => Thenable<unknown>,
3215 });
3216 }
3217 > } extHostTypes.ts
3218 >
3219 > export class ChatResponseAnchorPart implements vscode.ChatResponseAnchorPart {
3220 > value: vscode.Uri | vscode.Location;
3221 > title?: string;
3222 >
3223 > value2: vscode.Uri | vscode.Location | vscode.SymbolInformation;
3224 > resolve?(token: vscode.CancellationToken): Thenable<void>;
3225 >
3226 > constructor(value: vscode.Uri | vscode.Location | vscode.SymbolInformation, title?: string) {
3227 // eslint-disable-next-line local/code-no-any-casts
3228 this.value = value as any;
3230 this.title = title;
3231 }
3232 > } extHostTypes.ts
3233 >
3234 > export class ChatResponseProgressPart {
3235 > value: string;
3236 > constructor(value: string) {
3237 this.value = value;
3238 }
3239 > } extHostTypes.ts
3240 >
3241 > export class ChatResponseProgressPart2 {
3242 > value: string;
3243 > task?: (progress: vscode.Progress<vscode.ChatResponseWarningPart>) => Thenable<string | void>;
3244 > constructor(value: string, task?: (progress: vscode.Progress<vscode.ChatResponseWarningPart>) => Thenable<string | void>) {
3245 this.value = value;
3246 this.task = task;
3247 }
3248 > } extHostTypes.ts
3249 >
3250 > export class ChatResponseThinkingProgressPart {
3251 > value: string | string[];
3252 > id?: string;
3253 > metadata?: { readonly [key: string]: any };
3254 > constructor(value: string | string[], id?: string, metadata?: { readonly [key: string]: any }) {
3255 this.value = value;
3256 this.id = id;
3257 this.metadata = metadata;
3258 }
3259 > } extHostTypes.ts
3260 >
3261 > export class ChatResponseHookPart {
3262 > hookType: HookTypeValue;
3263 > stopReason?: string;
3264 > systemMessage?: string;
3265 > metadata?: { readonly [key: string]: unknown };
3266 > constructor(hookType: HookTypeValue, stopReason?: string, systemMessage?: string, metadata?: { readonly [key: string]: unknown }) {
3267 this.hookType = hookType;
3268 this.stopReason = stopReason;
3270 this.metadata = metadata;
3271 }
3272 > } extHostTypes.ts
3273 >
3274 > export class ChatResponseAutoModeResolutionPart {
3275 > resolvedModel: string;
3276 > resolvedModelName: string;
3277 > predictedLabel: string;
3278 > confidence: number;
3279 > constructor(resolvedModel: string, resolvedModelName: string, predictedLabel: string, confidence: number) {
3280 this.resolvedModel = resolvedModel;
3281 this.resolvedModelName = resolvedModelName;
3283 this.confidence = confidence;
3284 }
3285 > } extHostTypes.ts
3286 >
3287 > export class ChatResponseWarningPart {
3288 > value: vscode.MarkdownString;
3289 > constructor(value: string | vscode.MarkdownString) {
3290 if (typeof value !== 'string' && value.isTrusted === true) {
3291 throw new Error('The boolean form of MarkdownString.isTrusted is NOT supported for chat participants.');
3294 this.value = typeof value === 'string' ? new MarkdownString(value) : value;
3295 }
3296 > } extHostTypes.ts
3297 >
3298 > export class ChatResponseInfoPart {
3299 > value: vscode.MarkdownString;
3300 > constructor(value: string | vscode.MarkdownString) {
3301 if (typeof value !== 'string' && value.isTrusted === true) {
3302 throw new Error('The boolean form of MarkdownString.isTrusted is NOT supported for chat participants.');
3305 this.value = typeof value === 'string' ? new MarkdownString(value) : value;
3306 }
3307 > } extHostTypes.ts
3308 >
3309 > export class ChatResponseCommandButtonPart {
3310 > value: vscode.Command;
3311 > constructor(value: vscode.Command) {
3312 this.value = value;
3313 }
3314 > } extHostTypes.ts
3315 >
3316 > export class ChatResponseReferencePart {
3317 > value: vscode.Uri | vscode.Location | { variableName: string; value?: vscode.Uri | vscode.Location } | string;
3318 > iconPath?: vscode.Uri | vscode.ThemeIcon | { light: vscode.Uri; dark: vscode.Uri };
3319 > options?: { status?: { description: string; kind: vscode.ChatResponseReferencePartStatusKind }; diffMeta?: { added: number; removed: number } };
3320 > constructor(value: vscode.Uri | vscode.Location | { variableName: string; value?: vscode.Uri | vscode.Location } | string, iconPath?: vscode.Uri | vscode.ThemeIcon | { light: vscode.Uri; dark: vscode.Uri }, options?: { status?: { description: string; kind: vscode.ChatResponseReferencePartStatusKind } }) {
3321 this.value = value;
3322 this.iconPath = iconPath;
3323 this.options = options;
3324 }
3325 > } extHostTypes.ts
3326 >
3327 > export class ChatResponseCodeblockUriPart {
3328 > isEdit?: boolean;
3329 > undoStopId?: string;
3330 > value: vscode.Uri;
3331 > constructor(value: vscode.Uri, isEdit?: boolean, undoStopId?: string) {
3332 this.value = value;
3333 this.isEdit = isEdit;
3334 this.undoStopId = undoStopId;
3335 }
3336 > } extHostTypes.ts
3337 >
3338 > export class ChatResponseCodeCitationPart {
3339 > value: vscode.Uri;
3340 > license: string;
3341 > snippet: string;
3342 > constructor(value: vscode.Uri, license: string, snippet: string) {
3343 this.value = value;
3344 this.license = license;
3345 this.snippet = snippet;
3346 }
3347 > } extHostTypes.ts
3348 >
3349 > export class ChatResponseMovePart {
3350 > constructor(
3351 public readonly uri: vscode.Uri,
3352 public readonly range: vscode.Range,
3353 ) {
3354 }
3355 > } extHostTypes.ts
3356 >
3357 > export class ChatResponseExtensionsPart {
3358 > constructor(
3359 public readonly extensions: string[],
3360 ) {
3361 }
3362 > } extHostTypes.ts
3363 >
3364 > export class ChatResponsePullRequestPart {
3365 > public readonly uri?: vscode.Uri;
3366 > public readonly command: vscode.Command;
3367 >
3368 > constructor(
3369 uriOrCommand: vscode.Uri | vscode.Command,
3370 public readonly title: string,
3384 }
3385 }
3387 > toJSON() {
3388 return {
3389 $mid: MarshalledId.ChatResponsePullRequestPart,
3394 };
3395 }
3396 > } extHostTypes.ts
3397 >
3398 > /**
3399 > * The type of question for a chat question carousel.
3400 > */
3401 > export enum ChatQuestionType {
3402 > /**
3403 > * A free-form text input question.
3404 > */
3405 > Text = 1,
3406 > /**
3407 > * A single-select question with radio buttons.
3408 > */
3409 > SingleSelect = 2,
3410 > /**
3411 > * A multi-select question with checkboxes.
3412 > */
3413 > MultiSelect = 3
3414 > }
3415 >
3416 > /**
3417 > * Represents a question to be displayed in a chat question carousel.
3418 > * Questions can be of type 'text' for free-form input, 'singleSelect' for radio buttons,
3419 > * or 'multiSelect' for checkboxes.
3420 > */
3421 > export class ChatQuestion {
3422 > /** Unique identifier for the question. */
3423 > id: string;
3424 > /** The type of question: Text for free-form input, SingleSelect for radio buttons, MultiSelect for checkboxes. */
3425 > type: ChatQuestionType;
3426 > /** The title/header of the question. */
3427 > title: string;
3428 > /** Optional detailed message or description for the question. */
3429 > message?: string | vscode.MarkdownString;
3430 > /** Options for singleSelect or multiSelect questions. */
3431 > options?: { id: string; label: string; value: unknown }[];
3432 > /** The id(s) of the default selected option(s). */
3433 > defaultValue?: string | string[];
3434 > /** Whether to allow free-form text input in addition to predefined options. */
3435 > allowFreeformInput?: boolean;
3436 >
3437 > constructor(
3438 id: string,
3439 type: ChatQuestionType,
3454 this.allowFreeformInput = options?.allowFreeformInput;
3455 }
3456 > } extHostTypes.ts
3457 >
3458 > /**
3459 > * A carousel view for presenting multiple questions inline in the chat response.
3460 > * Users can navigate between questions and submit their answers.
3461 > */
3462 > export class ChatResponseQuestionCarouselPart {
3463 > /** The questions to display in the carousel. */
3464 > questions: ChatQuestion[];
3465 > /** Whether users can skip answering the questions. */
3466 > allowSkip: boolean;
3467 >
3468 > constructor(questions: ChatQuestion[], allowSkip: boolean = true) {
3469 this.questions = questions;
3470 this.allowSkip = allowSkip;
3471 }
3472 > } extHostTypes.ts
3473 >
3474 > export class ChatResponseTextEditPart implements vscode.ChatResponseTextEditPart {
3475 > uri: vscode.Uri;
3476 > edits: vscode.TextEdit[];
3477 > isDone?: boolean;
3478 > constructor(uri: vscode.Uri, editsOrDone: vscode.TextEdit | vscode.TextEdit[] | true) {
3479 this.uri = uri;
3480 if (editsOrDone === true) {
3485 }
3486 }
3487 > } extHostTypes.ts
3488 >
3489 > export class ChatResponseNotebookEditPart implements vscode.ChatResponseNotebookEditPart {
3490 > uri: vscode.Uri;
3491 > edits: vscode.NotebookEdit[];
3492 > isDone?: boolean;
3493 > constructor(uri: vscode.Uri, editsOrDone: vscode.NotebookEdit | vscode.NotebookEdit[] | true) {
3494 this.uri = uri;
3495 if (editsOrDone === true) {
3501 }
3502 }
3503 > } extHostTypes.ts
3504 >
3505 > export class ChatResponseWorkspaceEditPart implements vscode.ChatResponseWorkspaceEditPart {
3506 > edits: vscode.ChatWorkspaceFileEdit[];
3507 > constructor(edits: vscode.ChatWorkspaceFileEdit[]) {
3508 this.edits = edits;
3509 }
3510 > } extHostTypes.ts
3511 >
3512 > export interface ChatTerminalToolInvocationData2 {
3513 > commandLine: {
3514 > original: string;
3515 > userEdited?: string;
3516 > toolEdited?: string;
3517 > };
3518 > language: string;
3519 > }
3520 >
3521 > export enum ChatTodoStatus {
3522 > NotStarted = 1,
3523 > InProgress = 2,
3524 > Completed = 3
3525 > }
3526 >
3527 > export enum ChatDebugSubagentStatus {
3528 > Running = 0,
3529 > Completed = 1,
3530 > Failed = 2
3531 > }
3532 >
3533 > export class ChatToolInvocationPart {
3534 > toolName: string;
3535 > toolCallId: string;
3536 > errorMessage?: string;
3537 > invocationMessage?: string | vscode.MarkdownString;
3538 > originMessage?: string | vscode.MarkdownString;
3539 > pastTenseMessage?: string | vscode.MarkdownString;
3540 > isConfirmed?: boolean;
3541 > isComplete?: boolean;
3542 > toolSpecificData?: ChatTerminalToolInvocationData2;
3543 > subAgentInvocationId?: string;
3544 > subAgentName?: string;
3545 > presentation?: 'hidden' | 'hiddenAfterComplete' | undefined;
3546 >
3547 > constructor(toolName: string,
3548 toolCallId: string,
3549 errorMessage?: string) {
3552 this.errorMessage = errorMessage;
3553 }
3554 > } extHostTypes.ts
3555 >
3556 > export class ChatRequestTurn implements vscode.ChatRequestTurn2 {
3557 > constructor(
3558 readonly prompt: string,
3559 readonly command: string | undefined,
3566 readonly modeInstructions2?: vscode.ChatRequestModeInstructions,
3567 ) { }
3568 > } extHostTypes.ts
3569 >
3570 > export class ChatResponseTurn implements vscode.ChatResponseTurn {
3571 >
3572 > constructor(
3573 readonly response: ReadonlyArray<ChatResponseMarkdownPart | ChatResponseFileTreePart | ChatResponseAnchorPart | ChatResponseCommandButtonPart>,
3574 readonly result: vscode.ChatResult,
3576 readonly command?: string
3577 ) { }
3578 > } extHostTypes.ts
3579 >
3580 > export class ChatResponseTurn2 implements vscode.ChatResponseTurn2 {
3581 >
3582 > constructor(
3583 readonly response: ReadonlyArray<ChatResponseMarkdownPart | ChatResponseFileTreePart | ChatResponseAnchorPart | ChatResponseCommandButtonPart | ChatResponseExtensionsPart | ChatToolInvocationPart>,
3584 readonly result: vscode.ChatResult,
3586 readonly command?: string
3587 ) { }
3588 > } extHostTypes.ts
3589 >
3590 > export enum ChatLocation {
3591 > Panel = 1,
3592 > Terminal = 2,
3593 > Notebook = 3,
3594 > Editor = 4,
3595 > }
3596 >
3597 > export enum ChatSessionStatus {
3598 > Failed = 0,
3599 > Completed = 1,
3600 > InProgress = 2,
3601 > NeedsInput = 3
3602 > }
3603 >
3604 > export class ChatSessionCustomizationType {
3605 > static readonly Agent = new ChatSessionCustomizationType('agent');
3606 > static readonly Skill = new ChatSessionCustomizationType('skill');
3607 > static readonly Instructions = new ChatSessionCustomizationType('instructions');
3608 > static readonly Prompt = new ChatSessionCustomizationType('prompt');
3609 > static readonly Hook = new ChatSessionCustomizationType('hook');
3610 > static readonly Plugins = new ChatSessionCustomizationType('plugins');
3611 >
3612 > constructor(public readonly id: string) { }
3613 > }
3614 >
3615 > export enum ChatDebugLogLevel {
3616 > Trace = 0,
3617 > Info = 1,
3618 > Warning = 2,
3619 > Error = 3
3620 > }
3621 >
3622 > export enum ChatDebugToolCallResult {
3623 > Success = 0,
3624 > Error = 1
3625 > }
3626 >
3627 > export enum ChatDebugHookResult {
3628 > Success = 0,
3629 > Error = 1,
3630 > NonBlockingError = 2
3631 > }
3632 >
3633 > export class ChatDebugToolCallEvent {
3634 > readonly _kind = 'toolCall';
3635 > id?: string;
3636 > sessionResource?: vscode.Uri;
3637 > created: Date;
3638 > parentEventId?: string;
3639 > toolName: string;
3640 > toolCallId?: string;
3641 > input?: string;
3642 > output?: string;
3643 > result?: ChatDebugToolCallResult;
3644 > durationInMillis?: number;
3645 >
3646 > constructor(toolName: string, created: Date) {
3647 this.toolName = toolName;
3648 this.created = created;
3649 }
3650 > } extHostTypes.ts
3651 >
3652 > export class ChatDebugModelTurnEvent {
3653 > readonly _kind = 'modelTurn';
3654 > id?: string;
3655 > sessionResource?: vscode.Uri;
3656 > created: Date;
3657 > parentEventId?: string;
3658 > model?: string;
3659 > requestName?: string;
3660 > inputTokens?: number;
3661 > outputTokens?: number;
3662 > cachedTokens?: number;
3663 > totalTokens?: number;
3664 > cost?: number;
3665 > copilotUsageNanoAiu?: number;
3666 > durationInMillis?: number;
3667 >
3668 > constructor(created: Date) {
3669 this.created = created;
3670 }
3671 > } extHostTypes.ts
3672 >
3673 > export class ChatDebugGenericEvent {
3674 > readonly _kind = 'generic';
3675 > id?: string;
3676 > sessionResource?: vscode.Uri;
3677 > created: Date;
3678 > parentEventId?: string;
3679 > name: string;
3680 > details?: string;
3681 > level: ChatDebugLogLevel;
3682 > category?: string;
3683 >
3684 > constructor(name: string, level: ChatDebugLogLevel, created: Date) {
3685 this.name = name;
3686 this.level = level;
3687 this.created = created;
3688 }
3689 > } extHostTypes.ts
3690 >
3691 > export class ChatDebugSubagentInvocationEvent {
3692 > readonly _kind = 'subagentInvocation';
3693 > id?: string;
3694 > sessionResource?: vscode.Uri;
3695 > created: Date;
3696 > parentEventId?: string;
3697 > agentName: string;
3698 > description?: string;
3699 > status?: ChatDebugSubagentStatus;
3700 > durationInMillis?: number;
3701 > toolCallCount?: number;
3702 > modelTurnCount?: number;
3703 >
3704 > constructor(agentName: string, created: Date) {
3705 this.agentName = agentName;
3706 this.created = created;
3707 }
3708 > } extHostTypes.ts
3709 >
3710 > export class ChatDebugMessageSection {
3711 > name: string;
3712 > content: string;
3713 >
3714 > constructor(name: string, content: string) {
3715 this.name = name;
3716 this.content = content;
3717 }
3718 > } extHostTypes.ts
3719 >
3720 > export class ChatDebugUserMessageEvent {
3721 > readonly _kind = 'userMessage';
3722 > id?: string;
3723 > sessionResource?: vscode.Uri;
3724 > created: Date;
3725 > parentEventId?: string;
3726 > message: string;
3727 > sections: ChatDebugMessageSection[];
3728 >
3729 > constructor(message: string, created: Date) {
3730 this.message = message;
3731 this.created = created;
3732 this.sections = [];
3733 }
3734 > } extHostTypes.ts
3735 >
3736 > export class ChatDebugAgentResponseEvent {
3737 > readonly _kind = 'agentResponse';
3738 > id?: string;
3739 > sessionResource?: vscode.Uri;
3740 > created: Date;
3741 > parentEventId?: string;
3742 > message: string;
3743 > sections: ChatDebugMessageSection[];
3744 >
3745 > constructor(message: string, created: Date) {
3746 this.message = message;
3747 this.created = created;
3748 this.sections = [];
3749 }
3750 > } extHostTypes.ts
3751 >
3752 > export class ChatDebugEventTextContent {
3753 > readonly _kind = 'text';
3754 > value: string;
3755 >
3756 > constructor(value: string) {
3757 this.value = value;
3758 }
3759 > } extHostTypes.ts
3760 >
3761 > export enum ChatDebugMessageContentType {
3762 > User = 0,
3763 > Agent = 1
3764 > }
3765 >
3766 > export class ChatDebugEventMessageContent {
3767 > readonly _kind = 'messageContent';
3768 > type: ChatDebugMessageContentType;
3769 > message: string;
3770 > sections: ChatDebugMessageSection[];
3771 >
3772 > constructor(type: ChatDebugMessageContentType, message: string, sections: ChatDebugMessageSection[]) {
3773 this.type = type;
3774 this.message = message;
3775 this.sections = sections;
3776 }
3777 > } extHostTypes.ts
3778 >
3779 > export class ChatDebugEventToolCallContent {
3780 > readonly _kind = 'toolCallContent';
3781 > toolName: string;
3782 > result?: ChatDebugToolCallResult;
3783 > durationInMillis?: number;
3784 > input?: string;
3785 > output?: string;
3786 >
3787 > constructor(toolName: string) {
3788 this.toolName = toolName;
3789 }
3790 > } extHostTypes.ts
3791 >
3792 > export class ChatDebugEventModelTurnContent {
3793 > readonly _kind = 'modelTurnContent';
3794 > requestName: string;
3795 > model?: string;
3796 > status?: string;
3797 > durationInMillis?: number;
3798 > timeToFirstTokenInMillis?: number;
3799 > requestId?: string;
3800 > maxInputTokens?: number;
3801 > maxOutputTokens?: number;
3802 > inputTokens?: number;
3803 > outputTokens?: number;
3804 > cachedTokens?: number;
3805 > totalTokens?: number;
3806 > requestOptions?: string;
3807 > errorMessage?: string;
3808 > sections?: ChatDebugMessageSection[];
3809 >
3810 > constructor(requestName: string) {
3811 this.requestName = requestName;
3812 }
3813 > } extHostTypes.ts
3814 >
3815 > export class ChatDebugEventHookContent {
3816 > readonly _kind = 'hookContent';
3817 > hookType: string;
3818 > command?: string;
3819 > result?: ChatDebugHookResult;
3820 > durationInMillis?: number;
3821 > input?: string;
3822 > output?: string;
3823 > exitCode?: number;
3824 > errorMessage?: string;
3825 >
3826 > constructor(hookType: string) {
3827 this.hookType = hookType;
3828 }
3829 > } extHostTypes.ts
3830 >
3831 > export class ChatSessionChangedFile {
3832 > constructor(public readonly uri: vscode.Uri, public readonly originalUri: vscode.Uri | undefined, public readonly modifiedUri: vscode.Uri | undefined, public readonly insertions: number, public readonly deletions: number) { }
3833 > }
3834 >
3835 > export enum ChatResponseReferencePartStatusKind {
3836 > Complete = 1,
3837 > Partial = 2,
3838 > Omitted = 3
3839 > }
3840 >
3841 > export enum ChatResponseClearToPreviousToolInvocationReason {
3842 > NoReason = 0,
3843 > FilteredContentRetry = 1,
3844 > CopyrightContentRetry = 2,
3845 > }
3846 >
3847 > export class ChatRequestEditorData implements vscode.ChatRequestEditorData {
3848 > constructor(
3849 readonly editor: vscode.TextEditor,
3850 readonly document: vscode.TextDocument,
3852 readonly wholeRange: vscode.Range,
3853 ) { }
3854 > } extHostTypes.ts
3855 >
3856 > export class ChatRequestNotebookData implements vscode.ChatRequestNotebookData {
3857 > constructor(
3858 readonly cell: vscode.TextDocument
3859 ) { }
3860 > } extHostTypes.ts
3861 >
3862 > export class ChatReferenceBinaryData implements vscode.ChatReferenceBinaryData {
3863 > mimeType: string;
3864 > data: () => Thenable<Uint8Array>;
3865 > reference?: vscode.Uri;
3866 > isPasted?: boolean;
3867 > isURL?: boolean;
3868 > constructor(mimeType: string, data: () => Thenable<Uint8Array>, reference?: vscode.Uri, isPasted?: boolean, isURL?: boolean) {
3869 this.mimeType = mimeType;
3870 this.data = data;
3873 this.isURL = isURL;
3874 }
3875 > } extHostTypes.ts
3876 >
3877 > export class ChatReferenceDiagnostic implements vscode.ChatReferenceDiagnostic {
3878 > constructor(public readonly diagnostics: [vscode.Uri, vscode.Diagnostic[]][]) { }
3879 > }
3880 >
3881 > export enum LanguageModelChatMessageRole {
3882 > User = 1,
3883 > Assistant = 2,
3884 > System = 3
3885 > }
3886 >
3887 > export class LanguageModelToolResultPart implements vscode.LanguageModelToolResultPart {
3888 >
3889 > callId: string;
3890 > content: (LanguageModelTextPart | LanguageModelPromptTsxPart | unknown)[];
3891 > isError: boolean;
3892 >
3893 > constructor(callId: string, content: (LanguageModelTextPart | LanguageModelPromptTsxPart | unknown)[], isError?: boolean) {
3894 this.callId = callId;
3895 this.content = content;
3896 this.isError = isError ?? false;
3897 }
3898 > } extHostTypes.ts
3899 >
3900 >
3901 > export enum ChatErrorLevel {
3902 > Info = 0,
3903 > Warning = 1,
3904 > Error = 2
3905 > }
3906 >
3907 > export enum ChatInputNotificationSeverity {
3908 > Info = 0,
3909 > Warning = 1,
3910 > Error = 2,
3911 > }
3912 >
3913 > export class LanguageModelChatMessage implements vscode.LanguageModelChatMessage {
3914 >
3915 > static User(content: string | (LanguageModelTextPart | LanguageModelToolResultPart | LanguageModelToolCallPart | LanguageModelDataPart)[], name?: string): LanguageModelChatMessage {
3916 > return new LanguageModelChatMessage(LanguageModelChatMessageRole.User, content, name);
3917 > }
3918 >
3919 > static Assistant(content: string | (LanguageModelTextPart | LanguageModelToolResultPart | LanguageModelToolCallPart | LanguageModelDataPart)[], name?: string): LanguageModelChatMessage {
3920 return new LanguageModelChatMessage(LanguageModelChatMessageRole.Assistant, content, name);
3921 }
3923 > role: vscode.LanguageModelChatMessageRole;
3924 >
3925 > private _content: (LanguageModelTextPart | LanguageModelToolResultPart | LanguageModelToolCallPart | LanguageModelDataPart)[] = [];
3926 >
3927 > set content(value: string | (LanguageModelTextPart | LanguageModelToolResultPart | LanguageModelToolCallPart | LanguageModelDataPart)[]) {
3928 if (typeof value === 'string') {
3929 // we changed this and still support setting content with a string property. this keep the API runtime stable
3934 }
3935 }
3937 > get content(): (LanguageModelTextPart | LanguageModelToolResultPart | LanguageModelToolCallPart | LanguageModelDataPart)[] {
3938 return this._content;
3939 }
3941 > name: string | undefined;
3942 >
3943 > constructor(role: vscode.LanguageModelChatMessageRole, content: string | (LanguageModelTextPart | LanguageModelToolResultPart | LanguageModelToolCallPart | LanguageModelDataPart)[], name?: string) {
3944 this.role = role;
3945 this.content = content;
3946 this.name = name;
3947 }
3948 > } extHostTypes.ts
3949 >
3950 > export class LanguageModelChatMessage2 implements vscode.LanguageModelChatMessage2 {
3951 >
3952 > static User(content: string | (LanguageModelTextPart | LanguageModelToolResultPart | LanguageModelToolCallPart | LanguageModelDataPart)[], name?: string): LanguageModelChatMessage2 {
3953 > return new LanguageModelChatMessage2(LanguageModelChatMessageRole.User, content, name);
3954 > }
3955 >
3956 > static Assistant(content: string | (LanguageModelTextPart | LanguageModelToolResultPart | LanguageModelToolCallPart | LanguageModelDataPart)[], name?: string): LanguageModelChatMessage2 {
3957 return new LanguageModelChatMessage2(LanguageModelChatMessageRole.Assistant, content, name);
3958 }
3960 > role: vscode.LanguageModelChatMessageRole;
3961 >
3962 > private _content: (LanguageModelTextPart | LanguageModelToolResultPart | LanguageModelToolCallPart | LanguageModelDataPart | LanguageModelThinkingPart)[] = [];
3963 >
3964 > set content(value: string | (LanguageModelTextPart | LanguageModelToolResultPart | LanguageModelToolCallPart | LanguageModelDataPart | LanguageModelThinkingPart)[]) {
3965 if (typeof value === 'string') {
3966 // we changed this and still support setting content with a string property. this keep the API runtime stable
3971 }
3972 }
3974 > get content(): (LanguageModelTextPart | LanguageModelToolResultPart | LanguageModelToolCallPart | LanguageModelDataPart | LanguageModelThinkingPart)[] {
3975 return this._content;
3976 }
3978 > // Temp to avoid breaking changes
3979 > set content2(value: (string | LanguageModelToolResultPart | LanguageModelToolCallPart | LanguageModelDataPart)[] | undefined) {
3980 if (value) {
3981 this.content = value.map(part => {
3987 }
3988 }
3990 > get content2(): (string | LanguageModelToolResultPart | LanguageModelToolCallPart | LanguageModelDataPart | LanguageModelThinkingPart)[] | undefined {
3991 return this.content.map(part => {
3992 if (part instanceof LanguageModelTextPart) {
3996 });
3997 }
3999 > name: string | undefined;
4000 >
4001 > constructor(role: vscode.LanguageModelChatMessageRole, content: string | (LanguageModelTextPart | LanguageModelToolResultPart | LanguageModelToolCallPart | LanguageModelDataPart | LanguageModelThinkingPart)[], name?: string) {
4002 this.role = role;
4003 this.content = content;
4004 this.name = name;
4005 }
4006 > } extHostTypes.ts
4007 >
4008 >
4009 > export class LanguageModelToolCallPart implements vscode.LanguageModelToolCallPart {
4010 > callId: string;
4011 > name: string;
4012 > input: any;
4013 >
4014 > constructor(callId: string, name: string, input: any) {
4015 this.callId = callId;
4016 this.name = name;
4018 this.input = input;
4019 }
4020 > } extHostTypes.ts
4021 >
4022 > export enum LanguageModelPartAudience {
4023 > Assistant = 0,
4024 > User = 1,
4025 > Extension = 2,
4026 > }
4027 >
4028 > export class LanguageModelTextPart implements vscode.LanguageModelTextPart2 {
4029 > value: string;
4030 > audience: vscode.LanguageModelPartAudience[] | undefined;
4031 >
4032 > constructor(value: string, audience?: vscode.LanguageModelPartAudience[]) {
4033 this.value = value;
4034 audience = audience;
4035 }
4037 > toJSON() {
4038 return {
4039 $mid: MarshalledId.LanguageModelTextPart,
4042 };
4043 }
4044 > } extHostTypes.ts
4045 >
4046 > export class LanguageModelDataPart implements vscode.LanguageModelDataPart2 {
4047 > mimeType: string;
4048 > data: Uint8Array<ArrayBufferLike>;
4049 > audience: vscode.LanguageModelPartAudience[] | undefined;
4050 >
4051 > constructor(data: Uint8Array<ArrayBufferLike>, mimeType: string, audience?: vscode.LanguageModelPartAudience[]) {
4052 this.mimeType = mimeType;
4053 this.data = data;
4054 this.audience = audience;
4055 }
4057 > static image(data: Uint8Array<ArrayBufferLike>, mimeType: string): vscode.LanguageModelDataPart {
4058 return new LanguageModelDataPart(data, mimeType);
4059 }
4061 > static json(value: object, mime: string = 'text/x-json'): vscode.LanguageModelDataPart {
4062 const rawStr = JSON.stringify(value, undefined, '\t');
4063 return new LanguageModelDataPart(VSBuffer.fromString(rawStr).buffer, mime);
4064 }
4066 > static text(value: string, mime: string = Mimes.text): vscode.LanguageModelDataPart {
4067 return new LanguageModelDataPart(VSBuffer.fromString(value).buffer, mime);
4068 }
4070 > toJSON() {
4071 return {
4072 $mid: MarshalledId.LanguageModelDataPart,
4076 };
4077 }
4078 > } extHostTypes.ts
4079 >
4080 > export enum ChatImageMimeType {
4081 > PNG = 'image/png',
4082 > JPEG = 'image/jpeg',
4083 > GIF = 'image/gif',
4084 > WEBP = 'image/webp',
4085 > BMP = 'image/bmp',
4086 > }
4087 >
4088 > export class LanguageModelThinkingPart implements vscode.LanguageModelThinkingPart {
4089 > value: string | string[];
4090 > id?: string;
4091 > metadata?: { readonly [key: string]: any };
4092 >
4093 > constructor(value: string | string[], id?: string, metadata?: { readonly [key: string]: any }) {
4094 this.value = value;
4095 this.id = id;
4096 this.metadata = metadata;
4097 }
4099 > toJSON() {
4100 return {
4101 $mid: MarshalledId.LanguageModelThinkingPart,
4105 };
4106 }
4107 > } extHostTypes.ts
4108 >
4109 >
4110 >
4111 > export class LanguageModelPromptTsxPart {
4112 > value: unknown;
4113 >
4114 > constructor(value: unknown) {
4115 this.value = value;
4116 }
4118 > toJSON() {
4119 return {
4120 $mid: MarshalledId.LanguageModelPromptTsxPart,
4122 };
4123 }
4124 > } extHostTypes.ts
4125 >
4126 > /**
4127 > * @deprecated
4128 > */
4129 > export class LanguageModelChatSystemMessage {
4130 > content: string;
4131 > constructor(content: string) {
4132 this.content = content;
4133 }
4134 > } extHostTypes.ts
4135 >
4136 >
4137 > /**
4138 > * @deprecated
4139 > */
4140 > export class LanguageModelChatUserMessage {
4141 > content: string;
4142 > name: string | undefined;
4143 >
4144 > constructor(content: string, name?: string) {
4145 this.content = content;
4146 this.name = name;
4147 }
4148 > } extHostTypes.ts
4149 >
4150 > /**
4151 > * @deprecated
4152 > */
4153 > export class LanguageModelChatAssistantMessage {
4154 > content: string;
4155 > name?: string;
4156 >
4157 > constructor(content: string, name?: string) {
4158 this.content = content;
4159 this.name = name;
4160 }
4161 > } extHostTypes.ts
4162 >
4163 > export class LanguageModelError extends Error {
4164 >
4165 > static readonly #name = 'LanguageModelError';
4166 >
4167 > static NotFound(message?: string): LanguageModelError {
4168 return new LanguageModelError(message, LanguageModelError.NotFound.name);
4169 }
4171 > static NoPermissions(message?: string): LanguageModelError {
4172 return new LanguageModelError(message, LanguageModelError.NoPermissions.name);
4173 }
4175 > static Blocked(message?: string): LanguageModelError {
4176 return new LanguageModelError(message, LanguageModelError.Blocked.name);
4177 }
4179 > static tryDeserialize(data: SerializedError): LanguageModelError | undefined {
4180 if (data.name !== LanguageModelError.#name) {
4181 return undefined;
4183 return new LanguageModelError(data.message, data.code, data.cause);
4184 }
4186 > readonly code: string;
4187 >
4188 > constructor(message?: string, code?: string, cause?: Error) {
4189 super(message, { cause });
4190 this.name = LanguageModelError.#name;
4191 this.code = code ?? '';
4192 }
4194 > }
4195 >
4196 > export class LanguageModelToolResult {
4197 > constructor(public content: (LanguageModelTextPart | LanguageModelPromptTsxPart | LanguageModelDataPart)[]) { }
4198 >
4199 > toJSON() {
4200 return {
4201 $mid: MarshalledId.LanguageModelToolResult,
4203 };
4204 }
4205 > } extHostTypes.ts
4206 >
4207 > export class LanguageModelToolResult2 {
4208 > constructor(public content: (LanguageModelTextPart | LanguageModelPromptTsxPart | LanguageModelDataPart)[]) { }
4209 >
4210 > toJSON() {
4211 return {
4212 $mid: MarshalledId.LanguageModelToolResult,
4214 };
4215 }
4216 > } extHostTypes.ts
4217 >
4218 > export class ExtendedLanguageModelToolResult extends LanguageModelToolResult {
4219 > toolResultMessage?: string | MarkdownString;
4220 > toolResultDetails?: Array<URI | Location>;
4221 > toolMetadata?: unknown;
4222 > hasError?: boolean;
4223 > }
4224 >
4225 > export enum LanguageModelChatToolMode {
4226 > Auto = 1,
4227 > Required = 2
4228 > }
4229 >
4230 > export class LanguageModelToolExtensionSource implements vscode.LanguageModelToolExtensionSource {
4231 > constructor(public readonly id: string, public readonly label: string) { }
4232 > }
4233 >
4234 > export class LanguageModelToolMCPSource implements vscode.LanguageModelToolMCPSource {
4235 > constructor(public readonly label: string, public readonly name: string, public readonly instructions: string | undefined) { }
4236 > }
4237 >
4238 > //#endregion
4239 >
4240 > //#region ai
4241 >
4242 > export enum RelatedInformationType {
4243 > SymbolInformation = 1,
4244 > CommandInformation = 2,
4245 > SearchInformation = 3,
4246 > SettingInformation = 4
4247 > }
4248 >
4249 > export enum SettingsSearchResultKind {
4250 > EMBEDDED = 1,
4251 > LLM_RANKED = 2,
4252 > CANCELED = 3,
4253 > }
4254 >
4255 > //#endregion
4256 >
4257 > //#region Speech
4258 >
4259 > export enum SpeechToTextStatus {
4260 > Started = 1,
4261 > Recognizing = 2,
4262 > Recognized = 3,
4263 > Stopped = 4,
4264 > Error = 5
4265 > }
4266 >
4267 > export enum TextToSpeechStatus {
4268 > Started = 1,
4269 > Stopped = 2,
4270 > Error = 3
4271 > }
4272 >
4273 > export enum KeywordRecognitionStatus {
4274 > Recognized = 1,
4275 > Stopped = 2
4276 > }
4277 >
4278 > //#endregion
4279 >
4280 > //#region MCP
4281 > export enum McpToolAvailability {
4282 > Initial = 0,
4283 > Dynamic = 1,
4284 > }
4285 >
4286 > export class McpStdioServerDefinition implements vscode.McpStdioServerDefinition {
4287 > cwd?: URI;
4288 >
4289 > constructor(
4290 public label: string,
4291 public command: string,
4295 public metadata?: vscode.McpServerMetadata,
4296 ) { }
4297 > } extHostTypes.ts
4298 >
4299 > export class McpHttpServerDefinition implements vscode.McpHttpServerDefinition {
4300 > constructor(
4301 public label: string,
4302 public uri: URI,
4306 public authentication?: { providerId: string; scopes: string[] },
4307 ) { }
4308 > } extHostTypes.ts
4309 > //#endregion
4310 >
4311 > //#region Chat Prompt Files
4312 > //#endregion
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/platform/agentHost/common/state/protocol/channels-chat/state.ts 1557 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- state.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > // allow-any-unicode-comment-file
7 > // DO NOT EDIT -- auto-generated by scripts/sync-agent-host-protocol.ts
8 >
9 > import type { ModelSelection } from '../channels-root/state.js';
10 > import type { AgentSelection, McpAuthRequirement, SessionStatus } from '../channels-session/state.js';
11 > import type { ContentRef, ErrorInfo, FileEdit, StringOrMarkdown, TextRange, TextSelection, URI, UsageInfo } from '../common/state.js';
12 >
13 > // ─── Chat State ──────────────────────────────────────────────────────────────
14 >
15 > /**
16 > * Full state for a single chat, loaded when a client subscribes to the chat's
17 > * URI.
18 > *
19 > * The lightweight catalog representation of a chat is {@link ChatSummary},
20 > * carried in {@link SessionState.chats | `SessionState.chats`}. `ChatState`
21 > * **denormalizes** every {@link ChatSummary} field directly onto itself so
22 > * subscribers receive one flat object instead of having to merge a nested
23 > * `summary` sub-object. Producers MUST keep the two representations
24 > * consistent: any change to the inlined fields below SHOULD also be
25 > * announced on the parent session via the matching
26 > * {@link SessionChatUpdatedAction | `session/chatUpdated`} action.
27 > *
28 > * @category Chat State
29 > */
30 > export interface ChatState {
31 > // ── Summary fields (denormalized from ChatSummary) ─────────────────
32 > /** Chat URI */
33 > resource: URI;
34 > /** Chat title */
35 > title: string;
36 > /** Current chat status (reuses SessionStatus shape) */
37 > status: SessionStatus;
38 > /** Human-readable description of what the chat is currently doing */
39 > activity?: string;
40 > /** Last modification timestamp (ISO 8601, e.g. `"2025-03-10T18:42:03.123Z"`) */
41 > modifiedAt: string;
42 > /** How this chat came into existence */
43 > origin?: ChatOrigin;
44 > /**
45 > * How the user can interact with this chat. See {@link ChatInteractivity}.
46 > *
47 > * Supports agent-team patterns where worker chats are read-only or hidden.
48 > * Absence defaults to {@link ChatInteractivity.Full} for backward
49 > * compatibility.
50 > */
51 > interactivity?: ChatInteractivity;
52 > /**
53 > * The subset of the session's
54 > * {@link SessionState.workingDirectories | `workingDirectories`} that this
55 > * chat's agent has tool access to. Every entry MUST be present in the owning
56 > * session's `workingDirectories`; servers MUST reject a
57 > * `chat/workingDirectorySet` action that violates this constraint.
58 > *
59 > * When absent, the chat inherits the full session set. When present but empty
60 > * (not recommended), the chat has no working-directory tool access at all.
61 > *
62 > * Dispatch `chat/workingDirectorySet` / `chat/workingDirectoryRemoved` to
63 > * update the subset on a running chat.
64 > */
65 > workingDirectories?: URI[];
66 > /**
67 > * The chat's primary working directory — the distinguished root this chat is
68 > * centered on (e.g. the agent's process root for this chat, the default
69 > * location for relative paths). MUST be one of this chat's effective working
70 > * directories ({@link workingDirectories}, or the session's set when that is
71 > * absent). Present when the agent advertises
72 > * {@link MultipleWorkingDirectoriesCapability.requiresPrimary}.
73 > *
74 > * **Read-only and fixed at creation.** It is set from
75 > * {@link CreateChatParams.primaryWorkingDirectory} (or, for the session's
76 > * default chat, {@link CreateSessionParams.primaryWorkingDirectory}) and does
77 > * not change over the chat's lifetime — there is no action to mutate it, and
78 > * it does not participate in `session/chatUpdated`.
79 > */
80 > primaryWorkingDirectory?: URI;
81 >
82 > // ── Conversation contents ──────────────────────────────────────────
83 > /** Completed turns */
84 > turns: Turn[];
85 > /**
86 > * Cursor for loading older completed turns into this chat state.
87 > *
88 > * Presence means `turns` is a tail window and more historical turns are
89 > * available. Pass this opaque cursor to `fetchTurns`; the host MUST insert
90 > * the loaded turns into state and update or clear this cursor before
91 > * responding. Absence means the state contains all retained turns.
92 > */
93 > turnsNextCursor?: string;
94 > /** Currently in-progress turn */
95 > activeTurn?: ActiveTurn;
96 > /** Message to inject into the current turn at a convenient point */
97 > steeringMessage?: PendingMessage;
98 > /** Messages to send automatically as new turns after the current turn finishes */
99 > queuedMessages?: PendingMessage[];
100 > /**
101 > * The user's in-progress draft input for this chat — the message they are
102 > * composing but have not sent yet, including its
103 > * {@link Message.model | model} / {@link Message.agent | agent} selection
104 > * and attachments.
105 > *
106 > * Clients MAY periodically sync their local input state into this field so
107 > * a draft survives reloads and is visible to other clients viewing the same
108 > * chat. Eager syncing is **not** required — clients SHOULD debounce and MAY
109 > * sync only at convenient points. When presenting input UI for an existing
110 > * chat, clients SHOULD use any `draft` to initialize their input state.
111 > * Cleared (set to `undefined`) once the message is sent.
112 > */
113 > draft?: Message;
114 > /**
115 > * Additional provider-specific metadata for this chat.
116 > */
117 > _meta?: Record<string, unknown>;
118 > }
119 >
120 > /**
121 > * Lightweight catalog entry for a chat, carried in
122 > * {@link SessionState.chats | `SessionState.chats`}. The full conversation
123 > * lives in {@link ChatState}, which inlines (denormalizes) every field below.
124 > *
125 > * @category Chat State
126 > */
127 > export interface ChatSummary {
128 > /** Chat URI */
129 > resource: URI;
130 > /** Chat title */
131 > title: string;
132 > /** Current chat status (reuses SessionStatus shape) */
133 > status: SessionStatus;
134 > /** Human-readable description of what the chat is currently doing */
135 > activity?: string;
136 > /** Last modification timestamp (ISO 8601, e.g. `"2025-03-10T18:42:03.123Z"`) */
137 > modifiedAt: string;
138 > /** How this chat came into existence */
139 > origin?: ChatOrigin;
140 > /**
141 > * How the user can interact with this chat. See {@link ChatInteractivity}.
142 > *
143 > * Supports agent-team patterns where worker chats are read-only or hidden.
144 > * Absence defaults to {@link ChatInteractivity.Full} for backward
145 > * compatibility.
146 > */
147 > interactivity?: ChatInteractivity;
148 > /**
149 > * The subset of the session's working directories this chat uses.
150 > * See {@link ChatState.workingDirectories} for the full semantics.
151 > */
152 > workingDirectories?: URI[];
153 > /**
154 > * The chat's primary working directory.
155 > * See {@link ChatState.primaryWorkingDirectory} for the full semantics.
156 > */
157 > primaryWorkingDirectory?: URI;
158 > }
159 >
160 > /**
161 > * Discriminant for {@link ChatOrigin} — how a chat came into existence.
162 > *
163 > * @category Chat State
164 > */
165 > export const enum ChatOriginKind {
166 > /** User created the chat explicitly (e.g. via the host UI). */
167 > User = 'user',
168 > /** Forked from an existing chat at a specific turn. */
169 > Fork = 'fork',
170 > /** Created as an independent side conversation from a specific turn. */
171 > SideChat = 'sideChat',
172 > /** Spawned by a tool call running in another chat (e.g. a sub-agent delegation). */
173 > Tool = 'tool',
174 > }
175 >
176 > /**
177 > * Immutable selected-text snapshot captured when a side chat is created.
178 > *
179 > * The host records this exact text when it accepts `createChat`; later changes
180 > * to the source chat do not alter it.
181 > *
182 > * @category Chat State
183 > */
184 > export interface SideChatSelection {
185 > /**
186 > * Exact selected-text snapshot captured at `createChat` acceptance.
187 > *
188 > * MUST be non-empty.
189 > */
190 > text: string;
191 > /**
192 > * Optional provenance for the response part that contained {@link text} when
193 > * the host took the snapshot.
194 > *
195 > * Advisory only: this is not a live range or offset and MUST NOT be used to
196 > * recompute `text`.
197 > */
198 > responsePartId?: string;
199 > }
200 >
201 > /**
202 > * How a chat came into existence. Clients MAY use it to render
203 > * contextual UI (parent indicators, fork markers, "spawned by tool" badges).
204 > *
205 > * Fork and side-chat origins both carry a stable top-level `turnId` alongside
206 > * their discriminated `kind` value instead of snapshotting whether that turn
207 > * was active or historical at creation time. Consumers resolve the identifier
208 > * against the
209 > * source chat's current `activeTurn` or retained `turns` as needed.
210 > *
211 > * When a host accepts side-chat creation from the source chat's current active
212 > * turn, it snapshots the retained history plus that turn's current user
213 > * message and any partial assistant response already available. Later
214 > * source-turn deltas do not retroactively change the created side chat's
215 > * starting context, and once the source turn completes it is still referenced
216 > * by the same `turnId`. Side-chat origins MAY also retain an immutable
217 > * {@link SideChatSelection | selected-text snapshot} captured at acceptance
218 > * time; any `responsePartId` there is provenance only, not a range.
219 > *
220 > * The `tool` variant records a tool-spawned worker from the worker's side: its
221 > * `chat`/`toolCallId` identify the spawning tool call in the parent chat. This
222 > * is the canonical record of the spawn relationship. The same edge is surfaced
223 > * from the parent's side by {@link ToolResultSubagentContent}, whose `resource`
224 > * is this chat's URI; hosts MUST keep the two consistent.
225 > *
226 > * @category Chat State
227 > */
228 > export type ChatOrigin =
229 > | { kind: ChatOriginKind.User }
230 > | { kind: ChatOriginKind.Fork; chat: URI; turnId: string }
231 > | { kind: ChatOriginKind.SideChat; chat: URI; turnId: string; selection?: SideChatSelection }
232 > | { kind: ChatOriginKind.Tool; chat: URI; toolCallId: string };
233 >
234 > /**
235 > * How a user can interact with a chat.
236 > *
237 > * - `Full` — user can send messages and watch (default when absent)
238 > * - `ReadOnly` — user can watch but not send messages (e.g. agent team workers)
239 > * - `Hidden` — internal worker not shown in UI at all
240 > *
241 > * Supports the agent-team pattern where a lead chat is fully interactive and
242 > * worker chats are read-only (visible for observability) or hidden (internal
243 > * implementation detail). The harness sets this based on the chat's role;
244 > * the UI uses it to show appropriate controls.
245 > *
246 > * @category Chat State
247 > */
248 > export const enum ChatInteractivity {
249 > /** User can send messages and watch (default when absent) */
250 > Full = 'full',
251 > /** User can watch but not send messages */
252 > ReadOnly = 'read-only',
253 > /** Internal worker not shown in UI at all */
254 > Hidden = 'hidden',
255 > }
256 >
257 > // ─── Pending Message Types ───────────────────────────────────────────────────
258 >
259 > /**
260 > * Discriminant for pending message kinds.
261 > *
262 > * @category Pending Message Types
263 > */
264 > export const enum PendingMessageKind {
265 > /** Injected into the current turn at a convenient point */
266 > Steering = 'steering',
267 > /** Sent automatically as a new turn after the current turn finishes */
268 > Queued = 'queued',
269 > }
270 >
271 > /**
272 > * A message queued for future delivery to the agent.
273 > *
274 > * Steering messages are injected into the current turn mid-flight.
275 > * Queued messages are automatically started as new turns after the
276 > * current turn naturally finishes.
277 > *
278 > * @category Pending Message Types
279 > */
280 > export interface PendingMessage {
281 > /** Unique identifier for this pending message */
282 > id: string;
283 > /** The message that will start the next turn */
284 > message: Message;
285 > }
286 >
287 >
288 > // ─── Chat Input Types ────────────────────────────────────────────────────
289 >
290 > /**
291 > * How a client completed an input request.
292 > *
293 > * @category Chat Input Types
294 > */
295 > export const enum ChatInputResponseKind {
296 > Accept = 'accept',
297 > Decline = 'decline',
298 > Cancel = 'cancel',
299 > }
300 >
301 > /**
302 > * Question/input control kind.
303 > *
304 > * @category Chat Input Types
305 > */
306 > export const enum ChatInputQuestionKind {
307 > Text = 'text',
308 > Number = 'number',
309 > Integer = 'integer',
310 > Boolean = 'boolean',
311 > SingleSelect = 'single-select',
312 > MultiSelect = 'multi-select',
313 > }
314 >
315 > /**
316 > * A choice in a select-style question.
317 > *
318 > * @category Chat Input Types
319 > */
320 > export interface ChatInputOption {
321 > /** Stable option identifier; for MCP enum values this is the enum string */
322 > id: string;
323 > /** Display label */
324 > label: string;
325 > /** Optional secondary text */
326 > description?: string;
327 > /** Whether this option is the recommended/default choice */
328 > recommended?: boolean;
329 > }
330 >
331 > interface ChatInputQuestionBase {
332 > /** Stable question identifier used as the key in `answers` */
333 > id: string;
334 > /** Short display title */
335 > title?: string;
336 > /** Prompt shown to the user */
337 > message: string;
338 > /** Whether the user must answer this question to accept the request */
339 > required?: boolean;
340 > }
341 >
342 > /** Text question within a chat input request. */
343 > export interface ChatInputTextQuestion extends ChatInputQuestionBase {
344 > kind: ChatInputQuestionKind.Text;
345 > /** Format hint for text questions, such as `email`, `uri`, `date`, or `date-time` */
346 > format?: string;
347 > /** Minimum string length */
348 > min?: number;
349 > /** Maximum string length */
350 > max?: number;
351 > /** Default text */
352 > defaultValue?: string;
353 > }
354 >
355 > /** Numeric question within a chat input request. */
356 > export interface ChatInputNumberQuestion extends ChatInputQuestionBase {
357 > kind: ChatInputQuestionKind.Number | ChatInputQuestionKind.Integer;
358 > /**
359 > * Minimum value
360 > * @format float
361 > */
362 > min?: number;
363 > /**
364 > * Maximum value
365 > * @format float
366 > */
367 > max?: number;
368 > /**
369 > * Default numeric value
370 > * @format float
371 > */
372 > defaultValue?: number;
373 > }
374 >
375 > /** Boolean question within a chat input request. */
376 > export interface ChatInputBooleanQuestion extends ChatInputQuestionBase {
377 > kind: ChatInputQuestionKind.Boolean;
378 > /** Default boolean value */
379 > defaultValue?: boolean;
380 > }
381 >
382 > /** Single-select question within a chat input request. */
383 > export interface ChatInputSingleSelectQuestion extends ChatInputQuestionBase {
384 > kind: ChatInputQuestionKind.SingleSelect;
385 > /** Options the user may select from */
386 > options: ChatInputOption[];
387 > /** Whether the user may enter text instead of selecting an option */
388 > allowFreeformInput?: boolean;
389 > }
390 >
391 > /** Multi-select question within a chat input request. */
392 > export interface ChatInputMultiSelectQuestion extends ChatInputQuestionBase {
393 > kind: ChatInputQuestionKind.MultiSelect;
394 > /** Options the user may select from */
395 > options: ChatInputOption[];
396 > /** Whether the user may enter text in addition to selecting options */
397 > allowFreeformInput?: boolean;
398 > /** Minimum selected item count */
399 > min?: number;
400 > /** Maximum selected item count */
401 > max?: number;
402 > }
403 >
404 > /**
405 > * One question within a chat input request.
406 > *
407 > * @category Chat Input Types
408 > */
409 > export type ChatInputQuestion = ChatInputTextQuestion
410 > | ChatInputNumberQuestion
411 > | ChatInputBooleanQuestion
412 > | ChatInputSingleSelectQuestion
413 > | ChatInputMultiSelectQuestion;
414 >
415 > /**
416 > * The request payload carried by an {@link InputRequestResponsePart}.
417 > *
418 > * The server creates or replaces the containing response part with
419 > * `chat/inputRequested`. Clients sync drafts with `chat/inputAnswerChanged`
420 > * and submit responses with `chat/inputCompleted`.
421 > *
422 > * @category Chat Input Types
423 > */
424 > export interface ChatInputRequest {
425 > /** Stable request identifier */
426 > id: string;
427 > /** Display message for the request as a whole */
428 > message?: string;
429 > /** URL the user should review or open, for URL-style elicitations */
430 > url?: URI;
431 > /** Ordered questions to ask the user */
432 > questions?: ChatInputQuestion[];
433 > /** Current draft or submitted answers, keyed by question ID */
434 > answers?: Record<string, ChatInputAnswer>;
435 > }
436 >
437 > /**
438 > * Answer value kind.
439 > *
440 > * @category Chat Input Types
441 > */
442 > export const enum ChatInputAnswerValueKind {
443 > Text = 'text',
444 > Number = 'number',
445 > Boolean = 'boolean',
446 > Selected = 'selected',
447 > SelectedMany = 'selected-many',
448 > }
449 >
450 > /**
451 > * Value captured for one answer.
452 > *
453 > * @category Chat Input Types
454 > */
455 > export interface ChatInputTextAnswerValue {
456 > kind: ChatInputAnswerValueKind.Text;
457 > value: string;
458 > }
459 >
460 > export interface ChatInputNumberAnswerValue {
461 > kind: ChatInputAnswerValueKind.Number;
462 > /** @format float */
463 > value: number;
464 > }
465 >
466 > export interface ChatInputBooleanAnswerValue {
467 > kind: ChatInputAnswerValueKind.Boolean;
468 > value: boolean;
469 > }
470 >
471 > export interface ChatInputSelectedAnswerValue {
472 > kind: ChatInputAnswerValueKind.Selected;
473 > value: string;
474 > /** Free-form text entered instead of selecting an option */
475 > freeformValues?: string[];
476 > }
477 >
478 > export interface ChatInputSelectedManyAnswerValue {
479 > kind: ChatInputAnswerValueKind.SelectedMany;
480 > value: string[];
481 > /** Free-form text entered in addition to selected options */
482 > freeformValues?: string[];
483 > }
484 >
485 > export type ChatInputAnswerValue = ChatInputTextAnswerValue
486 > | ChatInputNumberAnswerValue
487 > | ChatInputBooleanAnswerValue
488 > | ChatInputSelectedAnswerValue
489 > | ChatInputSelectedManyAnswerValue;
490 >
491 > export interface ChatInputAnswered {
492 > /** Answer state */
493 > state: ChatInputAnswerState.Draft | ChatInputAnswerState.Submitted;
494 > /** Answer value */
495 > value: ChatInputAnswerValue;
496 > }
497 >
498 > export interface ChatInputSkipped {
499 > /** Answer state */
500 > state: ChatInputAnswerState.Skipped;
501 > /** Free-form reason or value captured while skipping, if any */
502 > freeformValues?: string[];
503 > }
504 >
505 > /**
506 > * Answer lifecycle state.
507 > *
508 > * @category Chat Input Types
509 > */
510 > export const enum ChatInputAnswerState {
511 > Draft = 'draft',
512 > Submitted = 'submitted',
513 > Skipped = 'skipped',
514 > }
515 >
516 > /**
517 > * Draft, submitted, or skipped answer for one question.
518 > *
519 > * @category Chat Input Types
520 > */
521 > export type ChatInputAnswer = ChatInputAnswered | ChatInputSkipped;
522 >
523 >
524 > // ─── Turn Types ──────────────────────────────────────────────────────────────
525 >
526 > /**
527 > * How a turn ended.
528 > *
529 > * @category Turn Types
530 > */
531 > export const enum TurnState {
532 > Complete = 'complete',
533 > Cancelled = 'cancelled',
534 > Error = 'error',
535 > }
536 >
537 > /**
538 > * Discriminant for {@link MessageAttachment} variants.
539 > *
540 > * @category Turn Types
541 > */
542 > export const enum MessageAttachmentKind {
543 > /** A simple, opaque attachment whose representation is described by the producer. */
544 > Simple = 'simple',
545 > /** An attachment whose data is embedded inline as a base64 string. */
546 > EmbeddedResource = 'embeddedResource',
547 > /** An attachment that references a resource by URI. */
548 > Resource = 'resource',
549 > /** An attachment that references annotations on an annotations channel. */
550 > Annotations = 'annotations',
551 > /** An attachment that references a bounded transcript from another chat. */
552 > Chat = 'chat',
553 > }
554 >
555 > /**
556 > * A completed request/response cycle.
557 > *
558 > * @category Turn Types
559 > */
560 > export interface Turn {
561 > /** Turn identifier */
562 > id: string;
563 > /** ISO 8601 timestamp when this turn started. */
564 > startedAt?: string;
565 > /** Turn duration in milliseconds. */
566 > duration?: number;
567 > /** The message that initiated the turn */
568 > message: Message;
569 > /**
570 > * All response content in stream order: text, tool calls, reasoning, and content refs.
571 > *
572 > * Consumers should derive display text by concatenating markdown parts,
573 > * and find tool calls by filtering for `ToolCall` parts.
574 > */
575 > responseParts: ResponsePart[];
576 > /** Token usage info */
577 > usage: UsageInfo | undefined;
578 > /** How the turn ended */
579 > state: TurnState;
580 > /** Error details if state is `'error'` */
581 > error?: ErrorInfo;
582 > }
583 >
584 > /**
585 > * An in-progress turn — the assistant is actively streaming.
586 > *
587 > * @category Turn Types
588 > */
589 > export interface ActiveTurn {
590 > /** Turn identifier */
591 > id: string;
592 > /** ISO 8601 timestamp when this turn started. */
593 > startedAt: string;
594 > /** The message that initiated the turn */
595 > message: Message;
596 > /**
597 > * All response content in stream order: text, tool calls, reasoning, and content refs.
598 > *
599 > * Tool call parts include `pendingPermissions` when permissions are awaiting user approval.
600 > */
601 > responseParts: ResponsePart[];
602 > /** Token usage info */
603 > usage: UsageInfo | undefined;
604 > }
605 >
606 > /**
607 > * Discriminant for {@link MessageOrigin} — identifies who produced a message.
608 > *
609 > * @category Turn Types
610 > */
611 > export enum MessageKind {
612 > /** Sent directly by the user. */
613 > User = 'user',
614 > /**
615 > * Produced by the agent itself rather than the user — for example, an agent
616 > * that seeds the first message of a chat it spawned.
617 > */
618 > Agent = 'agent',
619 > /**
620 > * Produced by a tool rather than the user — for example, a tool that spawns a
621 > * worker chat whose first message carries a seed prompt.
622 > */
623 > Tool = 'tool',
624 > /** A system-generated notification rather than a direct user message. */
625 > SystemNotification = 'systemNotification',
626 > }
627 >
628 > /**
629 > * Identifies the origin of a {@link Message} — who produced it. For the message
630 > * that initiates a turn ({@link Turn.message}), this is also the origin of the
631 > * turn; for steering or queued messages it is just the origin of that message.
632 > *
633 > * @category Turn Types
634 > */
635 > export interface MessageOrigin {
636 > /** The kind of actor that produced the message. */
637 > kind: MessageKind;
638 > }
639 >
640 > /**
641 > * A message that initiates or steers a turn. Messages can originate from the
642 > * user, the agent, a tool, or be system-generated (see {@link MessageOrigin}).
643 > *
644 > * Attachments MAY be referenced inside {@link Message.text} via their
645 > * {@link MessageAttachmentBase.range} field. Attachments without a range are
646 > * still associated with the message but do not correspond to a specific span
647 > * in the text.
648 > *
649 > * @category Turn Types
650 > */
651 > export interface Message {
652 > /** Message text */
653 > text: string;
654 > /** The origin of the message */
655 > origin: MessageOrigin;
656 > /** File/selection attachments */
657 > attachments?: MessageAttachment[];
658 > /**
659 > * The model this message was, or will be, sent with.
660 > *
661 > * For historic user/agent messages this records the model actually used, so
662 > * a client editing or resending the message can retain that selection. For a
663 > * {@link ChatState.draft | draft} it carries the model the user picked for
664 > * the message they are composing. Absent means the agent host's default
665 > * model applies.
666 > */
667 > model?: ModelSelection;
668 > /**
669 > * The custom agent this message was, or will be, sent with.
670 > *
671 > * For historic messages this records the agent actually used; for a
672 > * {@link ChatState.draft | draft} it carries the agent the user picked.
673 > * Absent means no custom agent — the provider's default behavior applies.
674 > */
675 > agent?: AgentSelection;
676 > /**
677 > * Additional provider-specific metadata for this message.
678 > *
679 > * Clients MAY look for well-known keys here to provide enhanced UI, and
680 > * agent hosts MAY use it to carry context that does not fit any other
681 > * field. Mirrors the MCP `_meta` convention.
682 > */
683 > _meta?: Record<string, unknown>;
684 > }
685 >
686 > /**
687 > * Common fields shared by all {@link MessageAttachment} variants.
688 > *
689 > * @category Turn Types
690 > */
691 > export interface MessageAttachmentBase {
692 > /**
693 > * A human-readable label for the attachment (e.g. the filename of a file
694 > * attachment). Used for display in UI.
695 > */
696 > label: string;
697 >
698 > /**
699 > * If defined, the range in {@link Message.text} that references this
700 > * attachment. This is a text range, not a byte range.
701 > */
702 > range?: TextRange;
703 >
704 > /**
705 > * Advisory display hint for clients rendering this attachment. Recognized
706 > * values include:
707 > *
708 > * - `'image'`: the attachment is an image
709 > * - `'document'`: the attachment is a textual document
710 > * - `'symbol'`: the attachment is a code symbol (e.g. a function or class)
711 > * - `'directory'`: the attachment is a folder
712 > * - `'selection'`: the attachment is a selection within a document
713 > *
714 > * Implementations MAY provide additional values; clients SHOULD fall back
715 > * to a reasonable default when an unknown value is encountered.
716 > */
717 > displayKind?: string;
718 >
719 > /**
720 > * Additional implementation-defined metadata for the attachment.
721 > *
722 > * If the attachment was produced by the `completions` command, the client
723 > * MUST preserve every property of `_meta` originally returned by the agent
724 > * host when sending the user message containing the accepted completion.
725 > */
726 > _meta?: Record<string, unknown>;
727 > }
728 >
729 > /**
730 > * A simple, opaque attachment whose model representation is described by
731 > * the producer.
732 > *
733 > * @category Turn Types
734 > */
735 > export interface SimpleMessageAttachment extends MessageAttachmentBase {
736 > /** Discriminant */
737 > type: MessageAttachmentKind.Simple;
738 >
739 > /**
740 > * Representation of the attachment as it should be shown to the model.
741 > *
742 > * If the attachment was produced by the client, this property MUST be
743 > * defined so the agent host can correctly interpret the attachment. This
744 > * property MAY be omitted when the attachment originated from a
745 > * `completions` response.
746 > */
747 > modelRepresentation?: string;
748 > }
749 >
750 > /**
751 > * An attachment whose data is embedded inline as a base64 string.
752 > *
753 > * Use this for small binary payloads (e.g. a pasted image) that should be
754 > * delivered with the user message itself rather than fetched separately.
755 > *
756 > * @category Turn Types
757 > */
758 > export interface MessageEmbeddedResourceAttachment extends MessageAttachmentBase {
759 > /** Discriminant */
760 > type: MessageAttachmentKind.EmbeddedResource;
761 > /** Base64-encoded binary data */
762 > data: string;
763 > /** Content MIME type (e.g. `"image/png"`, `"application/pdf"`) */
764 > contentType: string;
765 > /**
766 > * Optional selection within the attached textual resource.
767 > *
768 > * Only meaningful for textual resources.
769 > */
770 > selection?: TextSelection;
771 > }
772 >
773 > /**
774 > * An attachment that references a resource by URI. The content is not
775 > * delivered inline; consumers can fetch it via `resourceRead` when needed.
776 > *
777 > * @category Turn Types
778 > */
779 > export interface MessageResourceAttachment extends MessageAttachmentBase, ContentRef {
780 > /** Discriminant */
781 > type: MessageAttachmentKind.Resource;
782 > /**
783 > * Optional selection within the referenced textual resource.
784 > *
785 > * Only meaningful for textual resources.
786 > */
787 > selection?: TextSelection;
788 > }
789 >
790 > /**
791 > * An attachment that references annotations on a session's annotations
792 > * channel (see {@link AnnotationsState}).
793 > *
794 > * When {@link annotationIds} is omitted the attachment references every
795 > * annotation on the channel; when present it references only the listed
796 > * {@link Annotation.id | annotation ids}.
797 > *
798 > * @category Turn Types
799 > */
800 > export interface MessageAnnotationsAttachment extends MessageAttachmentBase {
801 > /** Discriminant */
802 > type: MessageAttachmentKind.Annotations;
803 > /**
804 > * The annotations channel URI (typically `ahp-session:/<uuid>/annotations`).
805 > * Matches {@link AnnotationsSummary.resource}.
806 > */
807 > resource: URI;
808 > /**
809 > * Specific {@link Annotation.id | annotation ids} to reference. When
810 > * omitted, the attachment references all annotations on the channel.
811 > */
812 > annotationIds?: string[];
813 > }
814 >
815 > /**
816 > * An attachment that references a chat transcript through a fixed completed
817 > * turn.
818 > *
819 > * The referenced chat MUST belong to the same session as the message's chat.
820 > * The host resolves the transcript from its first retained turn through
821 > * `endTurn`, inclusive, when accepting the message. Later turns do not
822 > * change the context represented by an already-sent attachment.
823 > *
824 > * Hosts MUST NOT recursively expand chat attachments found inside the
825 > * referenced transcript. Clients SHOULD keep rendering `label` if the
826 > * referenced chat is later pruned, and treat opening `resource` as best-effort.
827 > *
828 > * @category Turn Types
829 > */
830 > export interface MessageChatAttachment extends MessageAttachmentBase {
831 > /** Discriminant */
832 > type: MessageAttachmentKind.Chat;
833 > /** URI of the referenced chat. */
834 > resource: URI;
835 > /** Last completed turn included in the referenced transcript. */
836 > endTurn: string;
837 > }
838 >
839 > /**
840 > * An attachment associated with a {@link Message}.
841 > *
842 > * @category Turn Types
843 > */
844 > export type MessageAttachment =
845 > | SimpleMessageAttachment
846 > | MessageEmbeddedResourceAttachment
847 > | MessageResourceAttachment
848 > | MessageAnnotationsAttachment
849 > | MessageChatAttachment;
850 >
851 > // ─── Response Parts ──────────────────────────────────────────────────────────
852 >
853 > /**
854 > * Discriminant for response part types.
855 > *
856 > * @category Response Parts
857 > */
858 > export const enum ResponsePartKind {
859 > Markdown = 'markdown',
860 > ContentRef = 'contentRef',
861 > ToolCall = 'toolCall',
862 > Reasoning = 'reasoning',
863 > SystemNotification = 'systemNotification',
864 > InputRequest = 'inputRequest',
865 > }
866 >
867 > /**
868 > * @category Response Parts
869 > */
870 > export interface MarkdownResponsePart {
871 > /** Discriminant */
872 > kind: ResponsePartKind.Markdown;
873 > /** Part identifier, used by `chat/delta` to target this part for content appends */
874 > id: string;
875 > /** Markdown content */
876 > content: string;
877 > }
878 >
879 > /**
880 > * A content part that's a reference to large content stored outside the state tree.
881 > *
882 > * @category Response Parts
883 > */
884 > export interface ResourceReponsePart extends ContentRef {
885 > /** Discriminant */
886 > kind: ResponsePartKind.ContentRef;
887 > }
888 >
889 > /**
890 > * A tool call represented as a response part.
891 > *
892 > * Tool calls are part of the response stream, interleaved with text and
893 > * reasoning. The `toolCall.toolCallId` serves as the part identifier for
894 > * actions that target this part.
895 > *
896 > * @category Response Parts
897 > */
898 > export interface ToolCallResponsePart {
899 > /** Discriminant */
900 > kind: ResponsePartKind.ToolCall;
901 > /** Full tool call lifecycle state */
902 > toolCall: ToolCallState;
903 > }
904 >
905 > /**
906 > * Reasoning/thinking content from the model.
907 > *
908 > * @category Response Parts
909 > */
910 > export interface ReasoningResponsePart {
911 > /** Discriminant */
912 > kind: ResponsePartKind.Reasoning;
913 > /** Part identifier, used by `chat/reasoning` to target this part for content appends */
914 > id: string;
915 > /** Accumulated reasoning text */
916 > content: string;
917 > }
918 >
919 > /**
920 > * @category Response Parts
921 > */
922 > export type ResponsePart =
923 > | MarkdownResponsePart
924 > | ResourceReponsePart
925 > | ToolCallResponsePart
926 > | ReasoningResponsePart
927 > | SystemNotificationResponsePart
928 > | InputRequestResponsePart;
929 >
930 > /**
931 > * A live or resolved input request (elicitation) in the turn response stream.
932 > *
933 > * The server inserts the part with `chat/inputRequested`. While
934 > * {@link response} is absent, clients can update answer drafts with
935 > * `chat/inputAnswerChanged` and submit a response with `chat/inputCompleted`.
936 > * Completion updates this part in place so its stream position is stable and
937 > * the full interaction remains durable and backfillable via `fetchTurns`.
938 > *
939 > * If the turn ends without a submitted response, the unresolved part remains
940 > * in the completed turn transcript with {@link response} absent.
941 > *
942 > * @category Response Parts
943 > */
944 > export interface InputRequestResponsePart {
945 > /** Discriminant */
946 > kind: ResponsePartKind.InputRequest;
947 > /**
948 > * The request, carrying its `id`, `message`, `url`, `questions`, and current
949 > * draft or submitted `answers`.
950 > */
951 > request: ChatInputRequest;
952 > /**
953 > * How the request was resolved. Absent until a client submits `accept`,
954 > * `decline`, or `cancel` with `chat/inputCompleted`.
955 > */
956 > response?: ChatInputResponseKind;
957 > }
958 >
959 > /**
960 > * A system notification surfaced as part of the response stream.
961 > *
962 > * System notifications are messages authored by the agent harness
963 > * that need to be visible to both the agent (for situational awareness) and
964 > * the user (for transcript continuity). Examples include "background subagent
965 > * X completed" or "task Y was cancelled".
966 > *
967 > * @category Response Parts
968 > */
969 > export interface SystemNotificationResponsePart {
970 > /** Discriminant */
971 > kind: ResponsePartKind.SystemNotification;
972 > /** The text of the system notification */
973 > content: StringOrMarkdown;
974 > /**
975 > * Additional provider-specific metadata for this notification.
976 > *
977 > * A host MAY attach a machine-readable descriptor of what triggered the
978 > * notification so clients can categorize, icon, group, filter, or localize
979 > * it without parsing `content`. Clients MAY look for well-known keys here to
980 > * provide enhanced UI, and MUST render coherently from `content` alone when
981 > * `_meta` is absent or unrecognized.
982 > */
983 > _meta?: Record<string, unknown>;
984 > }
985 >
986 >
987 > // ─── Tool Call Types ─────────────────────────────────────────────────────────
988 >
989 > /**
990 > * Status of a tool call in the lifecycle state machine.
991 > *
992 > * @category Tool Call Types
993 > */
994 > export const enum ToolCallStatus {
995 > Streaming = 'streaming',
996 > PendingConfirmation = 'pending-confirmation',
997 > Running = 'running',
998 > /**
999 > * Running paused because the MCP server backing this call needs
1000 > * authentication (typically step-up auth for insufficient scope,
1001 > * surfacing mid-execution). See {@link ToolCallAuthRequiredState}.
1002 > */
1003 > AuthRequired = 'auth-required',
1004 > PendingResultConfirmation = 'pending-result-confirmation',
1005 > Completed = 'completed',
1006 > Cancelled = 'cancelled',
1007 > }
1008 >
1009 > /**
1010 > * How a tool call was confirmed for execution.
1011 > *
1012 > * - `NotNeeded` — No confirmation required (auto-approved)
1013 > * - `UserAction` — User explicitly approved
1014 > * - `Setting` — Approved by a persistent user setting
1015 > *
1016 > * @category Tool Call Types
1017 > */
1018 > export const enum ToolCallConfirmationReason {
1019 > NotNeeded = 'not-needed',
1020 > UserAction = 'user-action',
1021 > Setting = 'setting',
1022 > }
1023 >
1024 > /**
1025 > * Identifies a model judge as the source of a confirmation requirement.
1026 > *
1027 > * @category Tool Call Types
1028 > */
1029 > export const enum ToolCallRiskAssessmentKind {
1030 > Judge = 'judge',
1031 > }
1032 >
1033 > /**
1034 > * Lifecycle status of an asynchronous model-judge confirmation decision.
1035 > *
1036 > * @category Tool Call Types
1037 > */
1038 > export const enum ToolCallRiskAssessmentStatus {
1039 > Loading = 'loading',
1040 > Complete = 'complete',
1041 > }
1042 >
1043 > interface ToolCallRiskAssessmentBase {
1044 > kind: ToolCallRiskAssessmentKind;
1045 > }
1046 >
1047 > /**
1048 > * The model judge is still evaluating the tool call.
1049 > *
1050 > * @category Tool Call Types
1051 > */
1052 > export interface ToolCallRiskAssessmentLoadingState extends ToolCallRiskAssessmentBase {
1053 > status: ToolCallRiskAssessmentStatus.Loading;
1054 > }
1055 >
1056 > /**
1057 > * The model judge has completed its evaluation.
1058 > *
1059 > * @category Tool Call Types
1060 > */
1061 > export interface ToolCallRiskAssessmentCompleteState extends ToolCallRiskAssessmentBase {
1062 > status: ToolCallRiskAssessmentStatus.Complete;
1063 > reason: StringOrMarkdown;
1064 > /**
1065 > * The judge's normalized safety score, where `0` is unsafe and `1` is safe.
1066 > * @format float
1067 > */
1068 > safety: number;
1069 > }
1070 >
1071 > export type ToolCallRiskAssessment =
1072 > | ToolCallRiskAssessmentLoadingState
1073 > | ToolCallRiskAssessmentCompleteState;
1074 >
1075 > /**
1076 > * Why a tool call was cancelled.
1077 > *
1078 > * @category Tool Call Types
1079 > */
1080 > export const enum ToolCallCancellationReason {
1081 > Denied = 'denied',
1082 > Skipped = 'skipped',
1083 > ResultDenied = 'result-denied',
1084 > }
1085 >
1086 > /**
1087 > * Whether a confirmation option represents an approval or denial action.
1088 > *
1089 > * @category Tool Call Types
1090 > */
1091 > export const enum ConfirmationOptionKind {
1092 > Approve = 'approve',
1093 > Deny = 'deny',
1094 > }
1095 >
1096 > /**
1097 > * A confirmation option that the server offers for a tool call awaiting
1098 > * approval. Allows richer choices beyond simple approve/deny — for example,
1099 > * "Approve in this Session" or "Deny with reason."
1100 > *
1101 > * @category Tool Call Types
1102 > */
1103 > export interface ConfirmationOption {
1104 > /** Unique identifier for the option, returned in the confirmed action */
1105 > id: string;
1106 > /** Human-readable label displayed to the user */
1107 > label: string;
1108 > /** Whether this option represents an approval or denial */
1109 > kind: ConfirmationOptionKind;
1110 > /**
1111 > * Logical group number for visual categorisation.
1112 > *
1113 > * Clients SHOULD display options in the order they are defined and MAY
1114 > * use differing group numbers to insert dividers between logical clusters
1115 > * of options.
1116 > */
1117 > group?: number;
1118 > }
1119 >
1120 > export const enum ToolCallContributorKind {
1121 > Client = 'client',
1122 > MCP = 'mcp',
1123 > }
1124 >
1125 > export interface ToolCallClientContributor {
1126 > kind: ToolCallContributorKind.Client;
1127 > /**
1128 > * If this tool is provided by a client, the `clientId` of the owning client.
1129 > * Absent for server-side tools.
1130 > *
1131 > * When set, the identified client is responsible for executing the tool and
1132 > * dispatching `chat/toolCallComplete` with the result.
1133 > */
1134 > clientId: string;
1135 > }
1136 >
1137 > export interface ToolCallMcpContributor {
1138 > kind: ToolCallContributorKind.MCP;
1139 > /**
1140 > * Customization ID of the corresponding MCP server in {@link SessionState.customizations}.
1141 > */
1142 > customizationId: string;
1143 > }
1144 >
1145 > export type ToolCallContributor = ToolCallClientContributor | ToolCallMcpContributor;
1146 >
1147 > /**
1148 > * Metadata common to all tool call states.
1149 > *
1150 > * @category Tool Call Types
1151 > * @remarks
1152 > * Fields like `toolName` carry agent-specific identifiers on the wire despite the
1153 > * agent-agnostic design principle. These exist for debugging and logging purposes.
1154 > * A future version may move these to a separate diagnostic channel or namespace them
1155 > * more clearly.
1156 > */
1157 > interface ToolCallBase {
1158 > /** Unique tool call identifier */
1159 > toolCallId: string;
1160 > /** Internal tool name (for debugging/logging) */
1161 > toolName: string;
1162 > /** Human-readable tool name */
1163 > displayName: string;
1164 > /** Human-readable description of what the tool invocation intends to do */
1165 > intention?: string;
1166 > /**
1167 > * Reference to the contributor of the tool being called.
1168 > */
1169 > contributor?: ToolCallContributor;
1170 > /**
1171 > * Additional provider-specific metadata for this tool call.
1172 > *
1173 > * This MAY include a `ui` field corresponding to the MCP Apps (SEP-1865)
1174 > * `McpUiToolMeta` found in MCP tool calls, which may be used in combination
1175 > * with the {@link contributor} to serve MCP Apps.
1176 > */
1177 > _meta?: Record<string, unknown>;
1178 > }
1179 >
1180 > /**
1181 > * Properties available once tool call parameters are fully received.
1182 > *
1183 > * @category Tool Call Types
1184 > */
1185 > interface ToolCallParameterFields {
1186 > /** Message describing what the tool will do */
1187 > invocationMessage: StringOrMarkdown;
1188 > /** Raw tool input */
1189 > toolInput?: string;
1190 > }
1191 >
1192 > /**
1193 > * Tool execution result details, available after execution completes.
1194 > *
1195 > * @category Tool Call Types
1196 > */
1197 > export interface ToolCallResult {
1198 > /** Whether the tool succeeded */
1199 > success: boolean;
1200 > /** Past-tense description of what the tool did */
1201 > pastTenseMessage: StringOrMarkdown;
1202 > /**
1203 > * Unstructured result content blocks.
1204 > *
1205 > * This mirrors the `content` field of MCP `CallToolResult`.
1206 > */
1207 > content?: ToolResultContent[];
1208 > /**
1209 > * Optional structured result object.
1210 > *
1211 > * This mirrors the `structuredContent` field of MCP `CallToolResult`.
1212 > */
1213 > structuredContent?: Record<string, unknown>;
1214 > /** Error details if the tool failed */
1215 > error?: { message: string; code?: string };
1216 > }
1217 >
1218 > /**
1219 > * LM is streaming the tool call parameters.
1220 > *
1221 > * @category Tool Call Types
1222 > */
1223 > export interface ToolCallStreamingState extends ToolCallBase {
1224 > status: ToolCallStatus.Streaming;
1225 > /** Partial parameters accumulated so far */
1226 > partialInput?: string;
1227 > /** Progress message shown while parameters are streaming */
1228 > invocationMessage?: StringOrMarkdown;
1229 > }
1230 >
1231 > /**
1232 > * Parameters are complete, or a running tool requires re-confirmation
1233 > * (e.g. a mid-execution permission check).
1234 > *
1235 > * @category Tool Call Types
1236 > */
1237 > export interface ToolCallPendingConfirmationState extends ToolCallBase, ToolCallParameterFields {
1238 > status: ToolCallStatus.PendingConfirmation;
1239 > /** Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) */
1240 > confirmationTitle?: StringOrMarkdown;
1241 > /** Risk assessment that informed the confirmation requirement. */
1242 > riskAssessment?: ToolCallRiskAssessment;
1243 > /** File edits that this tool call will perform, for preview before confirmation */
1244 > edits?: { items: FileEdit[] };
1245 > /** Whether the agent host allows the client to edit the tool's input parameters before confirming */
1246 > editable?: boolean;
1247 > /**
1248 > * Options the server offers for this confirmation. When present, the client
1249 > * SHOULD render these instead of a plain approve/deny UI. Each option
1250 > * belongs to a {@link ConfirmationOptionGroup} so the client can still
1251 > * categorise the choices.
1252 > */
1253 > options?: ConfirmationOption[];
1254 > }
1255 >
1256 > /**
1257 > * Fields present on every tool call state that exists **after** confirmation
1258 > * has been resolved: {@link ToolCallRunningState}, {@link ToolCallAuthRequiredState},
1259 > * {@link ToolCallPendingResultConfirmationState}, and {@link ToolCallCompletedState}.
1260 > * `ToolCallPendingConfirmationState` (not yet confirmed) and
1261 > * `ToolCallCancelledState` (the denial path — never ran) don't satisfy this
1262 > * invariant, so they keep their own `selectedOption` field independently
1263 > * rather than extending this one.
1264 > *
1265 > * @category Tool Call Types
1266 > */
1267 > interface ToolCallPostConfirmationFields {
1268 > /** How the tool was confirmed for execution */
1269 > confirmed: ToolCallConfirmationReason;
1270 > /** The confirmation option the user selected, if confirmation options were provided */
1271 > selectedOption?: ConfirmationOption;
1272 > }
1273 >
1274 > /**
1275 > * Tool is actively executing.
1276 > *
1277 > * @category Tool Call Types
1278 > */
1279 > export interface ToolCallRunningState extends ToolCallBase, ToolCallParameterFields, ToolCallPostConfirmationFields {
1280 > status: ToolCallStatus.Running;
1281 > /**
1282 > * Partial content produced while the tool is still executing.
1283 > *
1284 > * For example, a terminal content block lets clients subscribe to live
1285 > * output before the tool completes.
1286 > */
1287 > content?: ToolResultContent[];
1288 > }
1289 >
1290 > /**
1291 > * A running tool call is paused because the MCP server backing it needs
1292 > * authentication — most commonly {@link McpAuthRequirement.reason |
1293 > * `insufficientScope`} step-up auth triggered by the `tools/call` request
1294 > * itself. Only ever reached from {@link ToolCallRunningState}, and normally
1295 > * returns there once authenticated: `running` → `auth-required` → `running`
1296 > * → …. A client MAY instead cancel the invocation without authenticating by
1297 > * dispatching a `chat/toolCallComplete` with a **failed** result, always
1298 > * moving straight to {@link ToolCallCompletedState} —
1299 > * `requiresResultConfirmation` is ignored on this path, so it can never
1300 > * enter {@link ToolCallPendingResultConfirmationState}. A **successful**
1301 > * result dispatched from this state is invalid and MUST be rejected/ignored
1302 > * as a no-op by the reducer, since execution never resumed after the
1303 > * challenge.
1304 > *
1305 > * This is the tool-call-level counterpart to
1306 > * {@link McpServerAuthRequiredState} — that state means the MCP *server*
1307 > * cannot serve any request; this one means *this specific invocation* is
1308 > * waiting on the same kind of challenge. The two are dispatched
1309 > * independently and MAY be true at the same time, or not: an
1310 > * `insufficientScope` challenge triggered by a single tool call, for
1311 > * example, need not block the whole server.
1312 > *
1313 > * Because the challenge is always resolved by pushing a token via the
1314 > * existing `authenticate` command, this state can only originate from a
1315 > * tool call {@link ToolCallContributorKind.MCP | contributed by an MCP
1316 > * server} — `contributor` is narrowed accordingly (unlike the optional,
1317 > * multi-kind `contributor` on other tool call states).
1318 > *
1319 > * @category Tool Call Types
1320 > */
1321 > export interface ToolCallAuthRequiredState extends ToolCallBase, ToolCallParameterFields, ToolCallPostConfirmationFields {
1322 > status: ToolCallStatus.AuthRequired;
1323 > /** The MCP server that contributed this tool call — always MCP, never a client tool. */
1324 > contributor: ToolCallMcpContributor;
1325 > /** The authentication challenge blocking this invocation. */
1326 > auth: McpAuthRequirement;
1327 > /** Partial content produced before the call paused for authentication. */
1328 > content?: ToolResultContent[];
1329 > }
1330 >
1331 > /**
1332 > * Tool finished executing, waiting for client to approve the result.
1333 > *
1334 > * @category Tool Call Types
1335 > */
1336 > export interface ToolCallPendingResultConfirmationState extends ToolCallBase, ToolCallParameterFields, ToolCallResult, ToolCallPostConfirmationFields {
1337 > status: ToolCallStatus.PendingResultConfirmation;
1338 > }
1339 >
1340 > /**
1341 > * Tool completed successfully or with an error.
1342 > *
1343 > * @category Tool Call Types
1344 > */
1345 > export interface ToolCallCompletedState extends ToolCallBase, ToolCallParameterFields, ToolCallResult, ToolCallPostConfirmationFields {
1346 > status: ToolCallStatus.Completed;
1347 > }
1348 >
1349 > /**
1350 > * Tool call was cancelled before execution.
1351 > *
1352 > * @category Tool Call Types
1353 > */
1354 > export interface ToolCallCancelledState extends ToolCallBase, ToolCallParameterFields {
1355 > status: ToolCallStatus.Cancelled;
1356 > /** Why the tool was cancelled */
1357 > reason: ToolCallCancellationReason;
1358 > /** Optional message explaining the cancellation */
1359 > reasonMessage?: StringOrMarkdown;
1360 > /** What the user suggested doing instead */
1361 > userSuggestion?: Message;
1362 > /** The confirmation option the user selected, if confirmation options were provided */
1363 > selectedOption?: ConfirmationOption;
1364 > }
1365 >
1366 > /**
1367 > * Discriminated union of all tool call lifecycle states.
1368 > *
1369 > * See the [state model guide](/guide/state-model.html#tool-call-lifecycle)
1370 > * for the full state machine diagram.
1371 > *
1372 > * @category Tool Call Types
1373 > */
1374 > export type ToolCallState =
1375 > | ToolCallStreamingState
1376 > | ToolCallPendingConfirmationState
1377 > | ToolCallRunningState
1378 > | ToolCallAuthRequiredState
1379 > | ToolCallPendingResultConfirmationState
1380 > | ToolCallCompletedState
1381 > | ToolCallCancelledState;
1382 >
1383 > /**
1384 > * The two tool-call states that block on a client confirmation: parameter
1385 > * confirmation before execution ({@link ToolCallPendingConfirmationState}) and
1386 > * result confirmation after execution
1387 > * ({@link ToolCallPendingResultConfirmationState}).
1388 > *
1389 > * {@link ToolCallAuthRequiredState} is intentionally **not** part of this
1390 > * union: it doesn't block on a `chat/toolCallConfirmed`-style client
1391 > * decision, it blocks on the client completing an OAuth flow and calling
1392 > * `authenticate`. See {@link SessionToolAuthenticationRequest} for its
1393 > * session-level surfacing.
1394 > *
1395 > * Surfaced at the session level by {@link SessionToolConfirmationRequest}.
1396 > *
1397 > * @category Tool Call Types
1398 > */
1399 > export type ToolCallConfirmationState =
1400 > | ToolCallPendingConfirmationState
1401 > | ToolCallPendingResultConfirmationState;
1402 >
1403 >
1404 > // ─── Tool Result Content ─────────────────────────────────────────────────────
1405 >
1406 > /**
1407 > * Discriminant for tool result content types.
1408 > *
1409 > * @category Tool Result Content
1410 > */
1411 > export const enum ToolResultContentType {
1412 > Text = 'text',
1413 > EmbeddedResource = 'embeddedResource',
1414 > Resource = 'resource',
1415 > FileEdit = 'fileEdit',
1416 > Terminal = 'terminal',
1417 > Subagent = 'subagent',
1418 > }
1419 >
1420 > /**
1421 > * Text content in a tool result.
1422 > *
1423 > * Mirrors MCP `TextContent`.
1424 > *
1425 > * @category Tool Result Content
1426 > */
1427 > export interface ToolResultTextContent {
1428 > type: ToolResultContentType.Text;
1429 > /** The text content */
1430 > text: string;
1431 > }
1432 >
1433 > /**
1434 > * Base64-encoded binary content embedded in a tool result.
1435 > *
1436 > * Mirrors MCP `EmbeddedResource` for inline binary data.
1437 > *
1438 > * @category Tool Result Content
1439 > */
1440 > export interface ToolResultEmbeddedResourceContent {
1441 > type: ToolResultContentType.EmbeddedResource;
1442 > /** Base64-encoded data */
1443 > data: string;
1444 > /** Content type (e.g. `"image/png"`, `"application/pdf"`) */
1445 > contentType: string;
1446 > }
1447 >
1448 > /**
1449 > * A reference to a resource stored outside the tool result.
1450 > *
1451 > * Wraps {@link ContentRef} for lazy-loading large results.
1452 > *
1453 > * @category Tool Result Content
1454 > */
1455 > export interface ToolResultResourceContent extends ContentRef {
1456 > type: ToolResultContentType.Resource;
1457 > }
1458 >
1459 > /**
1460 > * Describes a file modification performed by a tool.
1461 > *
1462 > * @category Tool Result Content
1463 > */
1464 > export interface ToolResultFileEditContent extends FileEdit {
1465 > type: ToolResultContentType.FileEdit;
1466 > }
1467 >
1468 > /**
1469 > * A reference to a terminal whose output is relevant to this tool result.
1470 > *
1471 > * Clients can subscribe to the terminal's URI to stream its output in real
1472 > * time, providing live feedback while a tool is executing.
1473 > *
1474 > * When the command exits, {@link result} is filled in on the completed
1475 > * result, retaining the outcome for clients that did not subscribe. This
1476 > * records the command's exit, not the terminal's — the terminal may keep
1477 > * running afterwards.
1478 > *
1479 > * @category Tool Result Content
1480 > */
1481 > export interface ToolResultTerminalContent {
1482 > type: ToolResultContentType.Terminal;
1483 > /** Terminal URI (subscribable for full terminal state) */
1484 > resource: URI;
1485 > /** Display title for the terminal content */
1486 > title: string;
1487 > /**
1488 > * Whether this terminal-style resource is backed by a pseudoterminal.
1489 > * When `false`, output is plain text and clients do not need to parse
1490 > * VT sequences.
1491 > */
1492 > isPty?: boolean;
1493 > /** Outcome of the command, present once it has exited. */
1494 > result?: TerminalCommandResult;
1495 > }
1496 >
1497 > /**
1498 > * Outcome of a command run in a terminal-style tool, filled in on
1499 > * {@link ToolResultTerminalContent.result} once the command exits.
1500 > *
1501 > * @category Tool Result Content
1502 > */
1503 > export interface TerminalCommandResult {
1504 > /** Exit code from the completed command, if reported by the runtime */
1505 > exitCode?: number;
1506 > /**
1507 > * Preview of the command's output, for clients that are not subscribed
1508 > * to the terminal or that arrive after it is disposed. When `isPty` is
1509 > * `true` the preview may contain VT sequences; when `false` it is plain
1510 > * text.
1511 > */
1512 > preview?: string;
1513 > /** Whether `preview` is known to be incomplete or truncated */
1514 > truncated?: boolean;
1515 > }
1516 >
1517 > /**
1518 > * A reference, embedded in a tool result, to a worker chat spawned by the tool
1519 > * call (a sub-agent delegation), referenced by a chat URI (`ahp-chat:/...`).
1520 > *
1521 > * This is the spawning tool call's forward view of the worker. The worker chat
1522 > * records the same edge in reverse via its {@link ChatOrigin} (`kind: 'tool'`),
1523 > * whose `toolCallId` identifies the tool call that emitted this content.
1524 > *
1525 > * @category Tool Result Content
1526 > */
1527 > export interface ToolResultSubagentContent {
1528 > type: ToolResultContentType.Subagent;
1529 > /** Worker chat URI (subscribable for full chat state) */
1530 > resource: URI;
1531 > /** Display title for the subagent */
1532 > title: string;
1533 > /** Internal agent name */
1534 > agentName?: string;
1535 > /** Human-readable description of the subagent's task */
1536 > description?: string;
1537 > }
1538 >
1539 > /**
1540 > * Content block in a tool result.
1541 > *
1542 > * Mirrors the content blocks in MCP `CallToolResult.content`, plus
1543 > * `ToolResultResourceContent` for lazy-loading large results,
1544 > * `ToolResultFileEditContent` for file edit diffs,
1545 > * `ToolResultTerminalContent` for live terminal output and
1546 > * command completion metadata, and
1547 > * `ToolResultSubagentContent` for tool-spawned worker chats (AHP extensions).
1548 > *
1549 > * @category Tool Result Content
1550 > */
1551 > export type ToolResultContent =
1552 > | ToolResultTextContent
1553 > | ToolResultEmbeddedResourceContent
1554 > | ToolResultResourceContent
1555 > | ToolResultFileEditContent
1556 > | ToolResultTerminalContent
1557 > | ToolResultSubagentContent;
src/vs/workbench/contrib/debug/common/debug.ts 1431 covered LOC · 5 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- debug.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IAction } from '../../../../base/common/actions.js';
7 > import { VSBuffer } from '../../../../base/common/buffer.js';
8 > import { CancellationToken } from '../../../../base/common/cancellation.js';
9 > import { Color } from '../../../../base/common/color.js';
10 > import { Event } from '../../../../base/common/event.js';
11 > import { IJSONSchema, IJSONSchemaSnippet } from '../../../../base/common/jsonSchema.js';
12 > import { IDisposable } from '../../../../base/common/lifecycle.js';
13 > import severity from '../../../../base/common/severity.js';
14 > import { URI, UriComponents, URI as uri } from '../../../../base/common/uri.js';
15 > import { IPosition, Position } from '../../../../editor/common/core/position.js';
16 > import { IRange } from '../../../../editor/common/core/range.js';
17 > import * as editorCommon from '../../../../editor/common/editorCommon.js';
18 > import { ITextModel as EditorIModel } from '../../../../editor/common/model.js';
19 > import * as nls from '../../../../nls.js';
20 > import { ConfigurationTarget } from '../../../../platform/configuration/common/configuration.js';
21 > import { RawContextKey } from '../../../../platform/contextkey/common/contextkey.js';
22 > import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
23 > import { ITelemetryEndpoint } from '../../../../platform/telemetry/common/telemetry.js';
24 > import { IWorkspaceFolder } from '../../../../platform/workspace/common/workspace.js';
25 > import { IEditorPane } from '../../../common/editor.js';
26 > import { DebugCompoundRoot } from './debugCompoundRoot.js';
27 > import { IDataBreakpointOptions, IFunctionBreakpointOptions, IInstructionBreakpointOptions } from './debugModel.js';
28 > import { Source } from './debugSource.js';
29 > import { ITaskIdentifier } from '../../tasks/common/tasks.js';
30 > import { LiveTestResult } from '../../testing/common/testResult.js';
31 > import { IEditorService } from '../../../services/editor/common/editorService.js';
32 > import { IView } from '../../../common/views.js';
33 >
34 > export const VIEWLET_ID = 'workbench.view.debug';
35 >
36 > export const VARIABLES_VIEW_ID = 'workbench.debug.variablesView';
37 > export const WATCH_VIEW_ID = 'workbench.debug.watchExpressionsView';
38 > export const CALLSTACK_VIEW_ID = 'workbench.debug.callStackView';
39 > export const LOADED_SCRIPTS_VIEW_ID = 'workbench.debug.loadedScriptsView';
40 > export const BREAKPOINTS_VIEW_ID = 'workbench.debug.breakPointsView';
41 > export const DISASSEMBLY_VIEW_ID = 'workbench.debug.disassemblyView';
42 > export const DEBUG_PANEL_ID = 'workbench.panel.repl';
43 > export const REPL_VIEW_ID = 'workbench.panel.repl.view';
44 > export const CONTEXT_DEBUG_TYPE = new RawContextKey<string>('debugType', undefined, { type: 'string', description: nls.localize('debugType', "Debug type of the active debug session. For example 'python'.") });
45 > export const CONTEXT_DEBUG_CONFIGURATION_TYPE = new RawContextKey<string>('debugConfigurationType', undefined, { type: 'string', description: nls.localize('debugConfigurationType', "Debug type of the selected launch configuration. For example 'python'.") });
46 > export const CONTEXT_DEBUG_STATE = new RawContextKey<string>('debugState', 'inactive', { type: 'string', description: nls.localize('debugState', "State that the focused debug session is in. One of the following: 'inactive', 'initializing', 'stopped' or 'running'.") });
47 > export const CONTEXT_DEBUG_UX_KEY = 'debugUx';
48 > export const CONTEXT_DEBUG_UX = new RawContextKey<string>(CONTEXT_DEBUG_UX_KEY, 'default', { type: 'string', description: nls.localize('debugUX', "Debug UX state. When there are no debug configurations it is 'simple', otherwise 'default'. Used to decide when to show welcome views in the debug viewlet.") });
49 > export const CONTEXT_HAS_DEBUGGED = new RawContextKey<boolean>('hasDebugged', false, { type: 'boolean', description: nls.localize('hasDebugged', "True when a debug session has been started at least once, false otherwise.") });
50 > export const CONTEXT_IN_DEBUG_MODE = new RawContextKey<boolean>('inDebugMode', false, { type: 'boolean', description: nls.localize('inDebugMode', "True when debugging, false otherwise.") });
51 > export const CONTEXT_IN_DEBUG_REPL = new RawContextKey<boolean>('inDebugRepl', false, { type: 'boolean', description: nls.localize('inDebugRepl', "True when focus is in the debug console, false otherwise.") });
52 > export const CONTEXT_BREAKPOINT_WIDGET_VISIBLE = new RawContextKey<boolean>('breakpointWidgetVisible', false, { type: 'boolean', description: nls.localize('breakpointWidgetVisibile', "True when breakpoint editor zone widget is visible, false otherwise.") });
53 > export const CONTEXT_IN_BREAKPOINT_WIDGET = new RawContextKey<boolean>('inBreakpointWidget', false, { type: 'boolean', description: nls.localize('inBreakpointWidget', "True when focus is in the breakpoint editor zone widget, false otherwise.") });
54 > export const CONTEXT_BREAKPOINTS_FOCUSED = new RawContextKey<boolean>('breakpointsFocused', true, { type: 'boolean', description: nls.localize('breakpointsFocused', "True when the BREAKPOINTS view is focused, false otherwise.") });
55 > export const CONTEXT_WATCH_EXPRESSIONS_FOCUSED = new RawContextKey<boolean>('watchExpressionsFocused', true, { type: 'boolean', description: nls.localize('watchExpressionsFocused', "True when the WATCH view is focused, false otherwise.") });
56 > export const CONTEXT_WATCH_EXPRESSIONS_EXIST = new RawContextKey<boolean>('watchExpressionsExist', false, { type: 'boolean', description: nls.localize('watchExpressionsExist', "True when at least one watch expression exists, false otherwise.") });
57 > export const CONTEXT_VARIABLES_FOCUSED = new RawContextKey<boolean>('variablesFocused', true, { type: 'boolean', description: nls.localize('variablesFocused', "True when the VARIABLES views is focused, false otherwise") });
58 > export const CONTEXT_EXPRESSION_SELECTED = new RawContextKey<boolean>('expressionSelected', false, { type: 'boolean', description: nls.localize('expressionSelected', "True when an expression input box is open in either the WATCH or the VARIABLES view, false otherwise.") });
59 > export const CONTEXT_BREAKPOINT_INPUT_FOCUSED = new RawContextKey<boolean>('breakpointInputFocused', false, { type: 'boolean', description: nls.localize('breakpointInputFocused', "True when the input box has focus in the BREAKPOINTS view.") });
60 > export const CONTEXT_CALLSTACK_ITEM_TYPE = new RawContextKey<string>('callStackItemType', undefined, { type: 'string', description: nls.localize('callStackItemType', "Represents the item type of the focused element in the CALL STACK view. For example: 'session', 'thread', 'stackFrame'") });
61 > export const CONTEXT_CALLSTACK_SESSION_IS_ATTACH = new RawContextKey<boolean>('callStackSessionIsAttach', false, { type: 'boolean', description: nls.localize('callStackSessionIsAttach', "True when the session in the CALL STACK view is attach, false otherwise. Used internally for inline menus in the CALL STACK view.") });
62 > export const CONTEXT_CALLSTACK_ITEM_STOPPED = new RawContextKey<boolean>('callStackItemStopped', false, { type: 'boolean', description: nls.localize('callStackItemStopped', "True when the focused item in the CALL STACK is stopped. Used internally for inline menus in the CALL STACK view.") });
63 > export const CONTEXT_CALLSTACK_SESSION_HAS_ONE_THREAD = new RawContextKey<boolean>('callStackSessionHasOneThread', false, { type: 'boolean', description: nls.localize('callStackSessionHasOneThread', "True when the focused session in the CALL STACK view has exactly one thread. Used internally for inline menus in the CALL STACK view.") });
64 > export const CONTEXT_CALLSTACK_FOCUSED = new RawContextKey<boolean>('callStackFocused', true, { type: 'boolean', description: nls.localize('callStackFocused', "True when the CALLSTACK view is focused, false otherwise.") });
65 > export const CONTEXT_WATCH_ITEM_TYPE = new RawContextKey<string>('watchItemType', undefined, { type: 'string', description: nls.localize('watchItemType', "Represents the item type of the focused element in the WATCH view. For example: 'expression', 'variable'") });
66 > export const CONTEXT_CAN_VIEW_MEMORY = new RawContextKey<boolean>('canViewMemory', undefined, { type: 'boolean', description: nls.localize('canViewMemory', "Indicates whether the item in the view has an associated memory reference.") });
67 > export const CONTEXT_BREAKPOINT_ITEM_TYPE = new RawContextKey<string>('breakpointItemType', undefined, { type: 'string', description: nls.localize('breakpointItemType', "Represents the item type of the focused element in the BREAKPOINTS view. For example: 'breakpoint', 'exceptionBreakpoint', 'functionBreakpoint', 'dataBreakpoint'") });
68 > export const CONTEXT_BREAKPOINT_ITEM_IS_DATA_BYTES = new RawContextKey<boolean>('breakpointItemBytes', undefined, { type: 'boolean', description: nls.localize('breakpointItemIsDataBytes', "Whether the breakpoint item is a data breakpoint on a byte range.") });
69 > export const CONTEXT_BREAKPOINT_HAS_MODES = new RawContextKey<boolean>('breakpointHasModes', false, { type: 'boolean', description: nls.localize('breakpointHasModes', "Whether the breakpoint has multiple modes it can switch to.") });
70 > export const CONTEXT_BREAKPOINT_SUPPORTS_CONDITION = new RawContextKey<boolean>('breakpointSupportsCondition', false, { type: 'boolean', description: nls.localize('breakpointSupportsCondition', "True when the focused breakpoint supports conditions.") });
71 > export const CONTEXT_LOADED_SCRIPTS_SUPPORTED = new RawContextKey<boolean>('loadedScriptsSupported', false, { type: 'boolean', description: nls.localize('loadedScriptsSupported', "True when the focused sessions supports the LOADED SCRIPTS view") });
72 > export const CONTEXT_LOADED_SCRIPTS_ITEM_TYPE = new RawContextKey<string>('loadedScriptsItemType', undefined, { type: 'string', description: nls.localize('loadedScriptsItemType', "Represents the item type of the focused element in the LOADED SCRIPTS view.") });
73 > export const CONTEXT_FOCUSED_SESSION_IS_ATTACH = new RawContextKey<boolean>('focusedSessionIsAttach', false, { type: 'boolean', description: nls.localize('focusedSessionIsAttach', "True when the focused session is 'attach'.") });
74 > export const CONTEXT_FOCUSED_SESSION_IS_NO_DEBUG = new RawContextKey<boolean>('focusedSessionIsNoDebug', false, { type: 'boolean', description: nls.localize('focusedSessionIsNoDebug', "True when the focused session is run without debugging.") });
75 > export const CONTEXT_STEP_BACK_SUPPORTED = new RawContextKey<boolean>('stepBackSupported', false, { type: 'boolean', description: nls.localize('stepBackSupported', "True when the focused session supports 'stepBack' requests.") });
76 > export const CONTEXT_RESTART_FRAME_SUPPORTED = new RawContextKey<boolean>('restartFrameSupported', false, { type: 'boolean', description: nls.localize('restartFrameSupported', "True when the focused session supports 'restartFrame' requests.") });
77 > export const CONTEXT_STACK_FRAME_SUPPORTS_RESTART = new RawContextKey<boolean>('stackFrameSupportsRestart', false, { type: 'boolean', description: nls.localize('stackFrameSupportsRestart', "True when the focused stack frame supports 'restartFrame'.") });
78 > export const CONTEXT_JUMP_TO_CURSOR_SUPPORTED = new RawContextKey<boolean>('jumpToCursorSupported', false, { type: 'boolean', description: nls.localize('jumpToCursorSupported', "True when the focused session supports 'jumpToCursor' request.") });
79 > export const CONTEXT_STEP_INTO_TARGETS_SUPPORTED = new RawContextKey<boolean>('stepIntoTargetsSupported', false, { type: 'boolean', description: nls.localize('stepIntoTargetsSupported', "True when the focused session supports 'stepIntoTargets' request.") });
80 > export const CONTEXT_BREAKPOINTS_EXIST = new RawContextKey<boolean>('breakpointsExist', false, { type: 'boolean', description: nls.localize('breakpointsExist', "True when at least one breakpoint exists.") });
81 > export const CONTEXT_DEBUGGERS_AVAILABLE = new RawContextKey<boolean>('debuggersAvailable', false, { type: 'boolean', description: nls.localize('debuggersAvailable', "True when there is at least one debug extensions active.") });
82 > export const CONTEXT_DEBUG_EXTENSION_AVAILABLE = new RawContextKey<boolean>('debugExtensionAvailable', true, { type: 'boolean', description: nls.localize('debugExtensionsAvailable', "True when there is at least one debug extension installed and enabled.") });
83 > export const CONTEXT_DEBUG_PROTOCOL_VARIABLE_MENU_CONTEXT = new RawContextKey<string>('debugProtocolVariableMenuContext', undefined, { type: 'string', description: nls.localize('debugProtocolVariableMenuContext', "Represents the context the debug adapter sets on the focused variable in the VARIABLES view.") });
84 > export const CONTEXT_SET_VARIABLE_SUPPORTED = new RawContextKey<boolean>('debugSetVariableSupported', false, { type: 'boolean', description: nls.localize('debugSetVariableSupported', "True when the focused session supports 'setVariable' request.") });
85 > export const CONTEXT_SET_DATA_BREAKPOINT_BYTES_SUPPORTED = new RawContextKey<boolean>('debugSetDataBreakpointAddressSupported', false, { type: 'boolean', description: nls.localize('debugSetDataBreakpointAddressSupported', "True when the focused session supports 'getBreakpointInfo' request on an address.") });
86 > export const CONTEXT_SET_EXPRESSION_SUPPORTED = new RawContextKey<boolean>('debugSetExpressionSupported', false, { type: 'boolean', description: nls.localize('debugSetExpressionSupported', "True when the focused session supports 'setExpression' request.") });
87 > export const CONTEXT_BREAK_WHEN_VALUE_CHANGES_SUPPORTED = new RawContextKey<boolean>('breakWhenValueChangesSupported', false, { type: 'boolean', description: nls.localize('breakWhenValueChangesSupported', "True when the focused session supports to break when value changes.") });
88 > export const CONTEXT_BREAK_WHEN_VALUE_IS_ACCESSED_SUPPORTED = new RawContextKey<boolean>('breakWhenValueIsAccessedSupported', false, { type: 'boolean', description: nls.localize('breakWhenValueIsAccessedSupported', "True when the focused breakpoint supports to break when value is accessed.") });
89 > export const CONTEXT_BREAK_WHEN_VALUE_IS_READ_SUPPORTED = new RawContextKey<boolean>('breakWhenValueIsReadSupported', false, { type: 'boolean', description: nls.localize('breakWhenValueIsReadSupported', "True when the focused breakpoint supports to break when value is read.") });
90 > export const CONTEXT_TERMINATE_DEBUGGEE_SUPPORTED = new RawContextKey<boolean>('terminateDebuggeeSupported', false, { type: 'boolean', description: nls.localize('terminateDebuggeeSupported', "True when the focused session supports the terminate debuggee capability.") });
91 > export const CONTEXT_SUSPEND_DEBUGGEE_SUPPORTED = new RawContextKey<boolean>('suspendDebuggeeSupported', false, { type: 'boolean', description: nls.localize('suspendDebuggeeSupported', "True when the focused session supports the suspend debuggee capability.") });
92 > export const CONTEXT_TERMINATE_THREADS_SUPPORTED = new RawContextKey<boolean>('terminateThreadsSupported', false, { type: 'boolean', description: nls.localize('terminateThreadsSupported', "True when the focused session supports the terminate threads capability.") });
93 > export const CONTEXT_VARIABLE_EVALUATE_NAME_PRESENT = new RawContextKey<boolean>('variableEvaluateNamePresent', false, { type: 'boolean', description: nls.localize('variableEvaluateNamePresent', "True when the focused variable has an 'evaluateName' field set.") });
94 > export const CONTEXT_VARIABLE_IS_READONLY = new RawContextKey<boolean>('variableIsReadonly', false, { type: 'boolean', description: nls.localize('variableIsReadonly', "True when the focused variable is read-only.") });
95 > export const CONTEXT_VARIABLE_VALUE = new RawContextKey<boolean>('variableValue', false, { type: 'string', description: nls.localize('variableValue', "Value of the variable, present for debug visualization clauses.") });
96 > export const CONTEXT_VARIABLE_TYPE = new RawContextKey<boolean>('variableType', false, { type: 'string', description: nls.localize('variableType', "Type of the variable, present for debug visualization clauses.") });
97 > export const CONTEXT_VARIABLE_INTERFACES = new RawContextKey<boolean>('variableInterfaces', false, { type: 'array', description: nls.localize('variableInterfaces', "Any interfaces or contracts that the variable satisfies, present for debug visualization clauses.") });
98 > export const CONTEXT_VARIABLE_NAME = new RawContextKey<boolean>('variableName', false, { type: 'string', description: nls.localize('variableName', "Name of the variable, present for debug visualization clauses.") });
99 > export const CONTEXT_VARIABLE_LANGUAGE = new RawContextKey<boolean>('variableLanguage', false, { type: 'string', description: nls.localize('variableLanguage', "Language of the variable source, present for debug visualization clauses.") });
100 > export const CONTEXT_VARIABLE_EXTENSIONID = new RawContextKey<boolean>('variableExtensionId', false, { type: 'string', description: nls.localize('variableExtensionId', "Extension ID of the variable source, present for debug visualization clauses.") });
101 > export const CONTEXT_EXCEPTION_WIDGET_VISIBLE = new RawContextKey<boolean>('exceptionWidgetVisible', false, { type: 'boolean', description: nls.localize('exceptionWidgetVisible', "True when the exception widget is visible.") });
102 > export const CONTEXT_MULTI_SESSION_REPL = new RawContextKey<boolean>('multiSessionRepl', false, { type: 'boolean', description: nls.localize('multiSessionRepl', "True when there is more than 1 debug console.") });
103 > export const CONTEXT_MULTI_SESSION_DEBUG = new RawContextKey<boolean>('multiSessionDebug', false, { type: 'boolean', description: nls.localize('multiSessionDebug', "True when there is more than 1 active debug session.") });
104 > export const CONTEXT_DISASSEMBLE_REQUEST_SUPPORTED = new RawContextKey<boolean>('disassembleRequestSupported', false, { type: 'boolean', description: nls.localize('disassembleRequestSupported', "True when the focused sessions supports disassemble request.") });
105 > export const CONTEXT_DISASSEMBLY_VIEW_FOCUS = new RawContextKey<boolean>('disassemblyViewFocus', false, { type: 'boolean', description: nls.localize('disassemblyViewFocus', "True when the Disassembly View is focused.") });
106 > export const CONTEXT_LANGUAGE_SUPPORTS_DISASSEMBLE_REQUEST = new RawContextKey<boolean>('languageSupportsDisassembleRequest', false, { type: 'boolean', description: nls.localize('languageSupportsDisassembleRequest', "True when the language in the current editor supports disassemble request.") });
107 > export const CONTEXT_FOCUSED_STACK_FRAME_HAS_INSTRUCTION_POINTER_REFERENCE = new RawContextKey<boolean>('focusedStackFrameHasInstructionReference', false, { type: 'boolean', description: nls.localize('focusedStackFrameHasInstructionReference', "True when the focused stack frame has instruction pointer reference.") });
108 >
109 > export const debuggerDisabledMessage = (debugType: string) => nls.localize('debuggerDisabled', "Configured debug type '{0}' is installed but not supported in this environment.", debugType);
110 >
111 > export const EDITOR_CONTRIBUTION_ID = 'editor.contrib.debug';
112 > export const BREAKPOINT_EDITOR_CONTRIBUTION_ID = 'editor.contrib.breakpoint';
113 > export const DEBUG_SCHEME = 'debug';
114 > export const INTERNAL_CONSOLE_OPTIONS_SCHEMA = {
115 > enum: ['neverOpen', 'openOnSessionStart', 'openOnFirstSessionStart'],
116 > default: 'openOnFirstSessionStart',
117 > description: nls.localize('internalConsoleOptions', "Controls when the internal Debug Console should open.")
118 > };
119 >
120 > export interface IDebugViewWithVariables extends IView {
121 > readonly treeSelection: IExpression[];
122 > }
123 >
124 > // raw
125 >
126 > export interface IRawModelUpdate {
127 > sessionId: string;
128 > threads: DebugProtocol.Thread[];
129 > stoppedDetails?: IRawStoppedDetails;
130 > }
131 >
132 > export interface IRawStoppedDetails {
133 > reason?: string;
134 > description?: string;
135 > threadId?: number;
136 > text?: string;
137 > totalFrames?: number;
138 > allThreadsStopped?: boolean;
139 > preserveFocusHint?: boolean;
140 > framesErrorMessage?: string;
141 > hitBreakpointIds?: number[];
142 > }
143 >
144 > // model
145 >
146 > export interface ITreeElement {
147 > getId(): string;
148 > }
149 >
150 > export interface IReplElement extends ITreeElement {
151 > toString(includeSource?: boolean): string;
152 > readonly sourceData?: IReplElementSource;
153 > }
154 >
155 > export interface INestingReplElement extends IReplElement {
156 > readonly hasChildren: boolean;
157 > getChildren(): Promise<IReplElement[]> | IReplElement[];
158 > }
159 >
160 > export interface IReplElementSource {
161 > readonly source: Source;
162 > readonly lineNumber: number;
163 > readonly column: number;
164 > }
165 >
166 > export interface IExpressionValue {
167 > readonly value: string;
168 > readonly type?: string;
169 > valueChanged?: boolean;
170 > }
171 >
172 > export interface IExpressionContainer extends ITreeElement, IExpressionValue {
173 > readonly hasChildren: boolean;
174 > getSession(): IDebugSession | undefined;
175 > evaluateLazy(): Promise<void>;
176 > getChildren(): Promise<IExpression[]>;
177 > readonly reference?: number;
178 > readonly memoryReference?: string;
179 > readonly presentationHint?: DebugProtocol.VariablePresentationHint | undefined;
180 > readonly valueLocationReference?: number;
181 > }
182 >
183 > export interface IExpression extends IExpressionContainer {
184 > name: string;
185 > }
186 >
187 > export interface IDebugger {
188 > readonly type: string;
189 > createDebugAdapter(session: IDebugSession): Promise<IDebugAdapter>;
190 > runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, sessionId: string): Promise<number | undefined>;
191 > startDebugging(args: IConfig, parentSessionId: string): Promise<boolean>;
192 > getCustomTelemetryEndpoint(): ITelemetryEndpoint | undefined;
193 > getInitialConfigurationContent(initialConfigs?: IConfig[]): Promise<string>;
194 > }
195 >
196 > export interface IDebuggerMetadata {
197 > label: string;
198 > type: string;
199 > strings?: { [key in DebuggerString]: string };
200 > interestedInLanguage(languageId: string): boolean;
201 > }
202 >
203 > export const enum State {
204 > Inactive,
205 > Initializing,
206 > Stopped,
207 > Running
208 > }
209 >
210 > export function getStateLabel(state: State): string {
211 switch (state) {
212 case State.Initializing: return 'initializing';
216 }
217 }
218 > debug.ts
219 > export interface AdapterEndEvent {
220 > error?: Error;
221 > sessionLengthInSeconds: number;
222 > emittedStopped: boolean;
223 > }
224 >
225 > export interface LoadedSourceEvent {
226 > reason: 'new' | 'changed' | 'removed';
227 > source: Source;
228 > }
229 >
230 > export type IDebugSessionReplMode = 'separate' | 'mergeWithParent';
231 >
232 > export interface IDebugTestRunReference {
233 > runId: string;
234 > taskId: string;
235 > }
236 >
237 > export interface IDebugSessionOptions {
238 > noDebug?: boolean;
239 > parentSession?: IDebugSession;
240 > lifecycleManagedByParent?: boolean;
241 > repl?: IDebugSessionReplMode;
242 > compoundRoot?: DebugCompoundRoot;
243 > compact?: boolean;
244 > startedByUser?: boolean;
245 > saveBeforeRestart?: boolean;
246 > suppressDebugToolbar?: boolean;
247 > suppressDebugStatusbar?: boolean;
248 > suppressDebugView?: boolean;
249 > /**
250 > * Set if the debug session is correlated with a test run. Stopping/restarting
251 > * the session will instead stop/restart the test run.
252 > */
253 > testRun?: IDebugTestRunReference;
254 > }
255 >
256 > export interface IDataBreakpointInfoResponse {
257 > dataId: string | null;
258 > description: string;
259 > canPersist?: boolean;
260 > accessTypes?: DebugProtocol.DataBreakpointAccessType[];
261 > }
262 >
263 > export interface IMemoryInvalidationEvent {
264 > fromOffset: number;
265 > toOffset: number;
266 > }
267 >
268 > export const enum MemoryRangeType {
269 > Valid,
270 > Unreadable,
271 > Error,
272 > }
273 >
274 > export interface IMemoryRange {
275 > type: MemoryRangeType;
276 > offset: number;
277 > length: number;
278 > }
279 >
280 > export interface IValidMemoryRange extends IMemoryRange {
281 > type: MemoryRangeType.Valid;
282 > offset: number;
283 > length: number;
284 > data: VSBuffer;
285 > }
286 >
287 > export interface IUnreadableMemoryRange extends IMemoryRange {
288 > type: MemoryRangeType.Unreadable;
289 > }
290 >
291 > export interface IErrorMemoryRange extends IMemoryRange {
292 > type: MemoryRangeType.Error;
293 > error: string;
294 > }
295 >
296 > /**
297 > * Union type of memory that can be returned from read(). Since a read request
298 > * could encompass multiple previously-read ranges, multiple of these types
299 > * are possible to return.
300 > */
301 > export type MemoryRange = IValidMemoryRange | IUnreadableMemoryRange | IErrorMemoryRange;
302 >
303 > export const DEBUG_MEMORY_SCHEME = 'vscode-debug-memory';
304 >
305 > /**
306 > * An IMemoryRegion corresponds to a contiguous range of memory referred to
307 > * by a DAP `memoryReference`.
308 > */
309 > export interface IMemoryRegion extends IDisposable {
310 > /**
311 > * Event that fires when memory changes. Can be a result of memory events or
312 > * `write` requests.
313 > */
314 > readonly onDidInvalidate: Event<IMemoryInvalidationEvent>;
315 >
316 > /**
317 > * Whether writes are supported on this memory region.
318 > */
319 > readonly writable: boolean;
320 >
321 > /**
322 > * Requests memory ranges from the debug adapter. It returns a list of memory
323 > * ranges that overlap (but may exceed!) the given offset. Use the `offset`
324 > * and `length` of each range for display.
325 > */
326 > read(fromOffset: number, toOffset: number): Promise<MemoryRange[]>;
327 >
328 > /**
329 > * Writes memory to the debug adapter at the given offset.
330 > */
331 > write(offset: number, data: VSBuffer): Promise<number>;
332 > }
333 >
334 > /** Data that can be inserted in {@link IDebugSession.appendToRepl} */
335 > export interface INewReplElementData {
336 > /**
337 > * Output string to display
338 > */
339 > output: string;
340 >
341 > /**
342 > * Expression data to display. Will result in the item being expandable in
343 > * the REPL. Its value will be used if {@link output} is not provided.
344 > */
345 > expression?: IExpression;
346 >
347 > /**
348 > * Output severity.
349 > */
350 > sev: severity;
351 >
352 > /**
353 > * Originating location.
354 > */
355 > source?: IReplElementSource;
356 > }
357 >
358 > export interface IDebugEvaluatePosition {
359 > line: number;
360 > column: number;
361 > source: DebugProtocol.Source;
362 > }
363 >
364 > export interface IDebugLocationReferenced {
365 > line: number;
366 > column: number;
367 > endLine?: number;
368 > endColumn?: number;
369 > source: Source;
370 > }
371 >
372 > export interface IDebugSession extends ITreeElement, IDisposable {
373 >
374 > readonly configuration: IConfig;
375 > readonly unresolvedConfiguration: IConfig | undefined;
376 > readonly state: State;
377 > readonly root: IWorkspaceFolder | undefined;
378 > readonly parentSession: IDebugSession | undefined;
379 > readonly subId: string | undefined;
380 > readonly compact: boolean;
381 > readonly compoundRoot: DebugCompoundRoot | undefined;
382 > readonly saveBeforeRestart: boolean;
383 > readonly name: string;
384 > readonly autoExpandLazyVariables: boolean;
385 > readonly suppressDebugToolbar: boolean;
386 > readonly suppressDebugStatusbar: boolean;
387 > readonly suppressDebugView: boolean;
388 > readonly lifecycleManagedByParent: boolean;
389 > /** Test run this debug session was spawned by */
390 > readonly correlatedTestRun?: LiveTestResult;
391 >
392 > setSubId(subId: string | undefined): void;
393 >
394 > getMemory(memoryReference: string): IMemoryRegion;
395 >
396 > setName(name: string): void;
397 > readonly onDidChangeName: Event<string>;
398 > getLabel(): string;
399 >
400 > getSourceForUri(modelUri: uri): Source | undefined;
401 > getSource(raw?: DebugProtocol.Source): Source;
402 >
403 > setConfiguration(configuration: { resolved: IConfig; unresolved: IConfig | undefined }): void;
404 > rawUpdate(data: IRawModelUpdate): void;
405 >
406 > getThread(threadId: number): IThread | undefined;
407 > getAllThreads(): IThread[];
408 > clearThreads(removeThreads: boolean, reference?: number): void;
409 > getStoppedDetails(): IRawStoppedDetails | undefined;
410 >
411 > getReplElements(): IReplElement[];
412 > hasSeparateRepl(): boolean;
413 > removeReplExpressions(): void;
414 > addReplExpression(stackFrame: IStackFrame | undefined, name: string): Promise<void>;
415 > appendToRepl(data: INewReplElementData): void;
416 > /** Cancel any associated test run set through the DebugSessionOptions */
417 > cancelCorrelatedTestRun(): void;
418 >
419 > // session events
420 > readonly onDidEndAdapter: Event<AdapterEndEvent | undefined>;
421 > readonly onDidChangeState: Event<void>;
422 > readonly onDidChangeReplElements: Event<IReplElement | undefined>;
423 >
424 > /** DA capabilities. Set only when there is a running session available. */
425 > readonly capabilities: DebugProtocol.Capabilities;
426 > /** DA capabilities. These are retained on the session even after is implementation ends. */
427 > readonly rememberedCapabilities?: DebugProtocol.Capabilities;
428 >
429 > // DAP events
430 >
431 > readonly onDidLoadedSource: Event<LoadedSourceEvent>;
432 > readonly onDidCustomEvent: Event<DebugProtocol.Event>;
433 > readonly onDidProgressStart: Event<DebugProtocol.ProgressStartEvent>;
434 > readonly onDidProgressUpdate: Event<DebugProtocol.ProgressUpdateEvent>;
435 > readonly onDidProgressEnd: Event<DebugProtocol.ProgressEndEvent>;
436 > readonly onDidInvalidateMemory: Event<DebugProtocol.MemoryEvent>;
437 >
438 > // DAP request
439 >
440 > initialize(dbgr: IDebugger): Promise<void>;
441 > launchOrAttach(config: IConfig): Promise<void>;
442 > restart(): Promise<void>;
443 > terminate(restart?: boolean /* false */): Promise<void>;
444 > disconnect(restart?: boolean /* false */, suspend?: boolean): Promise<void>;
445 >
446 > sendBreakpoints(modelUri: uri, bpts: IBreakpoint[], sourceModified: boolean): Promise<void>;
447 > sendFunctionBreakpoints(fbps: IFunctionBreakpoint[]): Promise<void>;
448 > dataBreakpointInfo(name: string, variablesReference?: number, frameId?: number): Promise<IDataBreakpointInfoResponse | undefined>;
449 > dataBytesBreakpointInfo(address: string, bytes: number): Promise<IDataBreakpointInfoResponse | undefined>;
450 > sendDataBreakpoints(dbps: IDataBreakpoint[]): Promise<void>;
451 > sendInstructionBreakpoints(dbps: IInstructionBreakpoint[]): Promise<void>;
452 > sendExceptionBreakpoints(exbpts: IExceptionBreakpoint[]): Promise<void>;
453 > breakpointsLocations(uri: uri, lineNumber: number): Promise<IPosition[]>;
454 > getDebugProtocolBreakpoint(breakpointId: string): DebugProtocol.Breakpoint | undefined;
455 > resolveLocationReference(locationReference: number): Promise<IDebugLocationReferenced>;
456 >
457 > stackTrace(threadId: number, startFrame: number, levels: number, token: CancellationToken): Promise<DebugProtocol.StackTraceResponse | undefined>;
458 > exceptionInfo(threadId: number): Promise<IExceptionInfo | undefined>;
459 > scopes(frameId: number, threadId: number): Promise<DebugProtocol.ScopesResponse | undefined>;
460 > variables(variablesReference: number, threadId: number | undefined, filter: 'indexed' | 'named' | undefined, start: number | undefined, count: number | undefined): Promise<DebugProtocol.VariablesResponse | undefined>;
461 > evaluate(expression: string, frameId?: number, context?: string, location?: IDebugEvaluatePosition): Promise<DebugProtocol.EvaluateResponse | undefined>;
462 > customRequest(request: string, args: unknown): Promise<DebugProtocol.Response | undefined>;
463 > cancel(progressId: string): Promise<DebugProtocol.CancelResponse | undefined>;
464 > disassemble(memoryReference: string, offset: number, instructionOffset: number, instructionCount: number): Promise<DebugProtocol.DisassembledInstruction[] | undefined>;
465 > readMemory(memoryReference: string, offset: number, count: number): Promise<DebugProtocol.ReadMemoryResponse | undefined>;
466 > writeMemory(memoryReference: string, offset: number, data: string, allowPartial?: boolean): Promise<DebugProtocol.WriteMemoryResponse | undefined>;
467 >
468 > restartFrame(frameId: number, threadId: number): Promise<void>;
469 > next(threadId: number, granularity?: DebugProtocol.SteppingGranularity): Promise<void>;
470 > stepIn(threadId: number, targetId?: number, granularity?: DebugProtocol.SteppingGranularity): Promise<void>;
471 > stepInTargets(frameId: number): Promise<DebugProtocol.StepInTarget[] | undefined>;
472 > stepOut(threadId: number, granularity?: DebugProtocol.SteppingGranularity): Promise<void>;
473 > stepBack(threadId: number, granularity?: DebugProtocol.SteppingGranularity): Promise<void>;
474 > continue(threadId: number): Promise<void>;
475 > reverseContinue(threadId: number): Promise<void>;
476 > pause(threadId: number): Promise<void>;
477 > terminateThreads(threadIds: number[]): Promise<void>;
478 >
479 > completions(frameId: number | undefined, threadId: number, text: string, position: Position, token: CancellationToken): Promise<DebugProtocol.CompletionsResponse | undefined>;
480 > setVariable(variablesReference: number | undefined, name: string, value: string): Promise<DebugProtocol.SetVariableResponse | undefined>;
481 > setExpression(frameId: number, expression: string, value: string): Promise<DebugProtocol.SetExpressionResponse | undefined>;
482 > loadSource(resource: uri): Promise<DebugProtocol.SourceResponse | undefined>;
483 > getLoadedSources(): Promise<Source[]>;
484 >
485 > gotoTargets(source: DebugProtocol.Source, line: number, column?: number): Promise<DebugProtocol.GotoTargetsResponse | undefined>;
486 > goto(threadId: number, targetId: number): Promise<DebugProtocol.GotoResponse | undefined>;
487 > }
488 >
489 > export interface IThread extends ITreeElement {
490 >
491 > /**
492 > * Process the thread belongs to
493 > */
494 > readonly session: IDebugSession;
495 >
496 > /**
497 > * Id of the thread generated by the debug adapter backend.
498 > */
499 > readonly threadId: number;
500 >
501 > /**
502 > * Name of the thread.
503 > */
504 > readonly name: string;
505 >
506 > /**
507 > * Information about the current thread stop event. Undefined if thread is not stopped.
508 > */
509 > readonly stoppedDetails: IRawStoppedDetails | undefined;
510 >
511 > /**
512 > * Information about the exception if an 'exception' stopped event raised and DA supports the 'exceptionInfo' request, otherwise undefined.
513 > */
514 > readonly exceptionInfo: Promise<IExceptionInfo | undefined>;
515 >
516 > readonly stateLabel: string;
517 >
518 > /**
519 > * Gets the callstack if it has already been received from the debug
520 > * adapter.
521 > */
522 > getCallStack(): ReadonlyArray<IStackFrame>;
523 >
524 >
525 > /**
526 > * Gets the top stack frame that is not hidden if the callstack has already been received from the debug adapter
527 > */
528 > getTopStackFrame(): IStackFrame | undefined;
529 >
530 > /**
531 > * Invalidates the callstack cache
532 > */
533 > clearCallStack(): void;
534 >
535 > /**
536 > * Indicates whether this thread is stopped. The callstack for stopped
537 > * threads can be retrieved from the debug adapter.
538 > */
539 > readonly stopped: boolean;
540 >
541 > next(granularity?: DebugProtocol.SteppingGranularity): Promise<void>;
542 > stepIn(granularity?: DebugProtocol.SteppingGranularity): Promise<void>;
543 > stepOut(granularity?: DebugProtocol.SteppingGranularity): Promise<void>;
544 > stepBack(granularity?: DebugProtocol.SteppingGranularity): Promise<void>;
545 > continue(): Promise<void>;
546 > pause(): Promise<void>;
547 > terminate(): Promise<void>;
548 > reverseContinue(): Promise<void>;
549 > }
550 >
551 > export interface IScope extends IExpressionContainer {
552 > readonly name: string;
553 > readonly expensive: boolean;
554 > readonly range?: IRange;
555 > readonly hasChildren: boolean;
556 > readonly childrenHaveBeenLoaded: boolean;
557 > }
558 >
559 > export interface IStackFrame extends ITreeElement {
560 > readonly thread: IThread;
561 > readonly name: string;
562 > readonly presentationHint: string | undefined;
563 > readonly frameId: number;
564 > readonly range: IRange;
565 > readonly source: Source;
566 > readonly canRestart: boolean;
567 > readonly instructionPointerReference?: string;
568 > getScopes(): Promise<IScope[]>;
569 > getMostSpecificScopes(range: IRange): Promise<ReadonlyArray<IScope>>;
570 > forgetScopes(): void;
571 > restart(): Promise<void>;
572 > toString(): string;
573 > openInEditor(editorService: IEditorService, preserveFocus?: boolean, sideBySide?: boolean, pinned?: boolean): Promise<IEditorPane | undefined>;
574 > equals(other: IStackFrame): boolean;
575 > }
576 >
577 > export function isFrameDeemphasized(frame: IStackFrame): boolean {
578 const hint = frame.presentationHint ?? frame.source.presentationHint;
579 return hint === 'deemphasize' || hint === 'subtle';
580 }
581 > debug.ts
582 > export interface IEnablement extends ITreeElement {
583 > readonly enabled: boolean;
584 > }
585 >
586 > export interface IBreakpointData {
587 > readonly id?: string;
588 > readonly lineNumber: number;
589 > readonly column?: number;
590 > readonly enabled?: boolean;
591 > readonly condition?: string;
592 > readonly logMessage?: string;
593 > readonly hitCondition?: string;
594 > readonly triggeredBy?: string;
595 > readonly mode?: string;
596 > readonly modeLabel?: string;
597 > }
598 >
599 > export interface IBreakpointUpdateData {
600 > readonly condition?: string;
601 > readonly hitCondition?: string;
602 > readonly logMessage?: string;
603 > readonly lineNumber?: number;
604 > readonly column?: number;
605 > readonly triggeredBy?: string;
606 > readonly mode?: string;
607 > readonly modeLabel?: string;
608 > }
609 >
610 > export interface IBaseBreakpoint extends IEnablement {
611 > readonly condition?: string;
612 > readonly hitCondition?: string;
613 > readonly logMessage?: string;
614 > readonly verified: boolean;
615 > readonly supported: boolean;
616 > readonly message?: string;
617 > /** The preferred mode of the breakpoint from {@link DebugProtocol.BreakpointMode} */
618 > readonly mode?: string;
619 > /** The preferred mode label of the breakpoint from {@link DebugProtocol.BreakpointMode} */
620 > readonly modeLabel?: string;
621 > readonly sessionsThatVerified: string[];
622 > getIdFromAdapter(sessionId: string): number | undefined;
623 > }
624 >
625 > export interface IBreakpoint extends IBaseBreakpoint {
626 > /** URI where the breakpoint was first set by the user. */
627 > readonly originalUri: uri;
628 > /** URI where the breakpoint is currently shown; may be moved by debugger */
629 > readonly uri: uri;
630 > readonly lineNumber: number;
631 > readonly endLineNumber?: number;
632 > readonly column?: number;
633 > readonly endColumn?: number;
634 > readonly adapterData: unknown;
635 > readonly sessionAgnosticData: { lineNumber: number; column: number | undefined };
636 > /** An ID of the breakpoint that triggers this breakpoint. */
637 > readonly triggeredBy?: string;
638 > /** Pending on the trigger breakpoint, which means this breakpoint is not yet sent to DA */
639 > readonly pending: boolean;
640 >
641 > /** Marks that a session did trigger the breakpoint. */
642 > setSessionDidTrigger(sessionId: string, didTrigger?: boolean): void;
643 > /** Gets whether the `triggeredBy` condition has been met in the given sesison ID. */
644 > getSessionDidTrigger(sessionId: string): boolean;
645 >
646 > toDAP(): DebugProtocol.SourceBreakpoint;
647 > }
648 >
649 > export interface IFunctionBreakpoint extends IBaseBreakpoint {
650 > readonly name: string;
651 > toDAP(): DebugProtocol.FunctionBreakpoint;
652 > }
653 >
654 > export interface IExceptionBreakpoint extends IBaseBreakpoint {
655 > readonly filter: string;
656 > readonly label: string;
657 > readonly description: string | undefined;
658 > }
659 >
660 > export const enum DataBreakpointSetType {
661 > Variable,
662 > Address,
663 > }
664 >
665 > /**
666 > * Source for a data breakpoint. A data breakpoint on a variable always has a
667 > * `dataId` because it cannot reference that variable globally, but addresses
668 > * can request info repeated and use session-specific data.
669 > */
670 > export type DataBreakpointSource =
671 > | { type: DataBreakpointSetType.Variable; dataId: string }
672 > | { type: DataBreakpointSetType.Address; address: string; bytes: number };
673 >
674 > export interface IDataBreakpoint extends IBaseBreakpoint {
675 > readonly description: string;
676 > readonly canPersist: boolean;
677 > readonly src: DataBreakpointSource;
678 > readonly accessType: DebugProtocol.DataBreakpointAccessType;
679 > toDAP(session: IDebugSession): Promise<DebugProtocol.DataBreakpoint | undefined>;
680 > }
681 >
682 > export interface IInstructionBreakpoint extends IBaseBreakpoint {
683 > readonly instructionReference: string;
684 > readonly offset?: number;
685 > /** Original instruction memory address; display purposes only */
686 > readonly address: bigint;
687 > toDAP(): DebugProtocol.InstructionBreakpoint;
688 > }
689 >
690 > export interface IExceptionInfo {
691 > readonly id?: string;
692 > readonly description?: string;
693 > readonly breakMode: string | null;
694 > readonly details?: DebugProtocol.ExceptionDetails;
695 > }
696 >
697 > // model interfaces
698 >
699 > export interface IViewModel extends ITreeElement {
700 > /**
701 > * Returns the focused debug session or undefined if no session is stopped.
702 > */
703 > readonly focusedSession: IDebugSession | undefined;
704 >
705 > /**
706 > * Returns the focused thread or undefined if no thread is stopped.
707 > */
708 > readonly focusedThread: IThread | undefined;
709 >
710 > /**
711 > * Returns the focused stack frame or undefined if there are no stack frames.
712 > */
713 > readonly focusedStackFrame: IStackFrame | undefined;
714 >
715 > setVisualizedExpression(original: IExpression, visualized: IExpression & { treeId: string } | undefined): void;
716 > /** Returns the visualized expression if loaded, or a tree it should be visualized with, or undefined */
717 > getVisualizedExpression(expression: IExpression): IExpression | string | undefined;
718 > getSelectedExpression(): { expression: IExpression; settingWatch: boolean } | undefined;
719 > setSelectedExpression(expression: IExpression | undefined, settingWatch: boolean): void;
720 > updateViews(): void;
721 >
722 > isMultiSessionView(): boolean;
723 >
724 > readonly onDidFocusSession: Event<IDebugSession | undefined>;
725 > readonly onDidFocusThread: Event<{ thread: IThread | undefined; explicit: boolean; session: IDebugSession | undefined }>;
726 > readonly onDidFocusStackFrame: Event<{ stackFrame: IStackFrame | undefined; explicit: boolean; session: IDebugSession | undefined }>;
727 > readonly onDidSelectExpression: Event<{ expression: IExpression; settingWatch: boolean } | undefined>;
728 > readonly onDidEvaluateLazyExpression: Event<IExpressionContainer>;
729 > /**
730 > * Fired when `setVisualizedExpression`, to migrate elements currently
731 > * rendered as `original` to the `replacement`.
732 > */
733 > readonly onDidChangeVisualization: Event<{ original: IExpression; replacement: IExpression }>;
734 > readonly onWillUpdateViews: Event<void>;
735 >
736 > evaluateLazyExpression(expression: IExpressionContainer): void;
737 > }
738 >
739 > export interface IEvaluate {
740 > evaluate(session: IDebugSession, stackFrame: IStackFrame, context: string): Promise<void>;
741 > }
742 >
743 > export interface IDebugModel extends ITreeElement {
744 > getSession(sessionId: string | undefined, includeInactive?: boolean): IDebugSession | undefined;
745 > getSessions(includeInactive?: boolean): IDebugSession[];
746 > getBreakpoints(filter?: { uri?: uri; originalUri?: uri; lineNumber?: number; column?: number; enabledOnly?: boolean; triggeredOnly?: boolean }): ReadonlyArray<IBreakpoint>;
747 > areBreakpointsActivated(): boolean;
748 > getFunctionBreakpoints(): ReadonlyArray<IFunctionBreakpoint>;
749 > getDataBreakpoints(): ReadonlyArray<IDataBreakpoint>;
750 >
751 > /**
752 > * Returns list of all exception breakpoints.
753 > */
754 > getExceptionBreakpoints(): ReadonlyArray<IExceptionBreakpoint>;
755 >
756 > /**
757 > * Returns list of exception breakpoints for the given session
758 > * @param sessionId Session id. If falsy, returns the breakpoints from the last set fallback session.
759 > */
760 > getExceptionBreakpointsForSession(sessionId?: string): ReadonlyArray<IExceptionBreakpoint>;
761 >
762 > getInstructionBreakpoints(): ReadonlyArray<IInstructionBreakpoint>;
763 > getWatchExpressions(): ReadonlyArray<IExpression & IEvaluate>;
764 > registerBreakpointModes(debugType: string, modes: DebugProtocol.BreakpointMode[]): void;
765 > getBreakpointModes(forBreakpointType: 'source' | 'exception' | 'data' | 'instruction'): DebugProtocol.BreakpointMode[];
766 > readonly onDidChangeBreakpoints: Event<IBreakpointsChangeEvent | undefined>;
767 > readonly onDidChangeCallStack: Event<void>;
768 > /**
769 > * The expression has been added, removed, or repositioned.
770 > */
771 > readonly onDidChangeWatchExpressions: Event<IExpression | undefined>;
772 > /**
773 > * The expression's value has changed.
774 > */
775 > readonly onDidChangeWatchExpressionValue: Event<IExpression | undefined>;
776 >
777 > fetchCallstack(thread: IThread, levels?: number): Promise<void>;
778 > }
779 >
780 > /**
781 > * An event describing a change to the set of [breakpoints](#debug.Breakpoint).
782 > */
783 > export interface IBreakpointsChangeEvent {
784 > added?: Array<IBreakpoint | IFunctionBreakpoint | IDataBreakpoint | IInstructionBreakpoint>;
785 > removed?: Array<IBreakpoint | IFunctionBreakpoint | IDataBreakpoint | IInstructionBreakpoint>;
786 > changed?: Array<IBreakpoint | IFunctionBreakpoint | IDataBreakpoint | IInstructionBreakpoint>;
787 > sessionOnly: boolean;
788 > }
789 >
790 > // Debug configuration interfaces
791 >
792 > export interface IDebugConfiguration {
793 > allowBreakpointsEverywhere: boolean;
794 > gutterMiddleClickAction: 'logpoint' | 'conditionalBreakpoint' | 'triggeredBreakpoint' | 'none';
795 > openDebug: 'neverOpen' | 'openOnSessionStart' | 'openOnFirstSessionStart' | 'openOnDebugBreak';
796 > openExplorerOnEnd: boolean;
797 > inlineValues: boolean | 'auto' | 'on' | 'off'; // boolean for back-compat
798 > toolBarLocation: 'floating' | 'docked' | 'commandCenter' | 'hidden';
799 > showInStatusBar: 'never' | 'always' | 'onFirstSessionStart';
800 > internalConsoleOptions: 'neverOpen' | 'openOnSessionStart' | 'openOnFirstSessionStart';
801 > extensionHostDebugAdapter: boolean;
802 > enableAllHovers: boolean;
803 > showSubSessionsInToolBar: boolean;
804 > closeReadonlyTabsOnEnd: boolean;
805 > console: {
806 > fontSize: number;
807 > fontFamily: string;
808 > lineHeight: number;
809 > wordWrap: boolean;
810 > closeOnEnd: boolean;
811 > collapseIdenticalLines: boolean;
812 > historySuggestions: boolean;
813 > acceptSuggestionOnEnter: 'off' | 'on';
814 > maximumLines: number;
815 > };
816 > focusWindowOnBreak: boolean;
817 > focusEditorOnBreak: boolean;
818 > onTaskErrors: 'debugAnyway' | 'showErrors' | 'prompt' | 'abort';
819 > showBreakpointsInOverviewRuler: boolean;
820 > showInlineBreakpointCandidates: boolean;
821 > confirmOnExit: 'always' | 'never';
822 > disassemblyView: {
823 > showSourceCode: boolean;
824 > };
825 > autoExpandLazyVariables: 'auto' | 'off' | 'on';
826 > enableStatusBarColor: boolean;
827 > showVariableTypes: boolean;
828 > hideSlowPreLaunchWarning: boolean;
829 > }
830 >
831 > export interface IGlobalConfig {
832 > version: string;
833 > compounds: ICompound[];
834 > configurations: IConfig[];
835 > }
836 >
837 > export interface IConfigPresentation {
838 > hidden?: boolean;
839 > group?: string;
840 > order?: number;
841 > }
842 >
843 > interface IEnvConfig {
844 > internalConsoleOptions?: 'neverOpen' | 'openOnSessionStart' | 'openOnFirstSessionStart';
845 > preRestartTask?: string | ITaskIdentifier;
846 > postRestartTask?: string | ITaskIdentifier;
847 > preLaunchTask?: string | ITaskIdentifier;
848 > postDebugTask?: string | ITaskIdentifier;
849 > debugServer?: number;
850 > noDebug?: boolean;
851 > suppressMultipleSessionWarning?: boolean;
852 > presentation?: IConfigPresentation;
853 > }
854 >
855 > export interface IConfig extends IEnvConfig {
856 >
857 > // fundamental attributes
858 > type: string;
859 > request: string;
860 > name: string;
861 > presentation?: IConfigPresentation;
862 > // platform specifics
863 > windows?: IEnvConfig;
864 > osx?: IEnvConfig;
865 > linux?: IEnvConfig;
866 >
867 > // internals
868 > __configurationTarget?: ConfigurationTarget;
869 > __sessionId?: string;
870 > __restart?: unknown;
871 > __autoAttach?: boolean;
872 > port?: number; // TODO
873 > }
874 >
875 > export interface ICompound {
876 > name: string;
877 > stopAll?: boolean;
878 > preLaunchTask?: string | ITaskIdentifier;
879 > configurations: (string | { name: string; folder: string })[];
880 > presentation?: IConfigPresentation;
881 > }
882 >
883 > export function isDebugConfig(thing: IConfig | ICompound): thing is IConfig {
884 return 'type' in thing && 'request' in thing;
885 }
886 > debug.ts
887 > export interface IDebugAdapter extends IDisposable {
888 > readonly onError: Event<Error>;
889 > readonly onExit: Event<number | null>;
890 > onRequest(callback: (request: DebugProtocol.Request) => void): void;
891 > onEvent(callback: (event: DebugProtocol.Event) => void): void;
892 > startSession(): Promise<void>;
893 > sendMessage(message: DebugProtocol.ProtocolMessage): void;
894 > sendResponse(response: DebugProtocol.Response): void;
895 > sendRequest(command: string, args: unknown, clb: (result: DebugProtocol.Response) => void, timeout?: number): number;
896 > stopSession(): Promise<void>;
897 > }
898 >
899 > export interface IDebugAdapterFactory extends ITerminalLauncher {
900 > createDebugAdapter(session: IDebugSession): IDebugAdapter;
901 > substituteVariables(folder: IWorkspaceFolder | undefined, config: IConfig): Promise<IConfig>;
902 > }
903 >
904 > export interface IDebugAdapterExecutableOptions {
905 > cwd?: string;
906 > env?: { [key: string]: string };
907 > }
908 >
909 > export interface IDebugAdapterExecutable {
910 > readonly type: 'executable';
911 > readonly command: string;
912 > readonly args: string[];
913 > readonly options?: IDebugAdapterExecutableOptions;
914 > }
915 >
916 > export interface IDebugAdapterServer {
917 > readonly type: 'server';
918 > readonly port: number;
919 > readonly host?: string;
920 > }
921 >
922 > export interface IDebugAdapterNamedPipeServer {
923 > readonly type: 'pipeServer';
924 > readonly path: string;
925 > }
926 >
927 > export interface IDebugAdapterInlineImpl extends IDisposable {
928 > readonly onDidSendMessage: Event<DebugProtocol.Message>;
929 > handleMessage(message: DebugProtocol.Message): void;
930 > }
931 >
932 > export interface IDebugAdapterImpl {
933 > readonly type: 'implementation';
934 > }
935 >
936 > export type IAdapterDescriptor = IDebugAdapterExecutable | IDebugAdapterServer | IDebugAdapterNamedPipeServer | IDebugAdapterImpl;
937 >
938 > export interface IPlatformSpecificAdapterContribution {
939 > program?: string;
940 > args?: string[];
941 > runtime?: string;
942 > runtimeArgs?: string[];
943 > }
944 >
945 > export interface IDebuggerContribution extends IPlatformSpecificAdapterContribution {
946 > type: string;
947 > label?: string;
948 > win?: IPlatformSpecificAdapterContribution;
949 > winx86?: IPlatformSpecificAdapterContribution;
950 > windows?: IPlatformSpecificAdapterContribution;
951 > osx?: IPlatformSpecificAdapterContribution;
952 > linux?: IPlatformSpecificAdapterContribution;
953 >
954 > // internal
955 > aiKey?: string;
956 >
957 > // supported languages
958 > languages?: string[];
959 >
960 > // debug configuration support
961 > configurationAttributes?: Record<string, IJSONSchema>;
962 > initialConfigurations?: unknown[];
963 > configurationSnippets?: IJSONSchemaSnippet[];
964 > variables?: { [key: string]: string };
965 > when?: string;
966 > hiddenWhen?: string;
967 > deprecated?: string;
968 > strings?: { [key in DebuggerString]: string };
969 > /** @deprecated */
970 > uiMessages?: { [key in DebuggerString]: string };
971 > }
972 >
973 > export interface IBreakpointContribution {
974 > language: string;
975 > when?: string;
976 > }
977 >
978 > export enum DebugConfigurationProviderTriggerKind {
979 > /**
980 > * `DebugConfigurationProvider.provideDebugConfigurations` is called to provide the initial debug configurations for a newly created launch.json.
981 > */
982 > Initial = 1,
983 > /**
984 > * `DebugConfigurationProvider.provideDebugConfigurations` is called to provide dynamically generated debug configurations when the user asks for them through the UI (e.g. via the "Select and Start Debugging" command).
985 > */
986 > Dynamic = 2
987 > }
988 >
989 > export interface IDebugConfigurationProvider {
990 > readonly type: string;
991 > readonly triggerKind: DebugConfigurationProviderTriggerKind;
992 > resolveDebugConfiguration?(folderUri: uri | undefined, debugConfiguration: IConfig, token: CancellationToken): Promise<IConfig | null | undefined>;
993 > resolveDebugConfigurationWithSubstitutedVariables?(folderUri: uri | undefined, debugConfiguration: IConfig, token: CancellationToken): Promise<IConfig | null | undefined>;
994 > provideDebugConfigurations?(folderUri: uri | undefined, token: CancellationToken): Promise<IConfig[]>;
995 > }
996 >
997 > export interface IDebugAdapterDescriptorFactory {
998 > readonly type: string;
999 > createDebugAdapterDescriptor(session: IDebugSession): Promise<IAdapterDescriptor>;
1000 > }
1001 >
1002 > interface ITerminalLauncher {
1003 > runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, sessionId: string): Promise<number | undefined>;
1004 > }
1005 >
1006 > export interface IConfigurationManager {
1007 >
1008 > /**
1009 > * Returns an object containing the selected launch configuration and the selected configuration name. Both these fields can be null (no folder workspace).
1010 > */
1011 > readonly selectedConfiguration: {
1012 > launch: ILaunch | undefined;
1013 > // Potentially activates extensions
1014 > getConfig: () => Promise<IConfig | undefined>;
1015 > name: string | undefined;
1016 > // Type is used when matching dynamic configurations to their corresponding provider
1017 > type: string | undefined;
1018 > };
1019 >
1020 > selectConfiguration(launch: ILaunch | undefined, name?: string, config?: IConfig, dynamicConfigOptions?: { type?: string }): Promise<void>;
1021 >
1022 > getLaunches(): ReadonlyArray<ILaunch>;
1023 > getLaunch(workspaceUri: uri | undefined): ILaunch | undefined;
1024 > getAllConfigurations(): { launch: ILaunch; name: string; presentation?: IConfigPresentation }[];
1025 > removeRecentDynamicConfigurations(name: string, type: string): void;
1026 > getRecentDynamicConfigurations(): { name: string; type: string }[];
1027 >
1028 > /**
1029 > * Allows to register on change of selected debug configuration.
1030 > */
1031 > readonly onDidSelectConfiguration: Event<void>;
1032 >
1033 > /**
1034 > * Allows to register on change of selected debug configuration.
1035 > */
1036 > readonly onDidChangeConfigurationProviders: Event<void>;
1037 >
1038 > hasDebugConfigurationProvider(debugType: string, triggerKind?: DebugConfigurationProviderTriggerKind): boolean;
1039 > getDynamicProviders(): Promise<{ label: string; type: string; pick: () => Promise<{ launch: ILaunch; config: IConfig; label: string } | undefined> }[]>;
1040 > getDynamicConfigurationsByType(type: string, token?: CancellationToken): Promise<{ launch: ILaunch; config: IConfig; label: string }[]>;
1041 >
1042 > registerDebugConfigurationProvider(debugConfigurationProvider: IDebugConfigurationProvider): IDisposable;
1043 > unregisterDebugConfigurationProvider(debugConfigurationProvider: IDebugConfigurationProvider): void;
1044 >
1045 > resolveConfigurationByProviders(folderUri: uri | undefined, type: string | undefined, debugConfiguration: unknown, token: CancellationToken): Promise<IConfig | null | undefined>;
1046 > }
1047 >
1048 > export enum DebuggerString {
1049 > UnverifiedBreakpoints = 'unverifiedBreakpoints'
1050 > }
1051 >
1052 > export interface IAdapterManager {
1053 >
1054 > readonly onDidRegisterDebugger: Event<void>;
1055 >
1056 > hasEnabledDebuggers(): boolean;
1057 > getDebugAdapterDescriptor(session: IDebugSession): Promise<IAdapterDescriptor | undefined>;
1058 > getDebuggerLabel(type: string): string | undefined;
1059 > someDebuggerInterestedInLanguage(language: string): boolean;
1060 > getDebugger(type: string): IDebuggerMetadata | undefined;
1061 >
1062 > activateDebuggers(activationEvent: string, debugType?: string): Promise<void>;
1063 > registerDebugAdapterFactory(debugTypes: string[], debugAdapterFactory: IDebugAdapterFactory): IDisposable;
1064 > createDebugAdapter(session: IDebugSession): IDebugAdapter | undefined;
1065 > registerDebugAdapterDescriptorFactory(debugAdapterDescriptorFactory: IDebugAdapterDescriptorFactory): IDisposable;
1066 > unregisterDebugAdapterDescriptorFactory(debugAdapterDescriptorFactory: IDebugAdapterDescriptorFactory): void;
1067 >
1068 > substituteVariables(debugType: string, folder: IWorkspaceFolder | undefined, config: IConfig): Promise<IConfig>;
1069 > runInTerminal(debugType: string, args: DebugProtocol.RunInTerminalRequestArguments, sessionId: string): Promise<number | undefined>;
1070 > getEnabledDebugger(type: string): (IDebugger & IDebuggerMetadata) | undefined;
1071 > guessDebugger(gettingConfigurations: boolean): Promise<IGuessedDebugger | undefined>;
1072 >
1073 > get onDidDebuggersExtPointRead(): Event<void>;
1074 > }
1075 >
1076 > export interface IGuessedDebugger {
1077 > debugger: IDebugger;
1078 > withConfig?: {
1079 > label: string;
1080 > launch: ILaunch;
1081 > config: IConfig;
1082 > };
1083 > }
1084 >
1085 > export interface ILaunch {
1086 >
1087 > /**
1088 > * Resource pointing to the launch.json this object is wrapping.
1089 > */
1090 > readonly uri: uri;
1091 >
1092 > /**
1093 > * Name of the launch.
1094 > */
1095 > readonly name: string;
1096 >
1097 > /**
1098 > * Workspace of the launch. Can be undefined.
1099 > */
1100 > readonly workspace: IWorkspaceFolder | undefined;
1101 >
1102 > /**
1103 > * Should this launch be shown in the debug dropdown.
1104 > */
1105 > readonly hidden: boolean;
1106 >
1107 > /**
1108 > * Returns a configuration with the specified name.
1109 > * Returns undefined if there is no configuration with the specified name.
1110 > */
1111 > getConfiguration(name: string): IConfig | undefined;
1112 >
1113 > /**
1114 > * Returns a compound with the specified name.
1115 > * Returns undefined if there is no compound with the specified name.
1116 > */
1117 > getCompound(name: string): ICompound | undefined;
1118 >
1119 > /**
1120 > * Returns the names of all configurations and compounds.
1121 > * Ignores configurations which are invalid.
1122 > */
1123 > getConfigurationNames(ignoreCompoundsAndPresentation?: boolean): string[];
1124 >
1125 > /**
1126 > * Opens the launch.json file. Creates if it does not exist.
1127 > */
1128 > openConfigFile(options: { preserveFocus: boolean; type?: string; suppressInitialConfigs?: boolean }, token?: CancellationToken): Promise<{ editor: IEditorPane | null; created: boolean }>;
1129 > }
1130 >
1131 > // Debug service interfaces
1132 >
1133 > export const IDebugService = createDecorator<IDebugService>('debugService');
1134 >
1135 > export interface IDebugService {
1136 > readonly _serviceBrand: undefined;
1137 >
1138 > /**
1139 > * Gets the current debug state.
1140 > */
1141 > readonly state: State;
1142 >
1143 > readonly initializingOptions?: IDebugSessionOptions | undefined;
1144 >
1145 > /**
1146 > * Allows to register on debug state changes.
1147 > */
1148 > readonly onDidChangeState: Event<State>;
1149 >
1150 > /**
1151 > * Allows to register on sessions about to be created (not yet fully initialised).
1152 > * This is fired exactly one time for any given session.
1153 > */
1154 > readonly onWillNewSession: Event<IDebugSession>;
1155 >
1156 > /**
1157 > * Fired when a new debug session is started. This may fire multiple times
1158 > * for a single session due to restarts.
1159 > */
1160 > readonly onDidNewSession: Event<IDebugSession>;
1161 >
1162 > /**
1163 > * Allows to register on end session events.
1164 > *
1165 > * Contains a boolean indicating whether the session will restart. If restart
1166 > * is true, the session should not considered to be dead yet.
1167 > */
1168 > readonly onDidEndSession: Event<{ session: IDebugSession; restart: boolean }>;
1169 >
1170 > /**
1171 > * Gets the configuration manager.
1172 > */
1173 > getConfigurationManager(): IConfigurationManager;
1174 >
1175 > /**
1176 > * Gets the adapter manager.
1177 > */
1178 > getAdapterManager(): IAdapterManager;
1179 >
1180 > /**
1181 > * Sets the focused stack frame and evaluates all expressions against the newly focused stack frame,
1182 > */
1183 > focusStackFrame(focusedStackFrame: IStackFrame | undefined, thread?: IThread, session?: IDebugSession, options?: { explicit?: boolean; preserveFocus?: boolean; sideBySide?: boolean; pinned?: boolean }): Promise<void>;
1184 >
1185 > /**
1186 > * Returns true if breakpoints can be set for a given editor model. Depends on mode.
1187 > */
1188 > canSetBreakpointsIn(model: EditorIModel): boolean;
1189 >
1190 > /**
1191 > * Adds new breakpoints to the model for the file specified with the uri. Notifies debug adapter of breakpoint changes.
1192 > */
1193 > addBreakpoints(uri: uri, rawBreakpoints: IBreakpointData[], ariaAnnounce?: boolean): Promise<IBreakpoint[]>;
1194 >
1195 > /**
1196 > * Updates the breakpoints.
1197 > */
1198 > updateBreakpoints(originalUri: uri, data: Map<string, IBreakpointUpdateData>, sendOnResourceSaved: boolean): Promise<void>;
1199 >
1200 > /**
1201 > * Enables or disables all breakpoints. If breakpoint is passed only enables or disables the passed breakpoint.
1202 > * Notifies debug adapter of breakpoint changes.
1203 > */
1204 > enableOrDisableBreakpoints(enable: boolean, breakpoint?: IEnablement): Promise<void>;
1205 >
1206 > /**
1207 > * Sets the global activated property for all breakpoints.
1208 > * Notifies debug adapter of breakpoint changes.
1209 > */
1210 > setBreakpointsActivated(activated: boolean): Promise<void>;
1211 >
1212 > /**
1213 > * Removes all breakpoints. If id is passed only removes the breakpoint associated with that id.
1214 > * Notifies debug adapter of breakpoint changes.
1215 > */
1216 > removeBreakpoints(id?: string | string[]): Promise<void>;
1217 >
1218 > /**
1219 > * Adds a new function breakpoint for the given name.
1220 > */
1221 > addFunctionBreakpoint(opts?: IFunctionBreakpointOptions, id?: string): void;
1222 >
1223 > /**
1224 > * Updates an already existing function breakpoint.
1225 > * Notifies debug adapter of breakpoint changes.
1226 > */
1227 > updateFunctionBreakpoint(id: string, update: { name?: string; hitCondition?: string; condition?: string }): Promise<void>;
1228 >
1229 > /**
1230 > * Removes all function breakpoints. If id is passed only removes the function breakpoint with the passed id.
1231 > * Notifies debug adapter of breakpoint changes.
1232 > */
1233 > removeFunctionBreakpoints(id?: string): Promise<void>;
1234 >
1235 > /**
1236 > * Adds a new data breakpoint.
1237 > */
1238 > addDataBreakpoint(opts: IDataBreakpointOptions): Promise<void>;
1239 >
1240 > /**
1241 > * Updates an already existing data breakpoint.
1242 > * Notifies debug adapter of breakpoint changes.
1243 > */
1244 > updateDataBreakpoint(id: string, update: { hitCondition?: string; condition?: string }): Promise<void>;
1245 >
1246 > /**
1247 > * Removes all data breakpoints. If id is passed only removes the data breakpoint with the passed id.
1248 > * Notifies debug adapter of breakpoint changes.
1249 > */
1250 > removeDataBreakpoints(id?: string): Promise<void>;
1251 >
1252 > /**
1253 > * Adds a new instruction breakpoint.
1254 > */
1255 > addInstructionBreakpoint(opts: IInstructionBreakpointOptions): Promise<void>;
1256 >
1257 > /**
1258 > * Removes all instruction breakpoints. If `address` is passed, only the
1259 > * instruction breakpoint with the matching resolved memory address is
1260 > * removed; this is preferred because the debug adapter is allowed to
1261 > * return different `instructionReference` strings for the same memory
1262 > * location on subsequent disassemble requests. If `address` is not
1263 > * provided, falls back to matching on `instructionReference` (and
1264 > * `offset` when specified). When no arguments are provided, all
1265 > * instruction breakpoints are removed. Notifies the debug adapter of
1266 > * breakpoint changes.
1267 > */
1268 > removeInstructionBreakpoints(instructionReference?: string, offset?: number, address?: bigint): Promise<void>;
1269 >
1270 > setExceptionBreakpointCondition(breakpoint: IExceptionBreakpoint, condition: string | undefined): Promise<void>;
1271 >
1272 > /**
1273 > * Creates breakpoints based on the sesison filter options. This will create
1274 > * disabled breakpoints (or enabled, if the filter indicates it's a default)
1275 > * for each filter provided in the session.
1276 > */
1277 > setExceptionBreakpointsForSession(session: IDebugSession, filters: DebugProtocol.ExceptionBreakpointsFilter[]): void;
1278 >
1279 > /**
1280 > * Sends all breakpoints to the passed session.
1281 > * If session is not passed, sends all breakpoints to each session.
1282 > */
1283 > sendAllBreakpoints(session?: IDebugSession): Promise<void>;
1284 >
1285 > /**
1286 > * Sends breakpoints of the given source to the passed session.
1287 > */
1288 > sendBreakpoints(modelUri: uri, sourceModified?: boolean, session?: IDebugSession): Promise<void>;
1289 >
1290 > /**
1291 > * Adds a new watch expression and evaluates it against the debug adapter.
1292 > */
1293 > addWatchExpression(name?: string): void;
1294 >
1295 > /**
1296 > * Renames a watch expression and evaluates it against the debug adapter.
1297 > */
1298 > renameWatchExpression(id: string, newName: string): void;
1299 >
1300 > /**
1301 > * Moves a watch expression to a new possition. Used for reordering watch expressions.
1302 > */
1303 > moveWatchExpression(id: string, position: number): void;
1304 >
1305 > /**
1306 > * Removes all watch expressions. If id is passed only removes the watch expression with the passed id.
1307 > */
1308 > removeWatchExpressions(id?: string): void;
1309 >
1310 > /**
1311 > * Starts debugging. If the configOrName is not passed uses the selected configuration in the debug dropdown.
1312 > * Also saves all files, manages if compounds are present in the configuration
1313 > * and resolveds configurations via DebugConfigurationProviders.
1314 > *
1315 > * Returns true if the start debugging was successful. For compound launches, all configurations have to start successfully for it to return success.
1316 > * On errors the startDebugging will throw an error, however some error and cancelations are handled and in that case will simply return false.
1317 > */
1318 > startDebugging(launch: ILaunch | undefined, configOrName?: IConfig | string, options?: IDebugSessionOptions, saveBeforeStart?: boolean): Promise<boolean>;
1319 >
1320 > /**
1321 > * Restarts a session or creates a new one if there is no active session.
1322 > */
1323 > restartSession(session: IDebugSession, restartData?: unknown): Promise<void>;
1324 >
1325 > /**
1326 > * Stops the session. If no session is specified then all sessions are stopped.
1327 > */
1328 > stopSession(session: IDebugSession | undefined, disconnect?: boolean, suspend?: boolean): Promise<void>;
1329 >
1330 > /**
1331 > * Makes unavailable all sources with the passed uri. Source will appear as grayed out in callstack view.
1332 > */
1333 > sourceIsNotAvailable(uri: uri): void;
1334 >
1335 > /**
1336 > * Gets the current debug model.
1337 > */
1338 > getModel(): IDebugModel;
1339 >
1340 > /**
1341 > * Gets the current view model.
1342 > */
1343 > getViewModel(): IViewModel;
1344 >
1345 > /**
1346 > * Resumes execution and pauses until the given position is reached.
1347 > */
1348 > runTo(uri: uri, lineNumber: number, column?: number): Promise<void>;
1349 > }
1350 >
1351 > // Editor interfaces
1352 > export const enum BreakpointWidgetContext {
1353 > CONDITION = 0,
1354 > HIT_COUNT = 1,
1355 > LOG_MESSAGE = 2,
1356 > TRIGGER_POINT = 3
1357 > }
1358 >
1359 > export interface IDebugEditorContribution extends editorCommon.IEditorContribution {
1360 > showHover(range: Position, focus: boolean): Promise<void>;
1361 > addLaunchConfiguration(): Promise<void>;
1362 > closeExceptionWidget(): void;
1363 > }
1364 >
1365 > export interface IBreakpointEditorContribution extends editorCommon.IEditorContribution {
1366 > showBreakpointWidget(lineNumber: number, column: number | undefined, context?: BreakpointWidgetContext): void;
1367 > closeBreakpointWidget(): void;
1368 > getContextMenuActionsAtPosition(lineNumber: number, model: EditorIModel): IAction[];
1369 > }
1370 >
1371 > export interface IReplConfiguration {
1372 > readonly fontSize: number;
1373 > readonly fontFamily: string;
1374 > readonly lineHeight: number;
1375 > readonly cssLineHeight: string;
1376 > readonly backgroundColor: Color | undefined;
1377 > readonly fontSizeForTwistie: number;
1378 > }
1379 >
1380 > export interface IReplOptions {
1381 > readonly replConfiguration: IReplConfiguration;
1382 > }
1383 >
1384 > export interface IDebugVisualizationContext {
1385 > variable: DebugProtocol.Variable;
1386 > containerId?: number;
1387 > frameId?: number;
1388 > threadId: number;
1389 > sessionId: string;
1390 > }
1391 >
1392 > export const enum DebugVisualizationType {
1393 > Command,
1394 > Tree,
1395 > }
1396 >
1397 > export type MainThreadDebugVisualization =
1398 > | { type: DebugVisualizationType.Command }
1399 > | { type: DebugVisualizationType.Tree; id: string };
1400 >
1401 >
1402 > export const enum DebugTreeItemCollapsibleState {
1403 > None = 0,
1404 > Collapsed = 1,
1405 > Expanded = 2
1406 > }
1407 >
1408 > export interface IDebugVisualizationTreeItem {
1409 > id: number;
1410 > label: string;
1411 > description?: string;
1412 > collapsibleState: DebugTreeItemCollapsibleState;
1413 > contextValue?: string;
1414 > canEdit?: boolean;
1415 > }
1416 >
1417 > export namespace IDebugVisualizationTreeItem {
1418 > export type Serialized = IDebugVisualizationTreeItem;
1419 > export const deserialize = (v: Serialized): IDebugVisualizationTreeItem => v;
1420 > export const serialize = (item: IDebugVisualizationTreeItem): Serialized => item;
1421 > }
1422 >
1423 > export interface IDebugVisualization {
1424 > id: number;
1425 > name: string;
1426 > iconPath: { light?: URI; dark: URI } | undefined;
1427 > iconClass: string | undefined;
1428 > visualization: MainThreadDebugVisualization | undefined;
1429 > }
1430 >
1431 > export namespace IDebugVisualization {
1432 > export interface Serialized {
1433 > id: number;
1434 > name: string;
1435 > iconPath?: { light?: UriComponents; dark: UriComponents };
1436 > iconClass?: string;
1437 > visualization?: MainThreadDebugVisualization;
1438 > }
1439 >
1440 > export const deserialize = (v: Serialized): IDebugVisualization => ({
1441 id: v.id,
1442 name: v.name,
1445 visualization: v.visualization,
1446 });
1447 > debug.ts
1448 > export const serialize = (visualizer: IDebugVisualization): Serialized => visualizer;
1449 > }
src/vs/workbench/common/editor.ts 1397 covered LOC · 36 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- editor.ts
2 > * Copyright (c) Microsoft 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 { Event } from '../../base/common/event.js';
8 > import { DeepRequiredNonNullable, assertReturnsDefined } from '../../base/common/types.js';
9 > import { URI } from '../../base/common/uri.js';
10 > import { Disposable, IDisposable, toDisposable } from '../../base/common/lifecycle.js';
11 > import { ICodeEditorViewState, IDiffEditor, IDiffEditorViewState, IEditor, IEditorViewState } from '../../editor/common/editorCommon.js';
12 > import { IEditorOptions, IResourceEditorInput, ITextResourceEditorInput, IBaseTextResourceEditorInput, IBaseUntypedEditorInput, ITextEditorOptions } from '../../platform/editor/common/editor.js';
13 > import type { EditorInput } from './editor/editorInput.js';
14 > import { IInstantiationService, IConstructorSignature, ServicesAccessor, BrandedService } from '../../platform/instantiation/common/instantiation.js';
15 > import { IContextKeyService } from '../../platform/contextkey/common/contextkey.js';
16 > import { Registry } from '../../platform/registry/common/platform.js';
17 > import { IEncodingSupport, ILanguageSupport } from '../services/textfile/common/textfiles.js';
18 > import { IEditorGroup } from '../services/editor/common/editorGroupsService.js';
19 > import { ICompositeControl, IComposite } from './composite.js';
20 > import { FileType, IFileReadLimits, IFileService } from '../../platform/files/common/files.js';
21 > import { IPathData } from '../../platform/window/common/window.js';
22 > import { IExtUri } from '../../base/common/resources.js';
23 > import { Schemas } from '../../base/common/network.js';
24 > import { IEditorService } from '../services/editor/common/editorService.js';
25 > import { ILogService } from '../../platform/log/common/log.js';
26 > import { IErrorWithActions, createErrorWithActions, isErrorWithActions } from '../../base/common/errorMessage.js';
27 > import { IAction, toAction } from '../../base/common/actions.js';
28 > import Severity from '../../base/common/severity.js';
29 > import { IPreferencesService } from '../services/preferences/common/preferences.js';
30 > import { IReadonlyEditorGroupModel } from './editor/editorGroupModel.js';
31 >
32 > // Static values for editor contributions
33 > export const EditorExtensions = {
34 > EditorPane: 'workbench.contributions.editors',
35 > EditorFactory: 'workbench.contributions.editor.inputFactories'
36 > };
37 >
38 > // Static information regarding the text editor
39 > export const DEFAULT_EDITOR_ASSOCIATION = {
40 > id: 'default',
41 > displayName: localize('promptOpenWith.defaultEditor.displayName', "Text Editor"),
42 > providerDisplayName: localize('builtinProviderDisplayName', "Built-in")
43 > };
44 >
45 > /**
46 > * Side by side editor id.
47 > */
48 > export const SIDE_BY_SIDE_EDITOR_ID = 'workbench.editor.sidebysideEditor';
49 >
50 > /**
51 > * Text diff editor id.
52 > */
53 > export const TEXT_DIFF_EDITOR_ID = 'workbench.editors.textDiffEditor';
54 >
55 > /**
56 > * Binary diff editor id.
57 > */
58 > export const BINARY_DIFF_EDITOR_ID = 'workbench.editors.binaryResourceDiffEditor';
59 >
60 > export interface IEditorDescriptor<T extends IEditorPane> {
61 >
62 > /**
63 > * The unique type identifier of the editor. All instances
64 > * of the same `IEditorPane` should have the same type
65 > * identifier.
66 > */
67 > readonly typeId: string;
68 >
69 > /**
70 > * The display name of the editor.
71 > */
72 > readonly name: string;
73 >
74 > /**
75 > * Instantiates the editor pane using the provided services.
76 > */
77 > instantiate(instantiationService: IInstantiationService, group: IEditorGroup): T;
78 >
79 > /**
80 > * Whether the descriptor is for the provided editor pane.
81 > */
82 > describes(editorPane: T): boolean;
83 > }
84 >
85 > /**
86 > * Declares that an editor hosts the full-width group header (rendered by the
87 > * editor group below the tab bar, using the group's configured header menus).
88 > */
89 > export interface IEditorHeaderActions {
90 > /** Editor-scoped instantiation service so the header toolbars' `when` clauses see the editor's context. */
91 > readonly instantiationService: IInstantiationService;
92 > }
93 >
94 > /**
95 > * The editor pane is the container for workbench editors.
96 > */
97 > export interface IEditorPane extends IComposite {
98 >
99 > /**
100 > * An event to notify when the `IEditorControl` in this
101 > * editor pane changes.
102 > *
103 > * This can be used for editor panes that are a compound
104 > * of multiple editor controls to signal that the active
105 > * editor control has changed when the user clicks around.
106 > */
107 > readonly onDidChangeControl: Event<void>;
108 >
109 > /**
110 > * An optional event to notify when the selection inside the editor
111 > * pane changed in case the editor has a selection concept.
112 > *
113 > * For example, in a text editor pane, the selection changes whenever
114 > * the cursor is set to a new location.
115 > */
116 > readonly onDidChangeSelection?: Event<IEditorPaneSelectionChangeEvent>;
117 >
118 > /**
119 > * An optional event to notify when the editor inside the pane scrolled
120 > */
121 > readonly onDidChangeScroll?: Event<void>;
122 >
123 > /**
124 > * The assigned input of this editor.
125 > */
126 > readonly input: EditorInput | undefined;
127 >
128 > /**
129 > * The assigned options of the editor.
130 > */
131 > readonly options: IEditorOptions | undefined;
132 >
133 > /**
134 > * The assigned group this editor is showing in.
135 > */
136 > readonly group: IEditorGroup;
137 >
138 > /**
139 > * The minimum width of this editor.
140 > */
141 > readonly minimumWidth: number;
142 >
143 > /**
144 > * The maximum width of this editor.
145 > */
146 > readonly maximumWidth: number;
147 >
148 > /**
149 > * The minimum height of this editor.
150 > */
151 > readonly minimumHeight: number;
152 >
153 > /**
154 > * The maximum height of this editor.
155 > */
156 > readonly maximumHeight: number;
157 >
158 > /**
159 > * An event to notify whenever minimum/maximum width/height changes.
160 > */
161 > readonly onDidChangeSizeConstraints: Event<{ width: number; height: number } | undefined>;
162 >
163 > /**
164 > * The context key service for this editor. Should be overridden by
165 > * editors that have their own ScopedContextKeyService
166 > */
167 > readonly scopedContextKeyService: IContextKeyService | undefined;
168 >
169 > /**
170 > * Returns the underlying control of this editor. Callers need to cast
171 > * the control to a specific instance as needed, e.g. by using the
172 > * `isCodeEditor` helper method to access the text code editor.
173 > *
174 > * Use the `onDidChangeControl` event to track whenever the control
175 > * changes.
176 > */
177 > getControl(): IEditorControl | undefined;
178 >
179 > /**
180 > * Returns the current view state of the editor if any.
181 > *
182 > * This method is optional to override for the editor pane
183 > * and should only be overridden when the pane can deal with
184 > * `IEditorOptions.viewState` to be applied when opening.
185 > */
186 > getViewState(): object | undefined;
187 >
188 > /**
189 > * An optional method to declare that this editor hosts the full-width group
190 > * header (rendered by the editor group below the tab bar using the group's
191 > * configured header menus), providing the editor-scoped instantiation service
192 > * so the header actions' `when` clauses evaluate in the editor's context.
193 > * Return `undefined` for no header (the default).
194 > */
195 > getHeaderActions?(): IEditorHeaderActions | undefined;
196 >
197 > /**
198 > * An optional method to return the current selection in
199 > * the editor pane in case the editor pane has a selection
200 > * concept.
201 > *
202 > * Clients of this method will typically react to the
203 > * `onDidChangeSelection` event to receive the current
204 > * selection as needed.
205 > */
206 > getSelection?(): IEditorPaneSelection | undefined;
207 >
208 > /**
209 > * An optional method to return the current scroll position
210 > * of an editor inside the pane.
211 > *
212 > * Clients of this method will typically react to the
213 > * `onDidChangeScroll` event to receive the current
214 > * scroll position as needed.
215 > */
216 > getScrollPosition?(): IEditorPaneScrollPosition;
217 >
218 > /**
219 > * An optional method to set the current scroll position
220 > * of an editor inside the pane.
221 > */
222 > setScrollPosition?(scrollPosition: IEditorPaneScrollPosition): void;
223 >
224 > /**
225 > * Finds out if this editor is visible or not.
226 > */
227 > isVisible(): boolean;
228 > }
229 >
230 > export interface IEditorPaneSelectionChangeEvent {
231 >
232 > /**
233 > * More details for how the selection was made.
234 > */
235 > reason: EditorPaneSelectionChangeReason;
236 > }
237 >
238 > export const enum EditorPaneSelectionChangeReason {
239 >
240 > /**
241 > * The selection was changed as a result of a programmatic
242 > * method invocation.
243 > *
244 > * For a text editor pane, this for example can be a selection
245 > * being restored from previous view state automatically.
246 > */
247 > PROGRAMMATIC = 1,
248 >
249 > /**
250 > * The selection was changed by the user.
251 > *
252 > * This typically means the user changed the selection
253 > * with mouse or keyboard.
254 > */
255 > USER,
256 >
257 > /**
258 > * The selection was changed as a result of editing in
259 > * the editor pane.
260 > *
261 > * For a text editor pane, this for example can be typing
262 > * in the text of the editor pane.
263 > */
264 > EDIT,
265 >
266 > /**
267 > * The selection was changed as a result of a navigation
268 > * action.
269 > *
270 > * For a text editor pane, this for example can be a result
271 > * of selecting an entry from a text outline view.
272 > */
273 > NAVIGATION,
274 >
275 > /**
276 > * The selection was changed as a result of a jump action
277 > * from within the editor pane.
278 > *
279 > * For a text editor pane, this for example can be a result
280 > * of invoking "Go to definition" from a symbol.
281 > */
282 > JUMP
283 > }
284 >
285 > export interface IEditorPaneSelection {
286 >
287 > /**
288 > * Asks to compare this selection to another selection.
289 > */
290 > compare(otherSelection: IEditorPaneSelection): EditorPaneSelectionCompareResult;
291 >
292 > /**
293 > * Asks to massage the provided `options` in a way
294 > * that the selection can be restored when the editor
295 > * is opened again.
296 > *
297 > * For a text editor this means to apply the selected
298 > * line and column as text editor options.
299 > */
300 > restore(options: IEditorOptions): IEditorOptions;
301 >
302 > /**
303 > * Only used for logging to print more info about the selection.
304 > */
305 > log?(): string;
306 > }
307 >
308 > export const enum EditorPaneSelectionCompareResult {
309 >
310 > /**
311 > * The selections are identical.
312 > */
313 > IDENTICAL = 1,
314 >
315 > /**
316 > * The selections are similar.
317 > *
318 > * For a text editor this can mean that the one
319 > * selection is in close proximity to the other
320 > * selection.
321 > *
322 > * Upstream clients may decide in this case to
323 > * not treat the selection different from the
324 > * previous one because it is not distinct enough.
325 > */
326 > SIMILAR = 2,
327 >
328 > /**
329 > * The selections are entirely different.
330 > */
331 > DIFFERENT = 3
332 > }
333 >
334 > export interface IEditorPaneWithSelection extends IEditorPane {
335 >
336 > readonly onDidChangeSelection: Event<IEditorPaneSelectionChangeEvent>;
337 >
338 > getSelection(): IEditorPaneSelection | undefined;
339 > }
340 >
341 > export function isEditorPaneWithSelection(editorPane: IEditorPane | undefined): editorPane is IEditorPaneWithSelection {
342 const candidate = editorPane as IEditorPaneWithSelection | undefined;
343
344 return !!candidate && typeof candidate.getSelection === 'function' && !!candidate.onDidChangeSelection;
345 }
346 > editor.ts
347 > export interface IEditorPaneWithScrolling extends IEditorPane {
348 >
349 > readonly onDidChangeScroll: Event<void>;
350 >
351 > getScrollPosition(): IEditorPaneScrollPosition;
352 >
353 > setScrollPosition(position: IEditorPaneScrollPosition): void;
354 > }
355 >
356 > export function isEditorPaneWithScrolling(editorPane: IEditorPane | undefined): editorPane is IEditorPaneWithScrolling {
357 const candidate = editorPane as IEditorPaneWithScrolling | undefined;
358
359 return !!candidate && typeof candidate.getScrollPosition === 'function' && typeof candidate.setScrollPosition === 'function' && !!candidate.onDidChangeScroll;
360 }
361 > editor.ts
362 > /**
363 > * Scroll position of a pane
364 > */
365 > export interface IEditorPaneScrollPosition {
366 > readonly scrollTop: number;
367 > readonly scrollLeft?: number;
368 > }
369 >
370 > /**
371 > * Try to retrieve the view state for the editor pane that
372 > * has the provided editor input opened, if at all.
373 > *
374 > * This method will return `undefined` if the editor input
375 > * is not visible in any of the opened editor panes.
376 > */
377 > export function findViewStateForEditor(input: EditorInput, group: GroupIdentifier, editorService: IEditorService): object | undefined {
378 for (const editorPane of editorService.visibleEditorPanes) {
379 if (editorPane.group.id === group && input.matches(editorPane.input)) {
384 return undefined;
385 }
386 > editor.ts
387 > /**
388 > * Overrides `IEditorPane` where `input` and `group` are known to be set.
389 > */
390 > export interface IVisibleEditorPane extends IEditorPane {
391 > readonly input: EditorInput;
392 > }
393 >
394 > /**
395 > * The text editor pane is the container for workbench text editors.
396 > */
397 > export interface ITextEditorPane extends IEditorPane {
398 >
399 > /**
400 > * Returns the underlying text editor widget of this editor.
401 > */
402 > getControl(): IEditor | undefined;
403 > }
404 >
405 > /**
406 > * The text editor pane is the container for workbench text diff editors.
407 > */
408 > export interface ITextDiffEditorPane extends IEditorPane {
409 >
410 > /**
411 > * Returns the underlying text diff editor widget of this editor.
412 > */
413 > getControl(): IDiffEditor | undefined;
414 > }
415 >
416 > /**
417 > * Marker interface for the control inside an editor pane. Callers
418 > * have to cast the control to work with it, e.g. via methods
419 > * such as `isCodeEditor(control)`.
420 > */
421 > export interface IEditorControl extends ICompositeControl { }
422 >
423 > export interface IFileEditorFactory {
424 >
425 > /**
426 > * The type identifier of the file editor.
427 > */
428 > typeId: string;
429 >
430 > /**
431 > * Creates new editor capable of showing files.
432 > */
433 > createFileEditor(resource: URI, preferredResource: URI | undefined, preferredName: string | undefined, preferredDescription: string | undefined, preferredEncoding: string | undefined, preferredLanguageId: string | undefined, preferredContents: string | undefined, instantiationService: IInstantiationService): IFileEditorInput;
434 >
435 > /**
436 > * Check if the provided object is a file editor.
437 > */
438 > isFileEditor(obj: unknown): obj is IFileEditorInput;
439 > }
440 >
441 > export interface IEditorFactoryRegistry {
442 >
443 > /**
444 > * Registers the file editor factory to use for file editors.
445 > */
446 > registerFileEditorFactory(factory: IFileEditorFactory): void;
447 >
448 > /**
449 > * Returns the file editor factory to use for file editors.
450 > */
451 > getFileEditorFactory(): IFileEditorFactory;
452 >
453 > /**
454 > * Registers a editor serializer for the given editor to the registry.
455 > * An editor serializer is capable of serializing and deserializing editor
456 > * from string data.
457 > *
458 > * @param editorTypeId the type identifier of the editor
459 > * @param serializer the editor serializer for serialization/deserialization
460 > */
461 > registerEditorSerializer<Services extends BrandedService[]>(editorTypeId: string, ctor: { new(...Services: Services): IEditorSerializer }): IDisposable;
462 >
463 > /**
464 > * Returns the editor serializer for the given editor.
465 > */
466 > getEditorSerializer(editor: EditorInput): IEditorSerializer | undefined;
467 > getEditorSerializer(editorTypeId: string): IEditorSerializer | undefined;
468 >
469 > /**
470 > * Starts the registry by providing the required services.
471 > */
472 > start(accessor: ServicesAccessor): void;
473 > }
474 >
475 > export interface IEditorSerializer {
476 >
477 > /**
478 > * Determines whether the given editor can be serialized by the serializer.
479 > */
480 > canSerialize(editor: EditorInput): boolean;
481 >
482 > /**
483 > * Returns a string representation of the provided editor that contains enough information
484 > * to deserialize back to the original editor from the deserialize() method.
485 > */
486 > serialize(editor: EditorInput): string | undefined;
487 >
488 > /**
489 > * Returns an editor from the provided serialized form of the editor. This form matches
490 > * the value returned from the serialize() method.
491 > */
492 > deserialize(instantiationService: IInstantiationService, serializedEditor: string): EditorInput | undefined;
493 > }
494 >
495 > export interface IUntitledTextResourceEditorInput extends IBaseTextResourceEditorInput {
496 >
497 > /**
498 > * Optional resource for the untitled editor. Depending on the value, the editor:
499 > * - should get a unique name if `undefined` (for example `Untitled-1`)
500 > * - should use the resource directly if the scheme is `untitled:`
501 > * - should change the scheme to `untitled:` otherwise and assume an associated path
502 > *
503 > * Untitled editors with associated path behave slightly different from other untitled
504 > * editors:
505 > * - they are dirty right when opening
506 > * - they will not ask for a file path when saving but use the associated path
507 > */
508 > readonly resource: URI | undefined;
509 > }
510 >
511 > /**
512 > * A resource side by side editor input shows 2 editors side by side but
513 > * without highlighting any differences.
514 > *
515 > * Note: both sides will be resolved as editor individually. As such, it is
516 > * possible to show 2 different editors side by side.
517 > *
518 > * @see {@link IResourceDiffEditorInput} for a variant that compares 2 editors.
519 > */
520 > export interface IResourceSideBySideEditorInput extends IBaseUntypedEditorInput {
521 >
522 > /**
523 > * The right hand side editor to open inside a side-by-side editor.
524 > */
525 > readonly primary: Omit<IResourceEditorInput, 'options'> | Omit<ITextResourceEditorInput, 'options'> | Omit<IUntitledTextResourceEditorInput, 'options'>;
526 >
527 > /**
528 > * The left hand side editor to open inside a side-by-side editor.
529 > */
530 > readonly secondary: Omit<IResourceEditorInput, 'options'> | Omit<ITextResourceEditorInput, 'options'> | Omit<IUntitledTextResourceEditorInput, 'options'>;
531 > }
532 >
533 > /**
534 > * A resource diff editor input compares 2 editors side by side
535 > * highlighting the differences.
536 > *
537 > * Note: both sides must be resolvable to the same editor, or
538 > * a text based presentation will be used as fallback.
539 > */
540 > export interface IResourceDiffEditorInput extends IBaseUntypedEditorInput {
541 >
542 > /**
543 > * The left hand side editor to open inside a diff editor.
544 > */
545 > readonly original: Omit<IResourceEditorInput, 'options'> | Omit<ITextResourceEditorInput, 'options'> | Omit<IUntitledTextResourceEditorInput, 'options'>;
546 >
547 > /**
548 > * The right hand side editor to open inside a diff editor.
549 > */
550 > readonly modified: Omit<IResourceEditorInput, 'options'> | Omit<ITextResourceEditorInput, 'options'> | Omit<IUntitledTextResourceEditorInput, 'options'>;
551 > }
552 >
553 > export interface ITextResourceDiffEditorInput extends IBaseTextResourceEditorInput {
554 >
555 > /**
556 > * The left hand side text editor to open inside a diff editor.
557 > */
558 > readonly original: Omit<ITextResourceEditorInput, 'options'> | Omit<IUntitledTextResourceEditorInput, 'options'>;
559 >
560 > /**
561 > * The right hand side text editor to open inside a diff editor.
562 > */
563 > readonly modified: Omit<ITextResourceEditorInput, 'options'> | Omit<IUntitledTextResourceEditorInput, 'options'>;
564 > }
565 >
566 > /**
567 > * A resource list diff editor input compares multiple resources side by side
568 > * highlighting the differences.
569 > */
570 > export interface IResourceMultiDiffEditorInput extends IBaseUntypedEditorInput {
571 > /**
572 > * A unique identifier of this multi diff editor input.
573 > * If a second multi diff editor with the same uri is opened, the existing one is revealed instead (even if the resources list is different!).
574 > */
575 > readonly multiDiffSource?: URI;
576 >
577 > /**
578 > * The list of resources to compare.
579 > * If not set, the resources are dynamically derived from the {@link multiDiffSource}.
580 > */
581 > readonly resources?: IMultiDiffEditorResource[];
582 >
583 > /**
584 > * Whether the editor should be serialized and stored for subsequent sessions.
585 > */
586 > readonly isTransient?: boolean;
587 > }
588 >
589 > export interface IMultiDiffEditorResource extends IResourceDiffEditorInput {
590 > readonly goToFileResource?: URI;
591 > }
592 > export type IResourceMergeEditorInputSide = (Omit<IResourceEditorInput, 'options'> | Omit<ITextResourceEditorInput, 'options'>) & { detail?: string };
593 >
594 > /**
595 > * A resource merge editor input compares multiple editors
596 > * highlighting the differences for merging.
597 > *
598 > * Note: all sides must be resolvable to the same editor, or
599 > * a text based presentation will be used as fallback.
600 > */
601 > export interface IResourceMergeEditorInput extends IBaseUntypedEditorInput {
602 >
603 > /**
604 > * The one changed version of the file.
605 > */
606 > readonly input1: IResourceMergeEditorInputSide;
607 >
608 > /**
609 > * The second changed version of the file.
610 > */
611 > readonly input2: IResourceMergeEditorInputSide;
612 >
613 > /**
614 > * The base common ancestor of the file to merge.
615 > */
616 > readonly base: Omit<IResourceEditorInput, 'options'> | Omit<ITextResourceEditorInput, 'options'>;
617 >
618 > /**
619 > * The resulting output of the merge.
620 > */
621 > readonly result: Omit<IResourceEditorInput, 'options'> | Omit<ITextResourceEditorInput, 'options'>;
622 > }
623 >
624 > export function isResourceEditorInput(editor: unknown): editor is IResourceEditorInput {
625 if (isEditorInput(editor)) {
626 return false; // make sure to not accidentally match on typed editor inputs
631 return URI.isUri(candidate?.resource);
632 }
633 > editor.ts
634 > export function isResourceDiffEditorInput(editor: unknown): editor is IResourceDiffEditorInput {
635 if (isEditorInput(editor)) {
636 return false; // make sure to not accidentally match on typed editor inputs
641 return candidate?.original !== undefined && candidate.modified !== undefined;
642 }
643 > editor.ts
644 > export function isResourceMultiDiffEditorInput(editor: unknown): editor is IResourceMultiDiffEditorInput {
645 if (isEditorInput(editor)) {
646 return false; // make sure to not accidentally match on typed editor inputs
657 return !!candidate.resources || !!candidate.multiDiffSource;
658 }
659 > editor.ts
660 > export function isResourceSideBySideEditorInput(editor: unknown): editor is IResourceSideBySideEditorInput {
661 if (isEditorInput(editor)) {
662 return false; // make sure to not accidentally match on typed editor inputs
671 return candidate?.primary !== undefined && candidate.secondary !== undefined;
672 }
673 > editor.ts
674 > export function isUntitledResourceEditorInput(editor: unknown): editor is IUntitledTextResourceEditorInput {
675 if (isEditorInput(editor)) {
676 return false; // make sure to not accidentally match on typed editor inputs
684 return candidate.resource === undefined || candidate.resource.scheme === Schemas.untitled || candidate.forceUntitled === true;
685 }
686 > editor.ts
687 > export function isResourceMergeEditorInput(editor: unknown): editor is IResourceMergeEditorInput {
688 if (isEditorInput(editor)) {
689 return false; // make sure to not accidentally match on typed editor inputs
694 return URI.isUri(candidate?.base?.resource) && URI.isUri(candidate?.input1?.resource) && URI.isUri(candidate?.input2?.resource) && URI.isUri(candidate?.result?.resource);
695 }
696 > editor.ts
697 > export const enum Verbosity {
698 > SHORT,
699 > MEDIUM,
700 > LONG
701 > }
702 >
703 > export const enum SaveReason {
704 >
705 > /**
706 > * Explicit user gesture.
707 > */
708 > EXPLICIT = 1,
709 >
710 > /**
711 > * Auto save after a timeout.
712 > */
713 > AUTO = 2,
714 >
715 > /**
716 > * Auto save after editor focus change.
717 > */
718 > FOCUS_CHANGE = 3,
719 >
720 > /**
721 > * Auto save after window change.
722 > */
723 > WINDOW_CHANGE = 4
724 > }
725 >
726 > export type SaveSource = string;
727 >
728 > interface ISaveSourceDescriptor {
729 > source: SaveSource;
730 > label: string;
731 > }
732 >
733 > class SaveSourceFactory {
734 >
735 > private readonly mapIdToSaveSource = new Map<SaveSource, ISaveSourceDescriptor>();
736 >
737 > /**
738 > * Registers a `SaveSource` with an identifier and label
739 > * to the registry so that it can be used in save operations.
740 > */
741 > registerSource(id: string, label: string): SaveSource {
742 let sourceDescriptor = this.mapIdToSaveSource.get(id);
743 if (!sourceDescriptor) {
748 return sourceDescriptor.source;
749 }
750 > editor.ts
751 > getSourceLabel(source: SaveSource): string {
752 return this.mapIdToSaveSource.get(source)?.label ?? source;
753 }
754 > } editor.ts
755 >
756 > export const SaveSourceRegistry = new SaveSourceFactory();
757 >
758 > export interface ISaveOptions {
759 >
760 > /**
761 > * An indicator how the save operation was triggered.
762 > */
763 > reason?: SaveReason;
764 >
765 > /**
766 > * An indicator about the source of the save operation.
767 > *
768 > * Must use `SaveSourceRegistry.registerSource()` to obtain.
769 > */
770 > readonly source?: SaveSource;
771 >
772 > /**
773 > * Forces to save the contents of the working copy
774 > * again even if the working copy is not dirty.
775 > */
776 > readonly force?: boolean;
777 >
778 > /**
779 > * Instructs the save operation to skip any save participants.
780 > */
781 > readonly skipSaveParticipants?: boolean;
782 >
783 > /**
784 > * A hint as to which file systems should be available for saving.
785 > */
786 > readonly availableFileSystems?: string[];
787 > }
788 >
789 > export interface IRevertOptions {
790 >
791 > /**
792 > * Forces to load the contents of the working copy
793 > * again even if the working copy is not dirty.
794 > */
795 > readonly force?: boolean;
796 >
797 > /**
798 > * A soft revert will clear dirty state of a working copy
799 > * but will not attempt to load it from its persisted state.
800 > *
801 > * This option may be used in scenarios where an editor is
802 > * closed and where we do not require to load the contents.
803 > */
804 > readonly soft?: boolean;
805 > }
806 >
807 > export interface IMoveResult {
808 > editor: EditorInput | IUntypedEditorInput;
809 > options?: IEditorOptions;
810 > }
811 >
812 > export const enum EditorInputCapabilities {
813 >
814 > /**
815 > * Signals no specific capability for the input.
816 > */
817 > None = 0,
818 >
819 > /**
820 > * Signals that the input is readonly.
821 > */
822 > Readonly = 1 << 1,
823 >
824 > /**
825 > * Signals that the input is untitled.
826 > */
827 > Untitled = 1 << 2,
828 >
829 > /**
830 > * Signals that the input can only be shown in one group
831 > * and not be split into multiple groups.
832 > */
833 > Singleton = 1 << 3,
834 >
835 > /**
836 > * Signals that the input requires workspace trust.
837 > */
838 > RequiresTrust = 1 << 4,
839 >
840 > /**
841 > * Signals that the editor can split into 2 in the same
842 > * editor group.
843 > */
844 > CanSplitInGroup = 1 << 5,
845 >
846 > /**
847 > * Signals that the editor wants its description to be
848 > * visible when presented to the user. By default, a UI
849 > * component may decide to hide the description portion
850 > * for brevity.
851 > */
852 > ForceDescription = 1 << 6,
853 >
854 > /**
855 > * Signals that the editor supports dropping into the
856 > * editor by holding shift.
857 > */
858 > CanDropIntoEditor = 1 << 7,
859 >
860 > /**
861 > * Signals that the editor is composed of multiple editors
862 > * within.
863 > */
864 > MultipleEditors = 1 << 8,
865 >
866 > /**
867 > * Signals that the editor cannot be in a dirty state
868 > * and may still have unsaved changes
869 > */
870 > Scratchpad = 1 << 9,
871 >
872 > /**
873 > * Signals that the editor should be revealed when being
874 > * opened if it is already opened in any editor group.
875 > */
876 > ForceReveal = 1 << 10,
877 >
878 > /**
879 > * Signals that the editor must be opened in a modal editor
880 > * part. This is honored unless the user has explicitly opted
881 > * out of modal editors via `workbench.editor.useModal: 'off'`.
882 > */
883 > RequiresModal = 1 << 11,
884 >
885 > /**
886 > * Signals that the editor is exempt from the opened editors
887 > * limit (`workbench.editor.limit`): it never counts towards the
888 > * limit and is never auto-closed to satisfy it.
889 > */
890 > ExcludeFromEditorLimit = 1 << 12
891 > }
892 >
893 > export type IUntypedEditorInput = IResourceEditorInput | ITextResourceEditorInput | IUntitledTextResourceEditorInput | IResourceDiffEditorInput | IResourceMultiDiffEditorInput | IResourceSideBySideEditorInput | IResourceMergeEditorInput;
894 >
895 > export abstract class AbstractEditorInput extends Disposable {
896 > // Marker class for implementing `isEditorInput`
897 > }
898 >
899 > export function isEditorInput(editor: unknown): editor is EditorInput {
900 return editor instanceof AbstractEditorInput;
901 }
902 > editor.ts
903 > export interface EditorInputWithPreferredResource {
904 >
905 > /**
906 > * An editor may provide an additional preferred resource alongside
907 > * the `resource` property. While the `resource` property serves as
908 > * unique identifier of the editor that should be used whenever we
909 > * compare to other editors, the `preferredResource` should be used
910 > * in places where e.g. the resource is shown to the user.
911 > *
912 > * For example: on Windows and macOS, the same URI with different
913 > * casing may point to the same file. The editor may chose to
914 > * "normalize" the URIs so that only one editor opens for different
915 > * URIs. But when displaying the editor label to the user, the
916 > * preferred URI should be used.
917 > *
918 > * Not all editors have a `preferredResource`. The `EditorResourceAccessor`
919 > * utility can be used to always get the right resource without having
920 > * to do instanceof checks.
921 > */
922 > readonly preferredResource: URI;
923 > }
924 >
925 function isEditorInputWithPreferredResource(editor: unknown): editor is EditorInputWithPreferredResource {
926 const candidate = editor as EditorInputWithPreferredResource | undefined;
928 return URI.isUri(candidate?.preferredResource);
929 }
930 > editor.ts
931 > export interface ISideBySideEditorInput extends EditorInput {
932 >
933 > /**
934 > * The primary editor input is shown on the right hand side.
935 > */
936 > primary: EditorInput;
937 >
938 > /**
939 > * The secondary editor input is shown on the left hand side.
940 > */
941 > secondary: EditorInput;
942 > }
943 >
944 > export function isSideBySideEditorInput(editor: unknown): editor is ISideBySideEditorInput {
945 const candidate = editor as ISideBySideEditorInput | undefined;
946
947 return isEditorInput(candidate?.primary) && isEditorInput(candidate?.secondary);
948 }
949 > editor.ts
950 > export interface IDiffEditorInput extends EditorInput {
951 >
952 > /**
953 > * The modified (primary) editor input is shown on the right hand side.
954 > */
955 > modified: EditorInput;
956 >
957 > /**
958 > * The original (secondary) editor input is shown on the left hand side.
959 > */
960 > original: EditorInput;
961 > }
962 >
963 > export function isDiffEditorInput(editor: unknown): editor is IDiffEditorInput {
964 const candidate = editor as IDiffEditorInput | undefined;
965
966 return isEditorInput(candidate?.modified) && isEditorInput(candidate?.original);
967 }
968 > editor.ts
969 > export interface IUntypedFileEditorInput extends ITextResourceEditorInput {
970 >
971 > /**
972 > * A marker to create a `IFileEditorInput` from this untyped input.
973 > */
974 > forceFile: true;
975 > }
976 >
977 > /**
978 > * This is a tagging interface to declare an editor input being capable of dealing with files. It is only used in the editor registry
979 > * to register this kind of input to the platform.
980 > */
981 > export interface IFileEditorInput extends EditorInput, IEncodingSupport, ILanguageSupport, EditorInputWithPreferredResource {
982 >
983 > /**
984 > * Gets the resource this file input is about. This will always be the
985 > * canonical form of the resource, so it may differ from the original
986 > * resource that was provided to create the input. Use `preferredResource`
987 > * for the form as it was created.
988 > */
989 > readonly resource: URI;
990 >
991 > /**
992 > * Sets the preferred resource to use for this file input.
993 > */
994 > setPreferredResource(preferredResource: URI): void;
995 >
996 > /**
997 > * Sets the preferred name to use for this file input.
998 > *
999 > * Note: for certain file schemes the input may decide to ignore this
1000 > * name and use our standard naming. Specifically for schemes we own,
1001 > * we do not let others override the name.
1002 > */
1003 > setPreferredName(name: string): void;
1004 >
1005 > /**
1006 > * Sets the preferred description to use for this file input.
1007 > *
1008 > * Note: for certain file schemes the input may decide to ignore this
1009 > * description and use our standard naming. Specifically for schemes we own,
1010 > * we do not let others override the description.
1011 > */
1012 > setPreferredDescription(description: string): void;
1013 >
1014 > /**
1015 > * Sets the preferred encoding to use for this file input.
1016 > */
1017 > setPreferredEncoding(encoding: string): void;
1018 >
1019 > /**
1020 > * Sets the preferred language id to use for this file input.
1021 > */
1022 > setPreferredLanguageId(languageId: string): void;
1023 >
1024 > /**
1025 > * Sets the preferred contents to use for this file input.
1026 > */
1027 > setPreferredContents(contents: string): void;
1028 >
1029 > /**
1030 > * Forces this file input to open as binary instead of text.
1031 > */
1032 > setForceOpenAsBinary(): void;
1033 >
1034 > /**
1035 > * Figure out if the file input has been resolved or not.
1036 > */
1037 > isResolved(): boolean;
1038 > }
1039 >
1040 > export interface IFileLimitedEditorInputOptions extends IEditorOptions {
1041 >
1042 > /**
1043 > * If provided, the size of the file will be checked against the limits
1044 > * and an error will be thrown if any limit is exceeded.
1045 > */
1046 > readonly limits?: IFileReadLimits;
1047 > }
1048 >
1049 > export interface IFileEditorInputOptions extends ITextEditorOptions, IFileLimitedEditorInputOptions { }
1050 >
1051 > export function createTooLargeFileError(group: IEditorGroup, input: EditorInput, options: IEditorOptions | undefined, message: string, preferencesService: IPreferencesService): Error {
1052 return createEditorOpenError(message, [
1053 toAction({
1073 });
1074 }
1075 > editor.ts
1076 > export interface EditorInputWithOptions {
1077 > editor: EditorInput;
1078 > options?: IEditorOptions;
1079 > }
1080 >
1081 > export interface EditorInputWithOptionsAndGroup extends EditorInputWithOptions {
1082 > group: IEditorGroup;
1083 > }
1084 >
1085 > export function isEditorInputWithOptions(editor: unknown): editor is EditorInputWithOptions {
1086 const candidate = editor as EditorInputWithOptions | undefined;
1087
1088 return isEditorInput(candidate?.editor);
1089 }
1090 > editor.ts
1091 > export function isEditorInputWithOptionsAndGroup(editor: unknown): editor is EditorInputWithOptionsAndGroup {
1092 const candidate = editor as EditorInputWithOptionsAndGroup | undefined;
1093
1094 return isEditorInputWithOptions(editor) && candidate?.group !== undefined;
1095 }
1096 > editor.ts
1097 > /**
1098 > * Context passed into `EditorPane#setInput` to give additional
1099 > * context information around why the editor was opened.
1100 > */
1101 > export interface IEditorOpenContext {
1102 >
1103 > /**
1104 > * An indicator if the editor input is new for the group the editor is in.
1105 > * An editor is new for a group if it was not part of the group before and
1106 > * otherwise was already opened in the group and just became the active editor.
1107 > *
1108 > * This hint can e.g. be used to decide whether to restore view state or not.
1109 > */
1110 > newInGroup?: boolean;
1111 > }
1112 >
1113 > export interface IEditorIdentifier {
1114 > groupId: GroupIdentifier;
1115 > editor: EditorInput;
1116 > }
1117 >
1118 > export function isEditorIdentifier(identifier: unknown): identifier is IEditorIdentifier {
1119 const candidate = identifier as IEditorIdentifier | undefined;
1120
1121 return typeof candidate?.groupId === 'number' && isEditorInput(candidate.editor);
1122 }
1123 > editor.ts
1124 > /**
1125 > * The editor commands context is used for editor commands (e.g. in the editor title)
1126 > * and we must ensure that the context is serializable because it potentially travels
1127 > * to the extension host!
1128 > */
1129 > export interface IEditorCommandsContext {
1130 > groupId: GroupIdentifier;
1131 > editorIndex?: number;
1132 >
1133 > preserveFocus?: boolean;
1134 > }
1135 >
1136 > export function isEditorCommandsContext(context: unknown): context is IEditorCommandsContext {
1137 const candidate = context as IEditorCommandsContext | undefined;
1138
1139 return typeof candidate?.groupId === 'number';
1140 }
1141 > editor.ts
1142 > /**
1143 > * More information around why an editor was closed in the model.
1144 > */
1145 > export enum EditorCloseContext {
1146 >
1147 > /**
1148 > * No specific context for closing (e.g. explicit user gesture).
1149 > */
1150 > UNKNOWN,
1151 >
1152 > /**
1153 > * The editor closed because it was replaced with another editor.
1154 > * This can either happen via explicit replace call or when an
1155 > * editor is in preview mode and another editor opens.
1156 > */
1157 > REPLACE,
1158 >
1159 > /**
1160 > * The editor closed as a result of moving it to another group.
1161 > */
1162 > MOVE,
1163 >
1164 > /**
1165 > * The editor closed because another editor turned into preview
1166 > * and this used to be the preview editor before.
1167 > */
1168 > UNPIN
1169 > }
1170 >
1171 > export interface IEditorCloseEvent extends IEditorIdentifier {
1172 >
1173 > /**
1174 > * More information around why the editor was closed.
1175 > */
1176 > readonly context: EditorCloseContext;
1177 >
1178 > /**
1179 > * The index of the editor before closing.
1180 > */
1181 > readonly index: number;
1182 >
1183 > /**
1184 > * Whether the editor was sticky or not.
1185 > */
1186 > readonly sticky: boolean;
1187 > }
1188 >
1189 > export interface IActiveEditorChangeEvent {
1190 >
1191 > /**
1192 > * The new active editor or `undefined` if the group is empty.
1193 > */
1194 > editor: EditorInput | undefined;
1195 >
1196 > /**
1197 > * Indicates whether the editor change is the result of an explicit
1198 > * user action (`true`) or happened automatically as a side effect
1199 > * (e.g. the chat agent opening files it has edited).
1200 > *
1201 > * When omitted, callers should treat the change as explicit.
1202 > */
1203 > isExplicit?: boolean;
1204 > }
1205 >
1206 > export interface IEditorWillMoveEvent extends IEditorIdentifier {
1207 >
1208 > /**
1209 > * The target group of the move operation.
1210 > */
1211 > readonly target: GroupIdentifier;
1212 > }
1213 >
1214 > export interface IEditorWillOpenEvent extends IEditorIdentifier { }
1215 >
1216 > export interface IWillInstantiateEditorPaneEvent {
1217 >
1218 > /**
1219 > * @see {@link IEditorDescriptor.typeId}
1220 > */
1221 > readonly typeId: string;
1222 > }
1223 >
1224 > export type GroupIdentifier = number;
1225 >
1226 > export const enum GroupModelChangeKind {
1227 >
1228 > /* Group Changes */
1229 > GROUP_ACTIVE,
1230 > GROUP_INDEX,
1231 > GROUP_LABEL,
1232 > GROUP_LOCKED,
1233 >
1234 > /* Editors Change */
1235 > EDITORS_SELECTION,
1236 >
1237 > /* Editor Changes */
1238 > EDITOR_OPEN,
1239 > EDITOR_CLOSE,
1240 > EDITOR_MOVE,
1241 > EDITOR_ACTIVE,
1242 > EDITOR_LABEL,
1243 > EDITOR_CAPABILITIES,
1244 > EDITOR_PIN,
1245 > EDITOR_TRANSIENT,
1246 > EDITOR_STICKY,
1247 > EDITOR_DIRTY,
1248 > EDITOR_WILL_DISPOSE
1249 > }
1250 >
1251 > export interface IWorkbenchEditorConfiguration {
1252 > workbench?: {
1253 > editor?: IEditorPartConfiguration;
1254 > iconTheme?: string;
1255 > };
1256 > }
1257 >
1258 > interface IEditorPartLimitConfiguration {
1259 > enabled?: boolean;
1260 > excludeDirty?: boolean;
1261 > value?: number;
1262 > perEditorGroup?: boolean;
1263 > }
1264 >
1265 > export interface IEditorPartLimitOptions extends Required<IEditorPartLimitConfiguration> { }
1266 >
1267 > interface IEditorPartDecorationsConfiguration {
1268 > badges?: boolean;
1269 > colors?: boolean;
1270 > }
1271 >
1272 > export interface IEditorPartDecorationOptions extends Required<IEditorPartDecorationsConfiguration> { }
1273 >
1274 > interface IEditorPartConfiguration {
1275 > showTabs?: 'multiple' | 'single' | 'none';
1276 > wrapTabs?: boolean;
1277 > scrollToSwitchTabs?: boolean;
1278 > highlightModifiedTabs?: boolean;
1279 > tabActionLocation?: 'left' | 'right';
1280 > tabActionCloseVisibility?: boolean;
1281 > tabActionUnpinVisibility?: boolean;
1282 > showTabIndex?: boolean;
1283 > alwaysShowEditorActions?: boolean;
1284 > tabSizing?: 'fit' | 'shrink' | 'fixed';
1285 > tabSizingFixedMinWidth?: number;
1286 > tabSizingFixedMaxWidth?: number;
1287 > pinnedTabSizing?: 'normal' | 'compact' | 'shrink';
1288 > pinnedTabsOnSeparateRow?: boolean;
1289 > tabHeight?: 'default' | 'compact';
1290 > preventPinnedEditorClose?: PreventPinnedEditorClose;
1291 > titleScrollbarSizing?: 'default' | 'large';
1292 > titleScrollbarVisibility?: 'auto' | 'visible' | 'hidden';
1293 > focusRecentEditorAfterClose?: boolean;
1294 > showIcons?: boolean;
1295 > enablePreview?: boolean;
1296 > enablePreviewFromQuickOpen?: boolean;
1297 > enablePreviewFromCodeNavigation?: boolean;
1298 > closeOnFileDelete?: boolean;
1299 > openPositioning?: 'left' | 'right' | 'first' | 'last';
1300 > openSideBySideDirection?: 'right' | 'down';
1301 > closeEmptyGroups?: boolean;
1302 > autoLockGroups?: Set<string>;
1303 > revealIfOpen?: boolean;
1304 > swipeToNavigate?: boolean;
1305 > mouseBackForwardToNavigate?: boolean;
1306 > labelFormat?: 'default' | 'short' | 'medium' | 'long';
1307 > restoreViewState?: boolean;
1308 > splitInGroupLayout?: 'vertical' | 'horizontal';
1309 > splitSizing?: 'auto' | 'split' | 'distribute';
1310 > splitOnDragAndDrop?: boolean;
1311 > allowDropIntoGroup?: boolean;
1312 > dragToOpenWindow?: boolean;
1313 > centeredLayoutFixedWidth?: boolean;
1314 > doubleClickTabToToggleEditorGroupSizes?: 'maximize' | 'expand' | 'off';
1315 > editorActionsLocation?: 'default' | 'titleBar' | 'hidden';
1316 > limit?: IEditorPartLimitConfiguration;
1317 > decorations?: IEditorPartDecorationsConfiguration;
1318 > }
1319 >
1320 > export interface IEditorPartOptions extends DeepRequiredNonNullable<IEditorPartConfiguration> {
1321 > hasIcons: boolean;
1322 > }
1323 >
1324 > export interface IEditorPartOptionsChangeEvent {
1325 > oldPartOptions: IEditorPartOptions;
1326 > newPartOptions: IEditorPartOptions;
1327 > }
1328 >
1329 > export enum SideBySideEditor {
1330 > PRIMARY = 1,
1331 > SECONDARY = 2,
1332 > BOTH = 3,
1333 > ANY = 4
1334 > }
1335 >
1336 > export interface IFindEditorOptions {
1337 >
1338 > /**
1339 > * Whether to consider any or both side by side editor as matching.
1340 > * By default, side by side editors will not be considered
1341 > * as matching, even if the editor is opened in one of the sides.
1342 > */
1343 > supportSideBySide?: SideBySideEditor.PRIMARY | SideBySideEditor.SECONDARY | SideBySideEditor.ANY;
1344 >
1345 > /**
1346 > * The order in which to consider editors for finding.
1347 > */
1348 > order?: EditorsOrder;
1349 > }
1350 >
1351 > export interface IMatchEditorOptions {
1352 >
1353 > /**
1354 > * Whether to consider a side by side editor as matching.
1355 > * By default, side by side editors will not be considered
1356 > * as matching, even if the editor is opened in one of the sides.
1357 > */
1358 > supportSideBySide?: SideBySideEditor.ANY | SideBySideEditor.BOTH;
1359 >
1360 > /**
1361 > * Only consider an editor to match when the
1362 > * `candidate === editor` but not when
1363 > * `candidate.matches(editor)`.
1364 > */
1365 > strictEquals?: boolean;
1366 > }
1367 >
1368 > export interface IEditorResourceAccessorOptions {
1369 >
1370 > /**
1371 > * Allows to access the `resource(s)` of side by side editors. If not
1372 > * specified, a `resource` for a side by side editor will always be
1373 > * `undefined`.
1374 > */
1375 > supportSideBySide?: SideBySideEditor;
1376 >
1377 > /**
1378 > * Allows to filter the scheme to consider. A resource scheme that does
1379 > * not match a filter will not be considered.
1380 > */
1381 > filterByScheme?: string | string[];
1382 > }
1383 >
1384 > class EditorResourceAccessorImpl {
1385 >
1386 > /**
1387 > * The original URI of an editor is the URI that was used originally to open
1388 > * the editor and should be used whenever the URI is presented to the user,
1389 > * e.g. as a label together with utility methods such as `ResourceLabel` or
1390 > * `ILabelService` that can turn this original URI into the best form for
1391 > * presenting.
1392 > *
1393 > * In contrast, the canonical URI (#getCanonicalUri) may be different and should
1394 > * be used whenever the URI is used to e.g. compare with other editors or when
1395 > * caching certain data based on the URI.
1396 > *
1397 > * For example: on Windows and macOS, the same file URI with different casing may
1398 > * point to the same file. The editor may chose to "normalize" the URI into a canonical
1399 > * form so that only one editor opens for same file URIs with different casing. As
1400 > * such, the original URI and the canonical URI can be different.
1401 > */
1402 > getOriginalUri(editor: EditorInput | IUntypedEditorInput | undefined | null): URI | undefined;
1403 > getOriginalUri(editor: EditorInput | IUntypedEditorInput | undefined | null, options: IEditorResourceAccessorOptions & { supportSideBySide?: SideBySideEditor.PRIMARY | SideBySideEditor.SECONDARY | SideBySideEditor.ANY }): URI | undefined;
1404 > getOriginalUri(editor: EditorInput | IUntypedEditorInput | undefined | null, options: IEditorResourceAccessorOptions & { supportSideBySide: SideBySideEditor.BOTH }): URI | { primary?: URI; secondary?: URI } | undefined;
1405 > getOriginalUri(editor: EditorInput | IUntypedEditorInput | undefined | null, options?: IEditorResourceAccessorOptions): URI | { primary?: URI; secondary?: URI } | undefined;
1406 > getOriginalUri(editor: EditorInput | IUntypedEditorInput | undefined | null, options?: IEditorResourceAccessorOptions): URI | { primary?: URI; secondary?: URI } | undefined {
1407 if (!editor) {
1408 return undefined;
1443 return this.filterUri(originalResource, options.filterByScheme);
1444 }
1445 > editor.ts
1446 > private getSideEditors(editor: EditorInput | IUntypedEditorInput): { primary: EditorInput | IUntypedEditorInput | undefined; secondary: EditorInput | IUntypedEditorInput | undefined } {
1447 if (isSideBySideEditorInput(editor) || isResourceSideBySideEditorInput(editor)) {
1448 return { primary: editor.primary, secondary: editor.secondary };
1455 return { primary: undefined, secondary: undefined };
1456 }
1457 > editor.ts
1458 > /**
1459 > * The canonical URI of an editor is the true unique identifier of the editor
1460 > * and should be used whenever the URI is used e.g. to compare with other
1461 > * editors or when caching certain data based on the URI.
1462 > *
1463 > * In contrast, the original URI (#getOriginalUri) may be different and should
1464 > * be used whenever the URI is presented to the user, e.g. as a label.
1465 > *
1466 > * For example: on Windows and macOS, the same file URI with different casing may
1467 > * point to the same file. The editor may chose to "normalize" the URI into a canonical
1468 > * form so that only one editor opens for same file URIs with different casing. As
1469 > * such, the original URI and the canonical URI can be different.
1470 > */
1471 > getCanonicalUri(editor: EditorInput | IUntypedEditorInput | undefined | null): URI | undefined;
1472 > getCanonicalUri(editor: EditorInput | IUntypedEditorInput | undefined | null, options: IEditorResourceAccessorOptions & { supportSideBySide?: SideBySideEditor.PRIMARY | SideBySideEditor.SECONDARY | SideBySideEditor.ANY }): URI | undefined;
1473 > getCanonicalUri(editor: EditorInput | IUntypedEditorInput | undefined | null, options: IEditorResourceAccessorOptions & { supportSideBySide: SideBySideEditor.BOTH }): URI | { primary?: URI; secondary?: URI } | undefined;
1474 > getCanonicalUri(editor: EditorInput | IUntypedEditorInput | undefined | null, options?: IEditorResourceAccessorOptions): URI | { primary?: URI; secondary?: URI } | undefined;
1475 > getCanonicalUri(editor: EditorInput | IUntypedEditorInput | undefined | null, options?: IEditorResourceAccessorOptions): URI | { primary?: URI; secondary?: URI } | undefined {
1476 if (!editor) {
1477 return undefined;
1512 return this.filterUri(canonicalResource, options.filterByScheme);
1513 }
1514 > editor.ts
1515 > private filterUri(resource: URI, filter: string | string[]): URI | undefined {
1516
1517 // Multiple scheme filter
1531 return undefined;
1532 }
1533 > } editor.ts
1534 >
1535 > export type PreventPinnedEditorClose = 'keyboardAndMouse' | 'keyboard' | 'mouse' | 'never' | undefined;
1536 >
1537 > export enum EditorCloseMethod {
1538 > UNKNOWN,
1539 > KEYBOARD,
1540 > MOUSE
1541 > }
1542 >
1543 > export function preventEditorClose(group: IEditorGroup | IReadonlyEditorGroupModel, editor: EditorInput, method: EditorCloseMethod, configuration: IEditorPartConfiguration): boolean {
1544 if (!group.isSticky(editor)) {
1545 return false; // only interested in sticky editors
1554 return false;
1555 }
1556 > editor.ts
1557 > export const EditorResourceAccessor = new EditorResourceAccessorImpl();
1558 >
1559 > export const enum CloseDirection {
1560 > LEFT,
1561 > RIGHT
1562 > }
1563 >
1564 > export interface IEditorMemento<T> {
1565 >
1566 > saveEditorState(group: IEditorGroup, resource: URI, state: T): void;
1567 > saveEditorState(group: IEditorGroup, editor: EditorInput, state: T): void;
1568 >
1569 > loadEditorState(group: IEditorGroup, resource: URI): T | undefined;
1570 > loadEditorState(group: IEditorGroup, editor: EditorInput): T | undefined;
1571 >
1572 > clearEditorState(resource: URI, group?: IEditorGroup): void;
1573 > clearEditorState(editor: EditorInput, group?: IEditorGroup): void;
1574 >
1575 > clearEditorStateOnDispose(resource: URI, editor: EditorInput): void;
1576 >
1577 > moveEditorState(source: URI, target: URI, comparer: IExtUri): void;
1578 > }
1579 >
1580 > class EditorFactoryRegistry implements IEditorFactoryRegistry {
1581 > private instantiationService: IInstantiationService | undefined;
1582 >
1583 > private fileEditorFactory: IFileEditorFactory | undefined;
1584 >
1585 > private readonly editorSerializerConstructors = new Map<string /* Type ID */, IConstructorSignature<IEditorSerializer>>();
1586 > private readonly editorSerializerInstances = new Map<string /* Type ID */, IEditorSerializer>();
1587 >
1588 > start(accessor: ServicesAccessor): void {
1589 const instantiationService = this.instantiationService = accessor.get(IInstantiationService);
1590
1595 this.editorSerializerConstructors.clear();
1596 }
1597 > editor.ts
1598 > private createEditorSerializer(editorTypeId: string, ctor: IConstructorSignature<IEditorSerializer>, instantiationService: IInstantiationService): void {
1599 const instance = instantiationService.createInstance(ctor);
1600 this.editorSerializerInstances.set(editorTypeId, instance);
1601 }
1602 > editor.ts
1603 > registerFileEditorFactory(factory: IFileEditorFactory): void {
1604 if (this.fileEditorFactory) {
1605 throw new Error('Can only register one file editor factory.');
1608 this.fileEditorFactory = factory;
1609 }
1610 > editor.ts
1611 > getFileEditorFactory(): IFileEditorFactory {
1612 return assertReturnsDefined(this.fileEditorFactory);
1613 }
1614 > editor.ts
1615 > registerEditorSerializer(editorTypeId: string, ctor: IConstructorSignature<IEditorSerializer>): IDisposable {
1616 if (this.editorSerializerConstructors.has(editorTypeId) || this.editorSerializerInstances.has(editorTypeId)) {
1617 throw new Error(`A editor serializer with type ID '${editorTypeId}' was already registered.`);
1629 });
1630 }
1631 > editor.ts
1632 > getEditorSerializer(editor: EditorInput): IEditorSerializer | undefined;
1633 > getEditorSerializer(editorTypeId: string): IEditorSerializer | undefined;
1634 > getEditorSerializer(arg1: string | EditorInput): IEditorSerializer | undefined {
1635 return this.editorSerializerInstances.get(typeof arg1 === 'string' ? arg1 : arg1.typeId);
1636 }
1637 > } editor.ts
1638 >
1639 > Registry.add(EditorExtensions.EditorFactory, new EditorFactoryRegistry());
1640 >
1641 export async function pathsToEditors(paths: IPathData[] | undefined, fileService: IFileService, logService: ILogService): Promise<ReadonlyArray<IResourceEditorInput | IUntitledTextResourceEditorInput | undefined>> {
1642 if (!paths?.length) {
1691 }));
1692 }
1693 > editor.ts
1694 > export const enum EditorsOrder {
1695 >
1696 > /**
1697 > * Editors sorted by most recent activity (most recent active first)
1698 > */
1699 > MOST_RECENTLY_ACTIVE,
1700 >
1701 > /**
1702 > * Editors sorted by sequential order
1703 > */
1704 > SEQUENTIAL
1705 > }
1706 >
1707 > export function isTextEditorViewState(candidate: unknown): candidate is IEditorViewState {
1708 const viewState = candidate as IEditorViewState | undefined;
1709 if (!viewState) {
1720 return !!(codeEditorViewState.contributionsState && codeEditorViewState.viewState && Array.isArray(codeEditorViewState.cursorState));
1721 }
1722 > editor.ts
1723 > export interface IEditorOpenErrorOptions {
1724 >
1725 > /**
1726 > * If set to true, the message will be taken
1727 > * from the error message entirely and not be
1728 > * composed with more text.
1729 > */
1730 > forceMessage?: boolean;
1731 >
1732 > /**
1733 > * If set, will override the severity of the error.
1734 > */
1735 > forceSeverity?: Severity;
1736 >
1737 > /**
1738 > * If set to true, the error may be shown in a dialog
1739 > * to the user if the editor opening was triggered by
1740 > * user action. Otherwise and by default, the error will
1741 > * be shown as place holder in the editor area.
1742 > */
1743 > allowDialog?: boolean;
1744 > }
1745 >
1746 > export interface IEditorOpenError extends IErrorWithActions, IEditorOpenErrorOptions { }
1747 >
1748 > export function isEditorOpenError(obj: unknown): obj is IEditorOpenError {
1749 return isErrorWithActions(obj);
1750 }
1751 > editor.ts
1752 > export function createEditorOpenError(messageOrError: string | Error, actions: IAction[], options?: IEditorOpenErrorOptions): IEditorOpenError {
1753 const error: IEditorOpenError = createErrorWithActions(messageOrError, actions);
1754
1759 return error;
1760 }
1761 > editor.ts
1762 > export interface IToolbarActions {
1763 > readonly primary: IAction[];
1764 > readonly secondary: IAction[];
1765 > }
src/vs/platform/files/common/files.ts 1360 covered LOC · 44 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- files.ts
2 > * Copyright (c) Microsoft 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, VSBufferReadable, VSBufferReadableStream } from '../../../base/common/buffer.js';
7 > import { CancellationToken } from '../../../base/common/cancellation.js';
8 > import { Event } from '../../../base/common/event.js';
9 > import { IExpression, IRelativePattern } from '../../../base/common/glob.js';
10 > import { IDisposable } from '../../../base/common/lifecycle.js';
11 > import { TernarySearchTree } from '../../../base/common/ternarySearchTree.js';
12 > import { sep } from '../../../base/common/path.js';
13 > import { ReadableStreamEvents } from '../../../base/common/stream.js';
14 > import { startsWithIgnoreCase } from '../../../base/common/strings.js';
15 > import { isNumber } from '../../../base/common/types.js';
16 > import { URI } from '../../../base/common/uri.js';
17 > import { localize } from '../../../nls.js';
18 > import { createDecorator } from '../../instantiation/common/instantiation.js';
19 > import { isWeb } from '../../../base/common/platform.js';
20 > import { Schemas } from '../../../base/common/network.js';
21 > import { IMarkdownString } from '../../../base/common/htmlContent.js';
22 > import { Lazy } from '../../../base/common/lazy.js';
23 >
24 > //#region file service & providers
25 >
26 > export const IFileService = createDecorator<IFileService>('fileService');
27 >
28 > export interface IFileService {
29 >
30 > readonly _serviceBrand: undefined;
31 >
32 > /**
33 > * An event that is fired when a file system provider is added or removed
34 > */
35 > readonly onDidChangeFileSystemProviderRegistrations: Event<IFileSystemProviderRegistrationEvent>;
36 >
37 > /**
38 > * An event that is fired when a registered file system provider changes its capabilities.
39 > */
40 > readonly onDidChangeFileSystemProviderCapabilities: Event<IFileSystemProviderCapabilitiesChangeEvent>;
41 >
42 > /**
43 > * An event that is fired when a file system provider is about to be activated. Listeners
44 > * can join this event with a long running promise to help in the activation process.
45 > */
46 > readonly onWillActivateFileSystemProvider: Event<IFileSystemProviderActivationEvent>;
47 >
48 > /**
49 > * Registers a file system provider for a certain scheme.
50 > */
51 > registerProvider(scheme: string, provider: IFileSystemProvider): IDisposable;
52 >
53 > /**
54 > * Returns a file system provider for a certain scheme.
55 > */
56 > getProvider(scheme: string): IFileSystemProvider | undefined;
57 >
58 > /**
59 > * Tries to activate a provider with the given scheme.
60 > */
61 > activateProvider(scheme: string): Promise<void>;
62 >
63 > /**
64 > * Checks if this file service can handle the given resource by
65 > * first activating any extension that wants to be activated
66 > * on the provided resource scheme to include extensions that
67 > * contribute file system providers for the given resource.
68 > */
69 > canHandleResource(resource: URI): Promise<boolean>;
70 >
71 > /**
72 > * Checks if the file service has a registered provider for the
73 > * provided resource.
74 > *
75 > * Note: this does NOT account for contributed providers from
76 > * extensions that have not been activated yet. To include those,
77 > * consider to call `await fileService.canHandleResource(resource)`.
78 > */
79 > hasProvider(resource: URI): boolean;
80 >
81 > /**
82 > * Checks if the provider for the provided resource has the provided file system capability.
83 > */
84 > hasCapability(resource: URI, capability: FileSystemProviderCapabilities): boolean;
85 >
86 > /**
87 > * List the schemes and capabilities for registered file system providers
88 > */
89 > listCapabilities(): Iterable<{ scheme: string; capabilities: FileSystemProviderCapabilities }>;
90 >
91 > /**
92 > * Allows to listen for file changes. The event will fire for every file within the opened workspace
93 > * (if any) as well as all files that have been watched explicitly using the #watch() API.
94 > */
95 > readonly onDidFilesChange: Event<FileChangesEvent>;
96 >
97 > /**
98 > * An event that is fired upon successful completion of a certain file operation.
99 > */
100 > readonly onDidRunOperation: Event<FileOperationEvent>;
101 >
102 > /**
103 > * Resolve the properties of a file/folder identified by the resource. For a folder, children
104 > * information is resolved as well depending on the provided options. Use `stat()` method if
105 > * you do not need children information.
106 > *
107 > * If the optional parameter "resolveTo" is specified in options, the stat service is asked
108 > * to provide a stat object that should contain the full graph of folders up to all of the
109 > * target resources.
110 > *
111 > * If the optional parameter "resolveSingleChildDescendants" is specified in options,
112 > * the stat service is asked to automatically resolve child folders that only
113 > * contain a single element.
114 > *
115 > * If the optional parameter "resolveMetadata" is specified in options,
116 > * the stat will contain metadata information such as size, mtime and etag.
117 > */
118 > resolve(resource: URI, options: IResolveMetadataFileOptions): Promise<IFileStatWithMetadata>;
119 > resolve(resource: URI, options?: IResolveFileOptions): Promise<IFileStat>;
120 >
121 > /**
122 > * Same as `resolve()` but supports resolving multiple resources in parallel.
123 > *
124 > * If one of the resolve targets fails to resolve returns a fake `IFileStat` instead of
125 > * making the whole call fail.
126 > */
127 > resolveAll(toResolve: { resource: URI; options: IResolveMetadataFileOptions }[]): Promise<IFileStatResult[]>;
128 > resolveAll(toResolve: { resource: URI; options?: IResolveFileOptions }[]): Promise<IFileStatResult[]>;
129 >
130 > /**
131 > * Same as `resolve()` but without resolving the children of a folder if the
132 > * resource is pointing to a folder.
133 > */
134 > stat(resource: URI): Promise<IFileStatWithPartialMetadata>;
135 >
136 > /**
137 > * Attempts to resolve the real path of the provided resource. The real path can be
138 > * different from the resource path for example when it is a symlink.
139 > *
140 > * Will return `undefined` if the real path cannot be resolved.
141 > */
142 > realpath(resource: URI): Promise<URI | undefined>;
143 >
144 > /**
145 > * Finds out if a file/folder identified by the resource exists.
146 > */
147 > exists(resource: URI): Promise<boolean>;
148 >
149 > /**
150 > * Read the contents of the provided resource unbuffered.
151 > */
152 > readFile(resource: URI, options?: IReadFileOptions, token?: CancellationToken): Promise<IFileContent>;
153 >
154 > /**
155 > * Read the contents of the provided resource buffered as stream.
156 > */
157 > readFileStream(resource: URI, options?: IReadFileStreamOptions, token?: CancellationToken): Promise<IFileStreamContent>;
158 >
159 > /**
160 > * Updates the content replacing its previous value.
161 > * If `options.append` is true, appends content to the end of the file instead.
162 > *
163 > * Emits a `FileOperation.WRITE` file operation event when successful.
164 > */
165 > writeFile(resource: URI, bufferOrReadableOrStream: VSBuffer | VSBufferReadable | VSBufferReadableStream, options?: IWriteFileOptions): Promise<IFileStatWithMetadata>;
166 >
167 > /**
168 > * Moves the file/folder to a new path identified by the resource.
169 > *
170 > * The optional parameter overwrite can be set to replace an existing file at the location.
171 > *
172 > * Emits a `FileOperation.MOVE` file operation event when successful.
173 > */
174 > move(source: URI, target: URI, overwrite?: boolean): Promise<IFileStatWithMetadata>;
175 >
176 > /**
177 > * Find out if a move operation is possible given the arguments. No changes on disk will
178 > * be performed. Returns an Error if the operation cannot be done.
179 > */
180 > canMove(source: URI, target: URI, overwrite?: boolean): Promise<Error | true>;
181 >
182 > /**
183 > * Copies the file/folder to a path identified by the resource. A folder is copied
184 > * recursively.
185 > *
186 > * Emits a `FileOperation.COPY` file operation event when successful.
187 > */
188 > copy(source: URI, target: URI, overwrite?: boolean): Promise<IFileStatWithMetadata>;
189 >
190 > /**
191 > * Find out if a copy operation is possible given the arguments. No changes on disk will
192 > * be performed. Returns an Error if the operation cannot be done.
193 > */
194 > canCopy(source: URI, target: URI, overwrite?: boolean): Promise<Error | true>;
195 >
196 > /**
197 > * Clones a file to a path identified by the resource. Folders are not supported.
198 > *
199 > * If the target path exists, it will be overwritten.
200 > */
201 > cloneFile(source: URI, target: URI): Promise<void>;
202 >
203 > /**
204 > * Creates a new file with the given path and optional contents. The returned promise
205 > * will have the stat model object as a result.
206 > *
207 > * The optional parameter content can be used as value to fill into the new file.
208 > *
209 > * Emits a `FileOperation.CREATE` file operation event when successful.
210 > */
211 > createFile(resource: URI, bufferOrReadableOrStream?: VSBuffer | VSBufferReadable | VSBufferReadableStream, options?: ICreateFileOptions): Promise<IFileStatWithMetadata>;
212 >
213 > /**
214 > * Find out if a file create operation is possible given the arguments. No changes on disk will
215 > * be performed. Returns an Error if the operation cannot be done.
216 > */
217 > canCreateFile(resource: URI, options?: ICreateFileOptions): Promise<Error | true>;
218 >
219 > /**
220 > * Creates a new folder with the given path. The returned promise
221 > * will have the stat model object as a result.
222 > *
223 > * Emits a `FileOperation.CREATE` file operation event when successful.
224 > */
225 > createFolder(resource: URI): Promise<IFileStatWithMetadata>;
226 >
227 > /**
228 > * Deletes the provided file. The optional useTrash parameter allows to
229 > * move the file to trash. The optional recursive parameter allows to delete
230 > * non-empty folders recursively.
231 > *
232 > * Emits a `FileOperation.DELETE` file operation event when successful.
233 > */
234 > del(resource: URI, options?: Partial<IFileDeleteOptions>): Promise<void>;
235 >
236 > /**
237 > * Find out if a delete operation is possible given the arguments. No changes on disk will
238 > * be performed. Returns an Error if the operation cannot be done.
239 > */
240 > canDelete(resource: URI, options?: Partial<IFileDeleteOptions>): Promise<Error | true>;
241 >
242 > /**
243 > * An event that signals an error when watching for file changes.
244 > */
245 > readonly onDidWatchError: Event<Error>;
246 >
247 > /**
248 > * Allows to start a watcher that reports file/folder change events on the provided resource.
249 > *
250 > * The watcher runs correlated and thus, file events will be reported on the returned
251 > * `IFileSystemWatcher` and not on the generic `IFileService.onDidFilesChange` event.
252 > *
253 > * Note: only non-recursive file watching supports event correlation for now.
254 > */
255 > createWatcher(resource: URI, options: IWatchOptionsWithoutCorrelation & { recursive: false }): IFileSystemWatcher;
256 >
257 > /**
258 > * Allows to start a watcher that reports file/folder change events on the provided resource.
259 > *
260 > * The watcher runs uncorrelated and thus will report all events from `IFileService.onDidFilesChange`.
261 > * This means, most listeners in the application will receive your events. It is encouraged to
262 > * use correlated watchers (via `IWatchOptionsWithCorrelation`) to limit events to your listener.
263 > */
264 > watch(resource: URI, options?: IWatchOptionsWithoutCorrelation): IDisposable;
265 >
266 > /**
267 > * Frees up any resources occupied by this service.
268 > */
269 > dispose(): void;
270 > }
271 >
272 > export interface IFileOverwriteOptions {
273 >
274 > /**
275 > * Set to `true` to overwrite a file if it exists. Will
276 > * throw an error otherwise if the file does exist.
277 > */
278 > readonly overwrite: boolean;
279 > }
280 >
281 > export interface IFileUnlockOptions {
282 >
283 > /**
284 > * Set to `true` to try to remove any write locks the file might
285 > * have. A file that is write locked will throw an error for any
286 > * attempt to write to unless `unlock: true` is provided.
287 > */
288 > readonly unlock: boolean;
289 > }
290 >
291 > export interface IFileAtomicReadOptions {
292 >
293 > /**
294 > * The optional `atomic` flag can be used to make sure
295 > * the `readFile` method is not running in parallel with
296 > * any `write` operations in the same process.
297 > *
298 > * Typically you should not need to use this flag but if
299 > * for example you are quickly reading a file right after
300 > * a file event occurred and the file changes a lot, there
301 > * is a chance that a read returns an empty or partial file
302 > * because a pending write has not finished yet.
303 > *
304 > * Note: this does not prevent the file from being written
305 > * to from a different process. If you need such atomic
306 > * operations, you better use a real database as storage.
307 > */
308 > readonly atomic: boolean;
309 > }
310 >
311 > export interface IFileAtomicOptions {
312 >
313 > /**
314 > * The postfix is used to create a temporary file based
315 > * on the original resource. The resulting temporary
316 > * file will be in the same folder as the resource and
317 > * have `postfix` appended to the resource name.
318 > *
319 > * Example: given a file resource `file:///some/path/foo.txt`
320 > * and a postfix `.vsctmp`, the temporary file will be
321 > * created as `file:///some/path/foo.txt.vsctmp`.
322 > */
323 > readonly postfix: string;
324 > }
325 >
326 > export interface IFileAtomicWriteOptions {
327 >
328 > /**
329 > * The optional `atomic` flag can be used to make sure
330 > * the `writeFile` method updates the target file atomically
331 > * by first writing to a temporary file in the same folder
332 > * and then renaming it over the target.
333 > */
334 > readonly atomic: IFileAtomicOptions | false;
335 > }
336 >
337 > export interface IFileAtomicDeleteOptions {
338 >
339 > /**
340 > * The optional `atomic` flag can be used to make sure
341 > * the `delete` method deletes the target atomically by
342 > * first renaming it to a temporary resource in the same
343 > * folder and then deleting it.
344 > */
345 > readonly atomic: IFileAtomicOptions | false;
346 > }
347 >
348 > export interface IFileReadLimits {
349 >
350 > /**
351 > * If the file exceeds the given size, an error of kind
352 > * `FILE_TOO_LARGE` will be thrown.
353 > */
354 > size?: number;
355 > }
356 >
357 > export interface IFileReadStreamOptions {
358 >
359 > /**
360 > * Is an integer specifying where to begin reading from in the file. If position is undefined,
361 > * data will be read from the current file position.
362 > */
363 > readonly position?: number;
364 >
365 > /**
366 > * Is an integer specifying how many bytes to read from the file. By default, all bytes
367 > * will be read.
368 > */
369 > readonly length?: number;
370 >
371 > /**
372 > * If provided, the size of the file will be checked against the limits
373 > * and an error will be thrown if any limit is exceeded.
374 > */
375 > readonly limits?: IFileReadLimits;
376 > }
377 >
378 > export interface IFileWriteOptions extends IFileOverwriteOptions, IFileUnlockOptions, IFileAtomicWriteOptions {
379 >
380 > /**
381 > * Set to `true` to create a file when it does not exist. Will
382 > * throw an error otherwise if the file does not exist.
383 > */
384 > readonly create: boolean;
385 >
386 > /**
387 > * Set to `true` to append content to the end of the file. Implies `create: true`,
388 > * and set only when the corresponding `FileAppend` capability is defined.
389 > */
390 > readonly append?: boolean;
391 > }
392 >
393 > export type IFileOpenOptions = IFileOpenForReadOptions | IFileOpenForWriteOptions;
394 >
395 > export function isFileOpenForWriteOptions(options: IFileOpenOptions): options is IFileOpenForWriteOptions {
396 return options.create === true;
397 }
398 > files.ts
399 > export interface IFileOpenForReadOptions {
400 >
401 > /**
402 > * A hint that the file should be opened for reading only.
403 > */
404 > readonly create: false;
405 > }
406 >
407 > export interface IFileOpenForWriteOptions extends IFileUnlockOptions {
408 >
409 > /**
410 > * A hint that the file should be opened for reading and writing.
411 > */
412 > readonly create: true;
413 >
414 > /**
415 > * Open the file in append mode. This will write data to the
416 > * end of the file.
417 > */
418 > readonly append?: boolean;
419 > }
420 >
421 > export interface IFileDeleteOptions {
422 >
423 > /**
424 > * Set to `true` to recursively delete any children of the file. This
425 > * only applies to folders and can lead to an error unless provided
426 > * if the folder is not empty.
427 > */
428 > readonly recursive: boolean;
429 >
430 > /**
431 > * Set to `true` to attempt to move the file to trash
432 > * instead of deleting it permanently from disk.
433 > *
434 > * This option maybe not be supported on all providers.
435 > */
436 > readonly useTrash: boolean;
437 >
438 > /**
439 > * The optional `atomic` flag can be used to make sure
440 > * the `delete` method deletes the target atomically by
441 > * first renaming it to a temporary resource in the same
442 > * folder and then deleting it.
443 > *
444 > * This option maybe not be supported on all providers.
445 > */
446 > readonly atomic: IFileAtomicOptions | false;
447 > }
448 >
449 > export enum FileType {
450 >
451 > /**
452 > * File is unknown (neither file, directory nor symbolic link).
453 > */
454 > Unknown = 0,
455 >
456 > /**
457 > * File is a normal file.
458 > */
459 > File = 1,
460 >
461 > /**
462 > * File is a directory.
463 > */
464 > Directory = 2,
465 >
466 > /**
467 > * File is a symbolic link.
468 > *
469 > * Note: even when the file is a symbolic link, you can test for
470 > * `FileType.File` and `FileType.Directory` to know the type of
471 > * the target the link points to.
472 > */
473 > SymbolicLink = 64
474 > }
475 >
476 > export enum FilePermission {
477 >
478 > /**
479 > * File is readonly. Components like editors should not
480 > * offer to edit the contents.
481 > */
482 > Readonly = 1,
483 >
484 > /**
485 > * File is locked. Components like editors should offer
486 > * to edit the contents and ask the user upon saving to
487 > * remove the lock.
488 > */
489 > Locked = 2,
490 >
491 > /**
492 > * File is executable. Relevant for Unix-like systems where
493 > * the executable bit determines if a file can be run.
494 > */
495 > Executable = 4
496 > }
497 >
498 > export interface IStat {
499 >
500 > /**
501 > * The file type.
502 > */
503 > readonly type: FileType;
504 >
505 > /**
506 > * The last modification date represented as millis from unix epoch.
507 > */
508 > readonly mtime: number;
509 >
510 > /**
511 > * The creation date represented as millis from unix epoch.
512 > */
513 > readonly ctime: number;
514 >
515 > /**
516 > * The size of the file in bytes.
517 > */
518 > readonly size: number;
519 >
520 > /**
521 > * The file permissions.
522 > */
523 > readonly permissions?: FilePermission;
524 > }
525 >
526 > export interface IWatchOptionsWithoutCorrelation {
527 >
528 > /**
529 > * Set to `true` to watch for changes recursively in a folder
530 > * and all of its children.
531 > */
532 > recursive: boolean;
533 >
534 > /**
535 > * A set of glob patterns or paths to exclude from watching.
536 > * Paths can be relative or absolute and when relative are
537 > * resolved against the watched folder. Glob patterns are
538 > * always matched relative to the watched folder.
539 > */
540 > excludes: string[];
541 >
542 > /**
543 > * An optional set of glob patterns or paths to include for
544 > * watching. If not provided, all paths are considered for
545 > * events.
546 > * Paths can be relative or absolute and when relative are
547 > * resolved against the watched folder. Glob patterns are
548 > * always matched relative to the watched folder.
549 > */
550 > includes?: Array<string | IRelativePattern>;
551 >
552 > /**
553 > * If provided, allows to filter the events that the watcher should consider
554 > * for emitting. If not provided, all events are emitted.
555 > *
556 > * For example, to emit added and updated events, set to:
557 > * `FileChangeFilter.ADDED | FileChangeFilter.UPDATED`.
558 > */
559 > filter?: FileChangeFilter;
560 > }
561 >
562 > export interface IWatchOptions extends IWatchOptionsWithoutCorrelation {
563 >
564 > /**
565 > * If provided, file change events from the watcher that
566 > * are a result of this watch request will carry the same
567 > * id.
568 > */
569 > readonly correlationId?: number;
570 > }
571 >
572 > export const enum FileChangeFilter {
573 > UPDATED = 1 << 1,
574 > ADDED = 1 << 2,
575 > DELETED = 1 << 3
576 > }
577 >
578 > export interface IWatchOptionsWithCorrelation extends IWatchOptions {
579 > readonly correlationId: number;
580 > }
581 >
582 > export interface IFileSystemWatcher extends IDisposable {
583 >
584 > /**
585 > * An event which fires on file/folder change only for changes
586 > * that correlate to the watch request with matching correlation
587 > * identifier.
588 > */
589 > readonly onDidChange: Event<FileChangesEvent>;
590 > }
591 >
592 > export function isFileSystemWatcher(thing: unknown): thing is IFileSystemWatcher {
593 const candidate = thing as IFileSystemWatcher | undefined;
594
595 return !!candidate && typeof candidate.onDidChange === 'function';
596 }
597 > files.ts
598 > export const enum FileSystemProviderCapabilities {
599 >
600 > /**
601 > * No capabilities.
602 > */
603 > None = 0,
604 >
605 > /**
606 > * Provider supports unbuffered read/write.
607 > */
608 > FileReadWrite = 1 << 1,
609 >
610 > /**
611 > * Provider supports open/read/write/close low level file operations.
612 > */
613 > FileOpenReadWriteClose = 1 << 2,
614 >
615 > /**
616 > * Provider supports stream based reading.
617 > */
618 > FileReadStream = 1 << 4,
619 >
620 > /**
621 > * Provider supports copy operation.
622 > */
623 > FileFolderCopy = 1 << 3,
624 >
625 > /**
626 > * Provider is path case sensitive.
627 > */
628 > PathCaseSensitive = 1 << 10,
629 >
630 > /**
631 > * All files of the provider are readonly.
632 > */
633 > Readonly = 1 << 11,
634 >
635 > /**
636 > * Provider supports to delete via trash.
637 > */
638 > Trash = 1 << 12,
639 >
640 > /**
641 > * Provider support to unlock files for writing.
642 > */
643 > FileWriteUnlock = 1 << 13,
644 >
645 > /**
646 > * Provider support to read files atomically. This implies the
647 > * provider provides the `FileReadWrite` capability too.
648 > */
649 > FileAtomicRead = 1 << 14,
650 >
651 > /**
652 > * Provider support to write files atomically. This implies the
653 > * provider provides the `FileReadWrite` capability too.
654 > */
655 > FileAtomicWrite = 1 << 15,
656 >
657 > /**
658 > * Provider support to delete atomically.
659 > */
660 > FileAtomicDelete = 1 << 16,
661 >
662 > /**
663 > * Provider support to clone files atomically.
664 > */
665 > FileClone = 1 << 17,
666 >
667 > /**
668 > * Provider support to resolve real paths.
669 > */
670 > FileRealpath = 1 << 18,
671 >
672 > /**
673 > * Provider support to append to files.
674 > */
675 > FileAppend = 1 << 19
676 > }
677 >
678 > export interface IFileSystemProvider {
679 >
680 > readonly capabilities: FileSystemProviderCapabilities;
681 > readonly onDidChangeCapabilities: Event<void>;
682 >
683 > readonly onDidChangeFile: Event<readonly IFileChange[]>;
684 > readonly onDidWatchError?: Event<string>;
685 > watch(resource: URI, opts: IWatchOptions): IDisposable;
686 >
687 > stat(resource: URI): Promise<IStat>;
688 > mkdir(resource: URI): Promise<void>;
689 > readdir(resource: URI): Promise<[string, FileType][]>;
690 > delete(resource: URI, opts: IFileDeleteOptions): Promise<void>;
691 >
692 > rename(from: URI, to: URI, opts: IFileOverwriteOptions): Promise<void>;
693 > copy?(from: URI, to: URI, opts: IFileOverwriteOptions): Promise<void>;
694 >
695 > readFile?(resource: URI): Promise<Uint8Array>;
696 > writeFile?(resource: URI, content: Uint8Array, opts: IFileWriteOptions): Promise<void>;
697 >
698 > readFileStream?(resource: URI, opts: IFileReadStreamOptions, token: CancellationToken): ReadableStreamEvents<Uint8Array>;
699 >
700 > open?(resource: URI, opts: IFileOpenOptions): Promise<number>;
701 > close?(fd: number): Promise<void>;
702 > read?(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise<number>;
703 > write?(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise<number>;
704 >
705 > cloneFile?(from: URI, to: URI): Promise<void>;
706 > }
707 >
708 > export interface IFileSystemProviderWithFileReadWriteCapability extends IFileSystemProvider {
709 > readFile(resource: URI): Promise<Uint8Array>;
710 > writeFile(resource: URI, content: Uint8Array, opts: IFileWriteOptions): Promise<void>;
711 > }
712 >
713 > export function hasReadWriteCapability(provider: IFileSystemProvider): provider is IFileSystemProviderWithFileReadWriteCapability {
714 return !!(provider.capabilities & FileSystemProviderCapabilities.FileReadWrite);
715 }
716 > files.ts
717 > export function hasFileAppendCapability(provider: IFileSystemProvider): boolean {
718 return !!(provider.capabilities & FileSystemProviderCapabilities.FileAppend);
719 }
720 > files.ts
721 > export interface IFileSystemProviderWithFileFolderCopyCapability extends IFileSystemProvider {
722 > copy(from: URI, to: URI, opts: IFileOverwriteOptions): Promise<void>;
723 > }
724 >
725 > export function hasFileFolderCopyCapability(provider: IFileSystemProvider): provider is IFileSystemProviderWithFileFolderCopyCapability {
726 return !!(provider.capabilities & FileSystemProviderCapabilities.FileFolderCopy);
727 }
728 > files.ts
729 > export interface IFileSystemProviderWithFileCloneCapability extends IFileSystemProvider {
730 > cloneFile(from: URI, to: URI): Promise<void>;
731 > }
732 >
733 > export function hasFileCloneCapability(provider: IFileSystemProvider): provider is IFileSystemProviderWithFileCloneCapability {
734 return !!(provider.capabilities & FileSystemProviderCapabilities.FileClone);
735 }
736 > files.ts
737 > export interface IFileSystemProviderWithFileRealpathCapability extends IFileSystemProvider {
738 > realpath(resource: URI): Promise<string>;
739 > }
740 >
741 > export function hasFileRealpathCapability(provider: IFileSystemProvider): provider is IFileSystemProviderWithFileRealpathCapability {
742 return !!(provider.capabilities & FileSystemProviderCapabilities.FileRealpath);
743 }
744 > files.ts
745 > export interface IFileSystemProviderWithOpenReadWriteCloseCapability extends IFileSystemProvider {
746 > open(resource: URI, opts: IFileOpenOptions): Promise<number>;
747 > close(fd: number): Promise<void>;
748 > read(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise<number>;
749 > write(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise<number>;
750 > }
751 >
752 > export function hasOpenReadWriteCloseCapability(provider: IFileSystemProvider): provider is IFileSystemProviderWithOpenReadWriteCloseCapability {
753 return !!(provider.capabilities & FileSystemProviderCapabilities.FileOpenReadWriteClose);
754 }
755 > files.ts
756 > export interface IFileSystemProviderWithFileReadStreamCapability extends IFileSystemProvider {
757 > readFileStream(resource: URI, opts: IFileReadStreamOptions, token: CancellationToken): ReadableStreamEvents<Uint8Array>;
758 > }
759 >
760 > export function hasFileReadStreamCapability(provider: IFileSystemProvider): provider is IFileSystemProviderWithFileReadStreamCapability {
761 return !!(provider.capabilities & FileSystemProviderCapabilities.FileReadStream);
762 }
763 > files.ts
764 > export interface IFileSystemProviderWithFileAtomicReadCapability extends IFileSystemProvider {
765 > readFile(resource: URI, opts?: IFileAtomicReadOptions): Promise<Uint8Array>;
766 > enforceAtomicReadFile?(resource: URI): boolean;
767 > }
768 >
769 > export function hasFileAtomicReadCapability(provider: IFileSystemProvider): provider is IFileSystemProviderWithFileAtomicReadCapability {
770 if (!hasReadWriteCapability(provider)) {
771 return false; // we require the `FileReadWrite` capability too
774 return !!(provider.capabilities & FileSystemProviderCapabilities.FileAtomicRead);
775 }
776 > files.ts
777 > export interface IFileSystemProviderWithFileAtomicWriteCapability extends IFileSystemProvider {
778 > writeFile(resource: URI, contents: Uint8Array, opts?: IFileAtomicWriteOptions): Promise<void>;
779 > enforceAtomicWriteFile?(resource: URI): IFileAtomicOptions | false;
780 > }
781 >
782 > export function hasFileAtomicWriteCapability(provider: IFileSystemProvider): provider is IFileSystemProviderWithFileAtomicWriteCapability {
783 if (!hasReadWriteCapability(provider)) {
784 return false; // we require the `FileReadWrite` capability too
787 return !!(provider.capabilities & FileSystemProviderCapabilities.FileAtomicWrite);
788 }
789 > files.ts
790 > export interface IFileSystemProviderWithFileAtomicDeleteCapability extends IFileSystemProvider {
791 > delete(resource: URI, opts: IFileAtomicDeleteOptions): Promise<void>;
792 > enforceAtomicDelete?(resource: URI): IFileAtomicOptions | false;
793 > }
794 >
795 > export function hasFileAtomicDeleteCapability(provider: IFileSystemProvider): provider is IFileSystemProviderWithFileAtomicDeleteCapability {
796 return !!(provider.capabilities & FileSystemProviderCapabilities.FileAtomicDelete);
797 }
798 > files.ts
799 > export interface IFileSystemProviderWithReadonlyCapability extends IFileSystemProvider {
800 >
801 > readonly capabilities: FileSystemProviderCapabilities.Readonly & FileSystemProviderCapabilities;
802 >
803 > /**
804 > * An optional message to show in the UI to explain why the file system is readonly.
805 > */
806 > readonly readOnlyMessage?: IMarkdownString;
807 > }
808 >
809 > export function hasReadonlyCapability(provider: IFileSystemProvider): provider is IFileSystemProviderWithReadonlyCapability {
810 return !!(provider.capabilities & FileSystemProviderCapabilities.Readonly);
811 }
812 > files.ts
813 > export enum FileSystemProviderErrorCode {
814 > FileExists = 'EntryExists',
815 > FileNotFound = 'EntryNotFound',
816 > FileNotADirectory = 'EntryNotADirectory',
817 > FileIsADirectory = 'EntryIsADirectory',
818 > FileExceedsStorageQuota = 'EntryExceedsStorageQuota',
819 > FileTooLarge = 'EntryTooLarge',
820 > FileWriteLocked = 'EntryWriteLocked',
821 > NoPermissions = 'NoPermissions',
822 > Unavailable = 'Unavailable',
823 > Unknown = 'Unknown'
824 > }
825 >
826 > export interface IFileSystemProviderError extends Error {
827 > readonly name: string;
828 > readonly code: FileSystemProviderErrorCode;
829 > }
830 >
831 > export class FileSystemProviderError extends Error implements IFileSystemProviderError {
832 >
833 > static create(error: Error | string, code: FileSystemProviderErrorCode): FileSystemProviderError {
834 > const providerError = new FileSystemProviderError(error.toString(), code);
835 > markAsFileSystemProviderError(providerError, code);
836 >
837 > return providerError;
838 > }
839 >
840 > private constructor(message: string, readonly code: FileSystemProviderErrorCode) {
841 super(message);
842 }
843 > } files.ts
844 >
845 > export function createFileSystemProviderError(error: Error | string, code: FileSystemProviderErrorCode): FileSystemProviderError {
846 return FileSystemProviderError.create(error, code);
847 }
848 > files.ts
849 > export function ensureFileSystemProviderError(error?: Error): Error {
850 if (!error) {
851 return createFileSystemProviderError(localize('unknownError', "Unknown Error"), FileSystemProviderErrorCode.Unknown); // https://github.com/microsoft/vscode/issues/72798
854 return error;
855 }
856 > files.ts
857 > export function markAsFileSystemProviderError(error: Error, code: FileSystemProviderErrorCode): Error {
858 error.name = code ? `${code} (FileSystemError)` : `FileSystemError`;
859
860 return error;
861 }
862 > files.ts
863 > export function toFileSystemProviderErrorCode(error: Error | undefined | null): FileSystemProviderErrorCode {
864
865 // Guard against abuse
893 return FileSystemProviderErrorCode.Unknown;
894 }
895 > files.ts
896 > export function toFileOperationResult(error: Error): FileOperationResult {
897
898 // FileSystemProviderError comes with the result already
921 }
922 }
923 > files.ts
924 > export interface IFileSystemProviderRegistrationEvent {
925 > readonly added: boolean;
926 > readonly scheme: string;
927 > readonly provider?: IFileSystemProvider;
928 > }
929 >
930 > export interface IFileSystemProviderCapabilitiesChangeEvent {
931 > readonly provider: IFileSystemProvider;
932 > readonly scheme: string;
933 > }
934 >
935 > export interface IFileSystemProviderActivationEvent {
936 > readonly scheme: string;
937 > join(promise: Promise<void>): void;
938 > }
939 >
940 > export const enum FileOperation {
941 > CREATE,
942 > DELETE,
943 > MOVE,
944 > COPY,
945 > WRITE
946 > }
947 >
948 > export interface IFileOperationEvent {
949 >
950 > readonly resource: URI;
951 > readonly operation: FileOperation;
952 >
953 > isOperation(operation: FileOperation.DELETE | FileOperation.WRITE): boolean;
954 > isOperation(operation: FileOperation.CREATE | FileOperation.MOVE | FileOperation.COPY): this is IFileOperationEventWithMetadata;
955 > }
956 >
957 > export interface IFileOperationEventWithMetadata extends IFileOperationEvent {
958 > readonly target: IFileStatWithMetadata;
959 > }
960 >
961 > export class FileOperationEvent implements IFileOperationEvent {
962 >
963 > constructor(resource: URI, operation: FileOperation.DELETE | FileOperation.WRITE);
964 > constructor(resource: URI, operation: FileOperation.CREATE | FileOperation.MOVE | FileOperation.COPY, target: IFileStatWithMetadata);
965 > constructor(readonly resource: URI, readonly operation: FileOperation, readonly target?: IFileStatWithMetadata) { }
966 >
967 > isOperation(operation: FileOperation.DELETE | FileOperation.WRITE): boolean;
968 > isOperation(operation: FileOperation.CREATE | FileOperation.MOVE | FileOperation.COPY): this is IFileOperationEventWithMetadata;
969 > isOperation(operation: FileOperation): boolean {
970 return this.operation === operation;
971 }
972 > } files.ts
973 >
974 > /**
975 > * Possible changes that can occur to a file.
976 > */
977 > export const enum FileChangeType {
978 > UPDATED,
979 > ADDED,
980 > DELETED
981 > }
982 >
983 > /**
984 > * Identifies a single change in a file.
985 > */
986 > export interface IFileChange {
987 >
988 > /**
989 > * The type of change that occurred to the file.
990 > */
991 > type: FileChangeType;
992 >
993 > /**
994 > * The unified resource identifier of the file that changed.
995 > */
996 > readonly resource: URI;
997 >
998 > /**
999 > * If provided when starting the file watcher, the correlation
1000 > * identifier will match the original file watching request as
1001 > * a way to identify the original component that is interested
1002 > * in the change.
1003 > */
1004 > readonly cId?: number;
1005 > }
1006 >
1007 > export class FileChangesEvent {
1008 >
1009 > private static readonly MIXED_CORRELATION = null;
1010 >
1011 > private readonly correlationId: number | undefined | typeof FileChangesEvent.MIXED_CORRELATION = undefined;
1012 >
1013 > constructor(changes: readonly IFileChange[], private readonly ignorePathCasing: boolean) {
1014 for (const change of changes) {
1015
1043 }
1044 }
1045 > files.ts
1046 > private readonly added = new Lazy(() => {
1047 > const added = TernarySearchTree.forUris<boolean>(() => this.ignorePathCasing); files.ts
1048 > added.fill(this.rawAdded.map(resource => [resource, true]));
1049 >
1050 > return added;
1051 > }); files.ts
1052 >
1053 > private readonly updated = new Lazy(() => {
1054 > const updated = TernarySearchTree.forUris<boolean>(() => this.ignorePathCasing); files.ts
1055 > updated.fill(this.rawUpdated.map(resource => [resource, true]));
1056 >
1057 > return updated;
1058 > }); files.ts
1059 >
1060 > private readonly deleted = new Lazy(() => {
1061 > const deleted = TernarySearchTree.forUris<boolean>(() => this.ignorePathCasing); files.ts
1062 > deleted.fill(this.rawDeleted.map(resource => [resource, true]));
1063 >
1064 > return deleted;
1065 > }); files.ts
1066 >
1067 > /**
1068 > * Find out if the file change events match the provided resource.
1069 > *
1070 > * Note: when passing `FileChangeType.DELETED`, we consider a match
1071 > * also when the parent of the resource got deleted.
1072 > */
1073 > contains(resource: URI, ...types: FileChangeType[]): boolean {
1074 return this.doContains(resource, { includeChildren: false }, ...types);
1075 }
1076 > files.ts
1077 > /**
1078 > * Find out if the file change events either match the provided
1079 > * resource, or contain a child of this resource.
1080 > */
1081 > affects(resource: URI, ...types: FileChangeType[]): boolean {
1082 return this.doContains(resource, { includeChildren: true }, ...types);
1083 }
1084 > files.ts
1085 > private doContains(resource: URI, options: { includeChildren: boolean }, ...types: FileChangeType[]): boolean {
1086 if (!resource) {
1087 return false;
1125 return false;
1126 }
1127 > files.ts
1128 > /**
1129 > * Returns if this event contains added files.
1130 > */
1131 > gotAdded(): boolean {
1132 return this.rawAdded.length > 0;
1133 }
1134 > files.ts
1135 > /**
1136 > * Returns if this event contains deleted files.
1137 > */
1138 > gotDeleted(): boolean {
1139 return this.rawDeleted.length > 0;
1140 }
1141 > files.ts
1142 > /**
1143 > * Returns if this event contains updated files.
1144 > */
1145 > gotUpdated(): boolean {
1146 return this.rawUpdated.length > 0;
1147 }
1148 > files.ts
1149 > /**
1150 > * Returns if this event contains changes that correlate to the
1151 > * provided `correlationId`.
1152 > *
1153 > * File change event correlation is an advanced watch feature that
1154 > * allows to identify from which watch request the events originate
1155 > * from. This correlation allows to route events specifically
1156 > * only to the requestor and not emit them to all listeners.
1157 > */
1158 > correlates(correlationId: number): boolean {
1159 return this.correlationId === correlationId;
1160 }
1161 > files.ts
1162 > /**
1163 > * Figure out if the event contains changes that correlate to one
1164 > * correlation identifier.
1165 > *
1166 > * File change event correlation is an advanced watch feature that
1167 > * allows to identify from which watch request the events originate
1168 > * from. This correlation allows to route events specifically
1169 > * only to the requestor and not emit them to all listeners.
1170 > */
1171 > hasCorrelation(): boolean {
1172 return typeof this.correlationId === 'number';
1173 }
1174 > files.ts
1175 > /**
1176 > * @deprecated use the `contains` or `affects` method to efficiently find
1177 > * out if the event relates to a given resource. these methods ensure:
1178 > * - that there is no expensive lookup needed (by using a `TernarySearchTree`)
1179 > * - correctly handles `FileChangeType.DELETED` events
1180 > */
1181 > readonly rawAdded: URI[] = [];
1182 >
1183 > /**
1184 > * @deprecated use the `contains` or `affects` method to efficiently find
1185 > * out if the event relates to a given resource. these methods ensure:
1186 > * - that there is no expensive lookup needed (by using a `TernarySearchTree`)
1187 > * - correctly handles `FileChangeType.DELETED` events
1188 > */
1189 > readonly rawUpdated: URI[] = [];
1190 >
1191 > /**
1192 > * @deprecated use the `contains` or `affects` method to efficiently find
1193 > * out if the event relates to a given resource. these methods ensure:
1194 > * - that there is no expensive lookup needed (by using a `TernarySearchTree`)
1195 > * - correctly handles `FileChangeType.DELETED` events
1196 > */
1197 > readonly rawDeleted: URI[] = [];
1198 > }
1199 >
1200 > export function isParent(path: string, candidate: string, ignoreCase?: boolean): boolean {
1201 if (!path || !candidate || path === candidate) {
1202 return false;
1217 return path.indexOf(candidate) === 0;
1218 }
1219 > files.ts
1220 > export interface IBaseFileStat {
1221 >
1222 > /**
1223 > * The unified resource identifier of this file or folder.
1224 > */
1225 > readonly resource: URI;
1226 >
1227 > /**
1228 > * The name which is the last segment
1229 > * of the {{path}}.
1230 > */
1231 > readonly name: string;
1232 >
1233 > /**
1234 > * The size of the file.
1235 > *
1236 > * The value may or may not be resolved as
1237 > * it is optional.
1238 > */
1239 > readonly size?: number;
1240 >
1241 > /**
1242 > * The last modification date represented as millis from unix epoch.
1243 > *
1244 > * The value may or may not be resolved as
1245 > * it is optional.
1246 > */
1247 > readonly mtime?: number;
1248 >
1249 > /**
1250 > * The creation date represented as millis from unix epoch.
1251 > *
1252 > * The value may or may not be resolved as
1253 > * it is optional.
1254 > */
1255 > readonly ctime?: number;
1256 >
1257 > /**
1258 > * A unique identifier that represents the
1259 > * current state of the file or directory.
1260 > *
1261 > * The value may or may not be resolved as
1262 > * it is optional.
1263 > */
1264 > readonly etag?: string;
1265 >
1266 > /**
1267 > * File is readonly. Components like editors should not
1268 > * offer to edit the contents.
1269 > */
1270 > readonly readonly?: boolean;
1271 >
1272 > /**
1273 > * File is locked. Components like editors should offer
1274 > * to edit the contents and ask the user upon saving to
1275 > * remove the lock.
1276 > */
1277 > readonly locked?: boolean;
1278 >
1279 > /**
1280 > * File is executable. Relevant for Unix-like systems where
1281 > * the executable bit determines if a file can be run.
1282 > */
1283 > readonly executable?: boolean;
1284 > }
1285 >
1286 > export interface IBaseFileStatWithMetadata extends Required<IBaseFileStat> { }
1287 >
1288 > /**
1289 > * A file resource with meta information and resolved children if any.
1290 > */
1291 > export interface IFileStat extends IBaseFileStat {
1292 >
1293 > /**
1294 > * The resource is a file.
1295 > */
1296 > readonly isFile: boolean;
1297 >
1298 > /**
1299 > * The resource is a directory.
1300 > */
1301 > readonly isDirectory: boolean;
1302 >
1303 > /**
1304 > * The resource is a symbolic link. Note: even when the
1305 > * file is a symbolic link, you can test for `FileType.File`
1306 > * and `FileType.Directory` to know the type of the target
1307 > * the link points to.
1308 > */
1309 > readonly isSymbolicLink: boolean;
1310 >
1311 > /**
1312 > * The children of the file stat or undefined if none.
1313 > */
1314 > children: IFileStat[] | undefined;
1315 > }
1316 >
1317 > export interface IFileStatWithMetadata extends IFileStat, IBaseFileStatWithMetadata {
1318 > readonly mtime: number;
1319 > readonly ctime: number;
1320 > readonly etag: string;
1321 > readonly size: number;
1322 > readonly readonly: boolean;
1323 > readonly locked: boolean;
1324 > readonly executable: boolean;
1325 > readonly children: IFileStatWithMetadata[] | undefined;
1326 > }
1327 >
1328 > export interface IFileStatResult {
1329 > readonly stat?: IFileStat;
1330 > readonly success: boolean;
1331 > }
1332 >
1333 > export interface IFileStatResultWithMetadata extends IFileStatResult {
1334 > readonly stat?: IFileStatWithMetadata;
1335 > }
1336 >
1337 > export interface IFileStatWithPartialMetadata extends Omit<IFileStatWithMetadata, 'children'> { }
1338 >
1339 > export interface IFileContent extends IBaseFileStatWithMetadata {
1340 >
1341 > /**
1342 > * The content of a file as buffer.
1343 > */
1344 > readonly value: VSBuffer;
1345 > }
1346 >
1347 > export interface IFileStreamContent extends IBaseFileStatWithMetadata {
1348 >
1349 > /**
1350 > * The content of a file as stream.
1351 > */
1352 > readonly value: VSBufferReadableStream;
1353 > }
1354 >
1355 > export interface IBaseReadFileOptions extends IFileReadStreamOptions {
1356 >
1357 > /**
1358 > * The optional etag parameter allows to return early from resolving the resource if
1359 > * the contents on disk match the etag. This prevents accumulated reading of resources
1360 > * that have been read already with the same etag.
1361 > * It is the task of the caller to makes sure to handle this error case from the promise.
1362 > */
1363 > readonly etag?: string;
1364 > }
1365 >
1366 > export interface IReadFileStreamOptions extends IBaseReadFileOptions { }
1367 >
1368 > export interface IReadFileOptions extends IBaseReadFileOptions {
1369 >
1370 > /**
1371 > * The optional `atomic` flag can be used to make sure
1372 > * the `readFile` method is not running in parallel with
1373 > * any `write` operations in the same process.
1374 > *
1375 > * Typically you should not need to use this flag but if
1376 > * for example you are quickly reading a file right after
1377 > * a file event occurred and the file changes a lot, there
1378 > * is a chance that a read returns an empty or partial file
1379 > * because a pending write has not finished yet.
1380 > *
1381 > * Note: this does not prevent the file from being written
1382 > * to from a different process. If you need such atomic
1383 > * operations, you better use a real database as storage.
1384 > */
1385 > readonly atomic?: boolean;
1386 > }
1387 >
1388 > export interface IWriteFileOptions {
1389 >
1390 > /**
1391 > * The last known modification time of the file. This can be used to prevent dirty writes.
1392 > */
1393 > readonly mtime?: number;
1394 >
1395 > /**
1396 > * The etag of the file. This can be used to prevent dirty writes.
1397 > */
1398 > readonly etag?: string;
1399 >
1400 > /**
1401 > * Whether to attempt to unlock a file before writing.
1402 > */
1403 > readonly unlock?: boolean;
1404 >
1405 > /**
1406 > * The optional `atomic` flag can be used to make sure
1407 > * the `writeFile` method updates the target file atomically
1408 > * by first writing to a temporary file in the same folder
1409 > * and then renaming it over the target.
1410 > */
1411 > readonly atomic?: IFileAtomicOptions | false;
1412 >
1413 > /**
1414 > * If set to true, will append to the end of the file instead of
1415 > * replacing its contents. Will create the file if it doesn't exist.
1416 > */
1417 > readonly append?: boolean;
1418 > }
1419 >
1420 > export interface IResolveFileOptions {
1421 >
1422 > /**
1423 > * Automatically continue resolving children of a directory until the provided resources
1424 > * are found.
1425 > */
1426 > readonly resolveTo?: readonly URI[];
1427 >
1428 > /**
1429 > * Automatically continue resolving children of a directory if the number of children is 1.
1430 > */
1431 > readonly resolveSingleChildDescendants?: boolean;
1432 >
1433 > /**
1434 > * Will resolve mtime, ctime, size and etag of files if enabled. This can have a negative impact
1435 > * on performance and thus should only be used when these values are required.
1436 > */
1437 > readonly resolveMetadata?: boolean;
1438 > }
1439 >
1440 > export interface IResolveMetadataFileOptions extends IResolveFileOptions {
1441 > readonly resolveMetadata: true;
1442 > }
1443 >
1444 > export interface ICreateFileOptions {
1445 >
1446 > /**
1447 > * Overwrite the file to create if it already exists on disk. Otherwise
1448 > * an error will be thrown (FILE_MODIFIED_SINCE).
1449 > */
1450 > readonly overwrite?: boolean;
1451 > }
1452 >
1453 > export class FileOperationError extends Error {
1454 > constructor(
1455 message: string,
1456 readonly fileOperationResult: FileOperationResult,
1459 super(message);
1460 }
1461 > } files.ts
1462 >
1463 > export class TooLargeFileOperationError extends FileOperationError {
1464 > constructor(
1465 message: string,
1466 override readonly fileOperationResult: FileOperationResult.FILE_TOO_LARGE,
1470 super(message, fileOperationResult, options);
1471 }
1472 > } files.ts
1473 >
1474 > export class NotModifiedSinceFileOperationError extends FileOperationError {
1475 >
1476 > constructor(
1477 message: string,
1478 readonly stat: IFileStatWithMetadata,
1481 super(message, FileOperationResult.FILE_NOT_MODIFIED_SINCE, options);
1482 }
1483 > } files.ts
1484 >
1485 > export const enum FileOperationResult {
1486 > FILE_IS_DIRECTORY,
1487 > FILE_NOT_FOUND,
1488 > FILE_NOT_MODIFIED_SINCE,
1489 > FILE_MODIFIED_SINCE,
1490 > FILE_MOVE_CONFLICT,
1491 > FILE_WRITE_LOCKED,
1492 > FILE_PERMISSION_DENIED,
1493 > FILE_TOO_LARGE,
1494 > FILE_INVALID_PATH,
1495 > FILE_NOT_DIRECTORY,
1496 > FILE_OTHER_ERROR
1497 > }
1498 >
1499 > //#endregion
1500 >
1501 > //#region Settings
1502 >
1503 > export const AutoSaveConfiguration = {
1504 > OFF: 'off',
1505 > AFTER_DELAY: 'afterDelay',
1506 > ON_FOCUS_CHANGE: 'onFocusChange',
1507 > ON_WINDOW_CHANGE: 'onWindowChange'
1508 > };
1509 >
1510 > export const HotExitConfiguration = {
1511 > OFF: 'off',
1512 > ON_EXIT: 'onExit',
1513 > ON_EXIT_AND_WINDOW_CLOSE: 'onExitAndWindowClose'
1514 > };
1515 >
1516 > export const FILES_ASSOCIATIONS_CONFIG = 'files.associations';
1517 > export const FILES_EXCLUDE_CONFIG = 'files.exclude';
1518 > export const FILES_READONLY_INCLUDE_CONFIG = 'files.readonlyInclude';
1519 > export const FILES_READONLY_EXCLUDE_CONFIG = 'files.readonlyExclude';
1520 > export const FILES_READONLY_FROM_PERMISSIONS_CONFIG = 'files.readonlyFromPermissions';
1521 >
1522 > export interface IGlobPatterns {
1523 > [filepattern: string]: boolean;
1524 > }
1525 >
1526 > export interface IFilesConfiguration {
1527 > files?: IFilesConfigurationNode;
1528 > }
1529 >
1530 > export interface IFilesConfigurationNode {
1531 > associations: { [filepattern: string]: string };
1532 > exclude: IExpression;
1533 > watcherExclude: IGlobPatterns;
1534 > watcherInclude: string[];
1535 > encoding: string;
1536 > autoGuessEncoding: boolean;
1537 > candidateGuessEncodings: string[];
1538 > defaultLanguage: string;
1539 > trimTrailingWhitespace: boolean;
1540 > autoSave: string;
1541 > autoSaveDelay: number;
1542 > autoSaveWorkspaceFilesOnly: boolean;
1543 > autoSaveWhenNoErrors: boolean;
1544 > eol: string;
1545 > enableTrash: boolean;
1546 > hotExit: string;
1547 > saveConflictResolution: 'askUser' | 'overwriteFileOnDisk';
1548 > readonlyInclude: IGlobPatterns;
1549 > readonlyExclude: IGlobPatterns;
1550 > readonlyFromPermissions: boolean;
1551 > }
1552 >
1553 > //#endregion
1554 >
1555 > //#region Utilities
1556 >
1557 > export enum FileKind {
1558 > FILE,
1559 > FOLDER,
1560 > ROOT_FOLDER
1561 > }
1562 >
1563 > /**
1564 > * A hint to disable etag checking for reading/writing.
1565 > */
1566 > export const ETAG_DISABLED = '';
1567 >
1568 > export function etag(stat: { mtime: number; size: number }): string;
1569 > export function etag(stat: { mtime: number | undefined; size: number | undefined }): string | undefined;
1570 > export function etag(stat: { mtime: number | undefined; size: number | undefined }): string | undefined {
1571 if (typeof stat.size !== 'number' || typeof stat.mtime !== 'number') {
1572 return undefined;
1575 return stat.mtime.toString(29) + stat.size.toString(31);
1576 }
1577 > files.ts
1578 export async function whenProviderRegistered(file: URI, fileService: IFileService): Promise<void> {
1579 if (fileService.hasProvider(URI.from({ scheme: file.scheme }))) {
1590 });
1591 }
1592 > files.ts
1593 > /**
1594 > * Helper to format a raw byte size into a human readable label.
1595 > */
1596 > export class ByteSize {
1597 >
1598 > static readonly KB = 1024;
1599 > static readonly MB = ByteSize.KB * ByteSize.KB;
1600 > static readonly GB = ByteSize.MB * ByteSize.KB;
1601 > static readonly TB = ByteSize.GB * ByteSize.KB;
1602 >
1603 > static formatSize(size: number): string {
1604 if (!isNumber(size)) {
1605 size = 0;
1624 return localize('sizeTB', "{0}TB", (size / ByteSize.TB).toFixed(2));
1625 }
1626 > } files.ts
1627 >
1628 > // File limits
1629 >
1630 > export function getLargeFileConfirmationLimit(remoteAuthority?: string): number;
1631 > export function getLargeFileConfirmationLimit(uri?: URI): number;
1632 > export function getLargeFileConfirmationLimit(arg?: string | URI): number {
1633 const isRemote = typeof arg === 'string' || arg?.scheme === Schemas.vscodeRemote;
1634 const isLocal = typeof arg !== 'string' && arg?.scheme === Schemas.file;
1655 return 1024 * ByteSize.MB;
1656 }
1657 > files.ts
1658 > //#endregion
src/vs/platform/agentHost/common/state/protocol/channels-session/state.ts 1351 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- state.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > // allow-any-unicode-comment-file
7 > // DO NOT EDIT -- auto-generated by scripts/sync-agent-host-protocol.ts
8 >
9 > import type { Changeset } from '../channels-changeset/state.js';
10 > import type { AnnotationsSummary } from '../channels-annotations/state.js';
11 > import type { ChatSummary, ChatInputRequest, ToolCallConfirmationState, ToolCallState, ToolCallAuthRequiredState } from '../channels-chat/state.js';
12 > import type { ConfigPropertySchema, ErrorInfo, Icon, ProtectedResourceMetadata, TextRange, URI } from '../common/state.js';
13 >
14 > // ─── Session State ───────────────────────────────────────────────────────────
15 >
16 > /**
17 > * Session initialization state.
18 > *
19 > * @category Session State
20 > */
21 > export const enum SessionLifecycle {
22 > Creating = 'creating',
23 > Ready = 'ready',
24 > CreationFailed = 'creationFailed',
25 > }
26 >
27 > /**
28 > * Bitset of summary-level session status flags.
29 > *
30 > * Use bitwise checks instead of equality for non-terminal activity. For example,
31 > * `status & SessionStatus.InProgress` matches both ordinary in-progress turns
32 > * and turns that are paused waiting for input.
33 > *
34 > * @category Session State
35 > */
36 > export const enum SessionStatus {
37 > /** Session is idle — no turn is active. */
38 > Idle = 1,
39 > /** Session ended with an error. */
40 > Error = 1 << 1,
41 > /** A turn is actively streaming. */
42 > InProgress = 1 << 3,
43 > /** A turn is in progress but blocked waiting for user input or tool confirmation. */
44 > InputNeeded = (1 << 3) | (1 << 4),
45 > /** The client has viewed this session since its last modification. */
46 > IsRead = 1 << 5,
47 > /** The session has been archived by the client. */
48 > IsArchived = 1 << 6,
49 > }
50 >
51 > /**
52 > * Metadata shared between the full {@link SessionState} (delivered when a
53 > * client subscribes to a session's URI) and the lightweight
54 > * {@link SessionSummary} (carried in the root-channel session catalog).
55 > *
56 > * These fields describe the session at a glance and appear in both places.
57 > * `SessionState` owns the authoritative values for a subscribed session;
58 > * `SessionSummary` mirrors them into the catalog so clients that only render a
59 > * session list don't have to subscribe to every session URI. The host keeps
60 > * the catalog in sync via `root/sessionSummaryChanged`.
61 > *
62 > * @category Session State
63 > */
64 > export interface SessionMetadata {
65 > /** Agent provider ID */
66 > provider: string;
67 > /** Session title */
68 > title: string;
69 > /** Current session status */
70 > status: SessionStatus;
71 > /** Human-readable description of what the session is currently doing */
72 > activity?: string;
73 > /** Server-owned project for this session */
74 > project?: ProjectInfo;
75 > /**
76 > * The working directories the session's agent has tool access to, as
77 > * maintained by the `session/workingDirectorySet` /
78 > * `session/workingDirectoryRemoved` actions. Directories are **equal peers** —
79 > * the session has no primary. Individual chats MAY restrict to a subset via
80 > * {@link ChatSummary.workingDirectories | their own `workingDirectories`} and
81 > * designate one of their own directories as primary (see
82 > * {@link ChatState.primaryWorkingDirectory}); a chat that sets no subset
83 > * operates against this full set.
84 > */
85 > workingDirectories?: URI[];
86 > /**
87 > * Lightweight summary of this session's inline annotations channel
88 > * (`ahp-session:/<uuid>/annotations`). Surfaced so badge UI can render
89 > * annotation / entry counts without subscribing. Absent when the session
90 > * does not expose an annotations channel.
91 > */
92 > annotations?: AnnotationsSummary;
93 > }
94 >
95 > /**
96 > * Full state for a single session, loaded when a client subscribes to the session's URI.
97 > *
98 > * Inlines (denormalizes) every {@link SessionMetadata} field directly onto
99 > * itself so subscribers receive one flat object instead of a nested summary.
100 > * The lightweight catalog representation is {@link SessionSummary}, surfaced on
101 > * the root channel; the host keeps the two in sync via
102 > * `root/sessionSummaryChanged`.
103 > *
104 > * @category Session State
105 > */
106 > export interface SessionState extends SessionMetadata {
107 > /** Session initialization state */
108 > lifecycle: SessionLifecycle;
109 > /** Error details if creation failed */
110 > creationError?: ErrorInfo;
111 > /** Tools provided by the server (agent host) for this session */
112 > serverTools?: ToolDefinition[];
113 > /**
114 > * The clients currently providing tools and interactive capabilities to this
115 > * session. If multiple tools or customizations are provided by the same
116 > * active client, an agent host MAY deduplicate them when exposed to a model,
117 > * with a preference given to the client that started the turn.
118 > *
119 > * Membership is host-managed: clients add (or refresh) themselves with
120 > * `session/activeClientSet`, and the host removes them with
121 > * `session/activeClientRemoved` when they unsubscribe, disconnect without
122 > * reconnecting in time, or reconnect without resubscribing to the session.
123 > */
124 > activeClients: SessionActiveClient[];
125 > /** Catalog of chats in this session. */
126 > chats: ChatSummary[];
127 > /**
128 > * The chat that receives input when the user addresses the session without
129 > * selecting a specific chat. This is a UI routing hint, not a hierarchy
130 > * marker — chats remain equal peers at the protocol level. Hosts MAY change
131 > * this over the session's lifetime.
132 > */
133 > defaultChat?: URI;
134 > /** Session configuration schema and current values */
135 > config?: SessionConfigState;
136 > /**
137 > * Top-level customizations active in this session.
138 > *
139 > * Always one of the {@link Customization} variants:
140 > *
141 > * - Container customizations ({@link PluginCustomization},
142 > * {@link DirectoryCustomization}) whose children — agents, skills,
143 > * prompts, rules, hooks, MCP servers — live in each container's
144 > * {@link ContainerCustomizationBase.children | `children`} array.
145 > * - Top-level {@link McpServerCustomization} entries the host
146 > * surfaces directly (for example a globally-configured MCP server
147 > * that isn't bundled in a plugin or directory). MCP servers may
148 > * also appear as children of a container.
149 > *
150 > * Client-published plugins arrive via
151 > * {@link SessionActiveClient.customizations | `activeClients[].customizations`}
152 > * and the host propagates them into this list (typically with the
153 > * container's `clientId` set and `children` populated). Clients
154 > * publish in container shape only; bare MCP servers at the top level
155 > * are server-originated.
156 > */
157 > customizations?: Customization[];
158 > /**
159 > * Catalogue of changesets the server can produce for this session. Each
160 > * entry advertises a subscribable view of file changes (uncommitted,
161 > * session-wide, per-turn, etc.) and the URI template the client expands
162 > * before subscribing. See {@link Changeset} for the full shape and
163 > * {@link /guide/changesets | Changesets} for an overview of the model.
164 > */
165 > changesets?: Changeset[];
166 > /**
167 > * Outstanding input the session is blocked on, aggregated across every chat
168 > * so a client can discover and answer it from the session channel alone,
169 > * without subscribing to individual chats.
170 > *
171 > * Each entry is self-sufficient: it carries the owning chat's URI plus every
172 > * identifier the client needs to respond. A client answers by dispatching the
173 > * ordinary `chat/*` action to that chat's channel — see
174 > * {@link SessionInputRequest} for the per-variant response path. A present,
175 > * non-empty list implies {@link SessionStatus.InputNeeded} on
176 > * {@link SessionSummary.status}.
177 > *
178 > * Host-managed: the host upserts entries with `session/inputNeededSet` as
179 > * chats raise requests and removes them with `session/inputNeededRemoved`
180 > * once the underlying request resolves.
181 > */
182 > inputNeeded?: SessionInputRequest[];
183 > /**
184 > * Additional provider-specific metadata for this session.
185 > *
186 > * Clients MAY look for well-known keys here to provide enhanced UI.
187 > * For example, a `git` key may provide extra git metadata about the session's
188 > * working directories.
189 > */
190 > _meta?: Record<string, unknown>;
191 > }
192 >
193 > /**
194 > * A client currently providing tools and interactive capabilities to a session.
195 > *
196 > * A session MAY have several active clients at once; entries in
197 > * {@link SessionState.activeClients} are keyed by `clientId`. The server SHOULD
198 > * automatically remove an active client when that client disconnects.
199 > *
200 > * @category Session State
201 > */
202 > export interface SessionActiveClient {
203 > /** Client identifier (matches `clientId` from `initialize`) */
204 > clientId: string;
205 > /** Human-readable client name (e.g. `"VS Code"`) */
206 > displayName?: string;
207 > /** Tools this client provides to the session */
208 > tools: ToolDefinition[];
209 > /**
210 > * Plugin customizations this client contributes to the session.
211 > *
212 > * Clients publish in [Open Plugins](https://open-plugins.com/) format
213 > * — i.e. always container-shaped plugins. They MAY synthesize virtual
214 > * plugins in memory and rely on the host to expand them into concrete
215 > * children inside {@link SessionState.customizations}.
216 > */
217 > customizations?: ClientPluginCustomization[];
218 > }
219 >
220 > // ─── Session Input Requests ──────────────────────────────────────────────────
221 >
222 > /**
223 > * Discriminant for the kinds of outstanding input a session can surface in
224 > * {@link SessionState.inputNeeded}.
225 > *
226 > * This is a general/typological union (not a lifecycle), so the discriminant is
227 > * a `*Kind`.
228 > *
229 > * @category Session Input Types
230 > */
231 > export const enum SessionInputRequestKind {
232 > /** A user-facing elicitation mirrored from an unresolved chat response part. */
233 > ChatInput = 'chatInput',
234 > /** A tool call awaiting parameter- or result-confirmation. */
235 > ToolConfirmation = 'toolConfirmation',
236 > /** A running tool the session wants an active client to execute. */
237 > ToolClientExecution = 'toolClientExecution',
238 > /** A tool call blocked on MCP authentication mid-execution. */
239 > ToolAuthentication = 'toolAuthentication',
240 > }
241 >
242 > /**
243 > * Fields common to every {@link SessionInputRequest} variant.
244 > *
245 > * @category Session Input Types
246 > */
247 > interface SessionInputRequestBase {
248 > /**
249 > * Stable key for this entry, unique within the session's
250 > * {@link SessionState.inputNeeded} list. The host derives it however it likes
251 > * (for example from the chat URI plus the underlying request or tool-call
252 > * id); consumers MUST treat it as opaque. It is the key for the
253 > * `session/inputNeededSet` / `session/inputNeededRemoved` upsert convention.
254 > */
255 > id: string;
256 > /**
257 > * The chat the underlying request lives in. This is the channel a client
258 > * dispatches its response to — it does not need to have subscribed to that
259 > * chat first.
260 > */
261 > chat: URI;
262 > }
263 >
264 > /**
265 > * A user-input elicitation surfaced at the session level, mirroring the request
266 > * from an unresolved {@link InputRequestResponsePart} in the owning chat.
267 > *
268 > * Respond by dispatching `chat/inputCompleted` (or syncing drafts with
269 > * `chat/inputAnswerChanged`) to {@link SessionInputRequestBase.chat | `chat`},
270 > * keyed by {@link ChatInputRequest.id | `request.id`}.
271 > *
272 > * @category Session Input Types
273 > */
274 > export interface SessionChatInputRequest extends SessionInputRequestBase {
275 > kind: SessionInputRequestKind.ChatInput;
276 > /** The mirrored chat input request. */
277 > request: ChatInputRequest;
278 > }
279 >
280 > /**
281 > * A tool call blocked on confirmation — either parameter confirmation before
282 > * execution or result confirmation after — surfaced at the session level.
283 > *
284 > * Respond by dispatching `chat/toolCallConfirmed` (for
285 > * {@link ToolCallPendingConfirmationState}) or `chat/toolCallResultConfirmed`
286 > * (for {@link ToolCallPendingResultConfirmationState}) to
287 > * {@link SessionInputRequestBase.chat | `chat`}, keyed by `turnId` and
288 > * `toolCall.toolCallId`.
289 > *
290 > * @category Session Input Types
291 > */
292 > export interface SessionToolConfirmationRequest extends SessionInputRequestBase {
293 > kind: SessionInputRequestKind.ToolConfirmation;
294 > /** The turn the tool call belongs to. */
295 > turnId: string;
296 > /** The tool call awaiting confirmation. */
297 > toolCall: ToolCallConfirmationState;
298 > }
299 >
300 > /**
301 > * A running tool whose execution is delegated to an active client. Surfaced so
302 > * a client that provides the tool can pick up the work without subscribing to
303 > * the owning chat.
304 > *
305 > * The {@link toolCall} is always a {@link ToolCallRunningState} (a
306 > * {@link ToolCallState} in `running` status) whose
307 > * {@link ToolCallRunningState.contributor | `contributor`} is a client
308 > * {@link ToolCallClientContributor} whose `clientId` matches the denormalized
309 > * {@link clientId} here. Execute and report the result by dispatching
310 > * `chat/toolCallComplete` (and optionally streaming with
311 > * `chat/toolCallContentChanged`) to {@link SessionInputRequestBase.chat |
312 > * `chat`}, keyed by `turnId` and `toolCall.toolCallId`.
313 > *
314 > * @category Session Input Types
315 > */
316 > export interface SessionToolClientExecutionRequest extends SessionInputRequestBase {
317 > kind: SessionInputRequestKind.ToolClientExecution;
318 > /** The turn the tool call belongs to. */
319 > turnId: string;
320 > /**
321 > * The `clientId` expected to execute the tool. Matches the `clientId` of the
322 > * tool call's client {@link ToolCallContributor}.
323 > */
324 > clientId: string;
325 > /**
326 > * The running tool call the session wants the owning client to execute. The
327 > * host only ever populates this with a {@link ToolCallRunningState} (i.e. a
328 > * {@link ToolCallState} in `running` status).
329 > */
330 > toolCall: ToolCallState;
331 > }
332 >
333 > /**
334 > * A tool call blocked on MCP authentication mid-execution, surfaced at the
335 > * session level.
336 > *
337 > * The {@link toolCall} is always a {@link ToolCallAuthRequiredState} (a
338 > * {@link ToolCallState} in `auth-required` status). Unlike
339 > * {@link SessionToolConfirmationRequest}, this is **not** answered by
340 > * dispatching a `chat/*` action directly: the client obtains a token for
341 > * {@link ToolCallAuthRequiredState.auth | `toolCall.auth`}`.resource` and
342 > * pushes it via the existing `authenticate` command (see
343 > * {@link /specification/authentication | Authentication}). The host resumes
344 > * the tool call and dispatches `chat/toolCallAuthResolved` once the token is
345 > * accepted, at which point it also removes this entry with
346 > * `session/inputNeededRemoved`.
347 > *
348 > * @category Session Input Types
349 > */
350 > export interface SessionToolAuthenticationRequest extends SessionInputRequestBase {
351 > kind: SessionInputRequestKind.ToolAuthentication;
352 > /** The turn the tool call belongs to. */
353 > turnId: string;
354 > /** The tool call awaiting authentication. */
355 > toolCall: ToolCallAuthRequiredState;
356 > }
357 >
358 > /**
359 > * One outstanding piece of input a session is blocked on, aggregated across all
360 > * chats in {@link SessionState.inputNeeded}.
361 > *
362 > * Each entry is self-sufficient: it carries the owning
363 > * {@link SessionInputRequestBase.chat | `chat`} URI plus every identifier needed
364 > * to construct the response, so a client can answer by dispatching the ordinary
365 > * `chat/*` action (`chat/inputCompleted`, `chat/toolCallConfirmed`,
366 > * `chat/toolCallComplete`, …) to that chat's channel **without having subscribed
367 > * to the chat** — except {@link SessionToolAuthenticationRequest}, which is
368 > * resolved via the `authenticate` command instead. The host removes the entry
369 > * with `session/inputNeededRemoved` once the underlying request resolves.
370 > *
371 > * @category Session Input Types
372 > */
373 > export type SessionInputRequest =
374 > | SessionChatInputRequest
375 > | SessionToolConfirmationRequest
376 > | SessionToolClientExecutionRequest
377 > | SessionToolAuthenticationRequest;
378 >
379 > /**
380 > * Server-owned project metadata for a session.
381 > *
382 > * @category Session State
383 > */
384 > export interface ProjectInfo {
385 > /** Project URI */
386 > uri: URI;
387 > /** Human-readable project name */
388 > displayName: string;
389 > }
390 >
391 > /**
392 > * Lightweight catalog entry summarizing one session. Surfaced via
393 > * {@link RootChannelCommands.listSessions | `root/listSessions`} and
394 > * `root/sessionAdded`/`root/sessionSummaryChanged` notifications.
395 > *
396 > * **Aggregation across chats.** Once a session contains more than one chat,
397 > * several `SessionSummary` fields are derived from the underlying
398 > * {@link SessionState.chats | chat catalog}. Producers SHOULD follow these
399 > * rules so clients that only consume the session summary (e.g. a session
400 > * list) still see meaningful state:
401 > *
402 > * - `status`: take the activity bits (`Idle` / `InProgress` / `InputNeeded` /
403 > * `Error` — bits 0–4) from the
404 > * {@link SessionState.defaultChat | default chat} when present, else from
405 > * the most recently modified chat. **Promote** `InputNeeded` whenever any
406 > * chat in the session needs input, and **promote** `Error` whenever any
407 > * chat is in an error state — both override the default-chat bits. The
408 > * orthogonal flag bits (`IsRead`, `IsArchived`) remain session-scoped.
409 > * - `activity`: mirror the activity string of the default chat, or of the
410 > * chat currently driving the promoted status bits when a non-default chat
411 > * wins (e.g. the chat that raised `InputNeeded`).
412 > * - `modifiedAt`: the max of all chats' `modifiedAt`.
413 > * - `workingDirectories`: the session-level set. Individual chats MAY restrict
414 > * to a subset via {@link ChatSummary.workingDirectories}; aggregating these
415 > * up is meaningless and SHOULD NOT be attempted.
416 > * - `changes`: optional roll-up across all chats. Producers MAY sum the
417 > * per-chat changeset stats or report the most expensive chat's stats —
418 > * whichever is cheaper for the host to compute.
419 > *
420 > * Sessions with a single chat trivially satisfy all of the above (the chat's
421 > * values pass through unchanged). The rules only matter once a session
422 > * carries multiple chats.
423 > *
424 > * @category Session State
425 > */
426 > export interface SessionSummary extends SessionMetadata {
427 > /** Session URI */
428 > resource: URI;
429 > /** Creation timestamp (ISO 8601, e.g. `"2025-03-10T18:42:03.123Z"`) */
430 > createdAt: string;
431 > /** Last modification timestamp (ISO 8601, e.g. `"2025-03-10T18:42:03.123Z"`) */
432 > modifiedAt: string;
433 > /**
434 > * Aggregate summary of file changes associated with this session. Servers
435 > * may populate this to give clients a quick at-a-glance view of the
436 > * session's footprint (e.g., for list rendering) without requiring the
437 > * client to subscribe to a changeset.
438 > */
439 > changes?: ChangesSummary;
440 > /**
441 > * Lightweight server-defined metadata clients may use for the session
442 > * presentation. The protocol does not interpret these values; producers
443 > * SHOULD keep the payload small because summaries appear in session lists
444 > * and session notifications.
445 > */
446 > _meta?: Record<string, unknown>;
447 > }
448 >
449 > /**
450 > * Aggregate counts describing the file changes associated with a session.
451 > *
452 > * All fields are optional so servers can populate only the metrics they
453 > * cheaply have available.
454 > *
455 > * @category Session State
456 > */
457 > export interface ChangesSummary {
458 > /** Total number of inserted lines across all changed files. */
459 > additions?: number;
460 > /** Total number of deleted lines across all changed files. */
461 > deletions?: number;
462 > /** Number of files that have changes. */
463 > files?: number;
464 > }
465 >
466 > // ─── Agent Selection ─────────────────────────────────────────────────────────
467 >
468 > /**
469 > * A selected custom agent for a session.
470 > *
471 > * The `uri` identifies a specific custom agent (matching an
472 > * {@link AgentCustomization.uri | `AgentCustomization.uri`} exposed via
473 > * the session's effective customizations). Consumers resolve the agent's
474 > * display name by looking up `uri` in the session's customization tree.
475 > *
476 > * A message with no `agent` selected uses the provider's default behavior.
477 > *
478 > * @category Session State
479 > */
480 > export interface AgentSelection {
481 > /** Stable agent URI (matches an {@link AgentCustomization.uri}). */
482 > uri: URI;
483 > }
484 >
485 > // ─── Session Config Types ────────────────────────────────────────────────────
486 >
487 > /**
488 > * A session configuration property descriptor.
489 > *
490 > * Extends the generic {@link ConfigPropertySchema} with session-specific
491 > * display extensions.
492 > *
493 > * @category Session Config Types
494 > */
495 > export interface SessionConfigPropertySchema extends ConfigPropertySchema {
496 > /**
497 > * Display extension: when `true`, the full set of allowed values is too large
498 > * to enumerate statically. The client SHOULD use `sessionConfigCompletions`
499 > * to fetch matching values based on user input. Any values in `enum` are
500 > * seed/recent values for initial display.
501 > */
502 > enumDynamic?: boolean;
503 > /** When `true`, the user may change this property after session creation */
504 > sessionMutable?: boolean;
505 > }
506 >
507 > /**
508 > * A JSON Schema object describing available session configuration metadata.
509 > *
510 > * @category Session Config Types
511 > */
512 > export interface SessionConfigSchema {
513 > /** JSON Schema: always `'object'` */
514 > type: 'object';
515 > /** JSON Schema: property descriptors keyed by property id */
516 > properties: Record<string, SessionConfigPropertySchema>;
517 > /** JSON Schema: list of required property ids */
518 > required?: string[];
519 > }
520 >
521 > /**
522 > * Live session configuration metadata.
523 > *
524 > * The schema describes the available configuration properties and the values
525 > * contain the current value for each resolved property.
526 > *
527 > * @category Session Config Types
528 > */
529 > export interface SessionConfigState {
530 > /** JSON Schema describing available configuration properties */
531 > schema: SessionConfigSchema;
532 > /** Current configuration values */
533 > values: Record<string, unknown>;
534 > }
535 >
536 > // ─── Tool Definition Types ───────────────────────────────────────────────────
537 >
538 > /**
539 > * Describes a tool available in a session, provided by either the server or the active client.
540 > *
541 > * @category Tool Definition Types
542 > */
543 > export interface ToolDefinition {
544 > /** Unique tool identifier */
545 > name: string;
546 > /** Human-readable display name */
547 > title?: string;
548 > /** Description of what the tool does */
549 > description?: string;
550 > /**
551 > * JSON Schema defining the expected input parameters.
552 > *
553 > * Optional because client-provided tools may not have formal schemas.
554 > * Mirrors MCP `Tool.inputSchema`.
555 > */
556 > inputSchema?: {
557 > type: 'object';
558 > properties?: Record<string, object>;
559 > required?: string[];
560 > };
561 > /**
562 > * JSON Schema defining the structure of the tool's output.
563 > *
564 > * Mirrors MCP `Tool.outputSchema`.
565 > */
566 > outputSchema?: {
567 > type: 'object';
568 > properties?: Record<string, object>;
569 > required?: string[];
570 > };
571 > /** Behavioral hints about the tool. All properties are advisory. */
572 > annotations?: ToolAnnotations;
573 > /**
574 > * Additional provider-specific metadata.
575 > *
576 > * Mirrors the MCP `_meta` convention.
577 > */
578 > _meta?: Record<string, unknown>;
579 > }
580 >
581 > /**
582 > * Behavioral hints about a tool. All properties are advisory and not
583 > * guaranteed to faithfully describe tool behavior.
584 > *
585 > * Mirrors MCP `ToolAnnotations` from the Model Context Protocol specification.
586 > *
587 > * @category Tool Definition Types
588 > */
589 > export interface ToolAnnotations {
590 > /** Alternate human-readable title */
591 > title?: string;
592 > /** Tool does not modify its environment (default: false) */
593 > readOnlyHint?: boolean;
594 > /** Tool may perform destructive updates (default: true) */
595 > destructiveHint?: boolean;
596 > /** Repeated calls with the same arguments have no additional effect (default: false) */
597 > idempotentHint?: boolean;
598 > /** Tool may interact with external entities (default: true) */
599 > openWorldHint?: boolean;
600 > }
601 >
602 > // ─── Customization Types ─────────────────────────────────────────────────────
603 >
604 > /**
605 > * Discriminant for the kind of customization.
606 > *
607 > * Top-level entries in {@link SessionState.customizations} and
608 > * {@link AgentInfo.customizations} are either container customizations
609 > * ({@link CustomizationType.Plugin | `Plugin`} or
610 > * {@link CustomizationType.Directory | `Directory`}) or
611 > * {@link CustomizationType.McpServer | `McpServer`} entries surfaced
612 > * directly by the host. The remaining types appear only as children of
613 > * a container.
614 > *
615 > * @category Customization Types
616 > */
617 > export const enum CustomizationType {
618 > Plugin = 'plugin',
619 > Directory = 'directory',
620 > Agent = 'agent',
621 > Skill = 'skill',
622 > Prompt = 'prompt',
623 > Rule = 'rule',
624 > Hook = 'hook',
625 > McpServer = 'mcpServer',
626 > }
627 >
628 > /**
629 > * Customization types that appear as children of a
630 > * {@link PluginCustomization} or {@link DirectoryCustomization}.
631 > *
632 > * @category Customization Types
633 > */
634 > export type ChildCustomizationType =
635 > | CustomizationType.Agent
636 > | CustomizationType.Skill
637 > | CustomizationType.Prompt
638 > | CustomizationType.Rule
639 > | CustomizationType.Hook
640 > | CustomizationType.McpServer;
641 >
642 > /**
643 > * Fields shared by every customization variant.
644 > *
645 > * @category Customization Types
646 > */
647 > interface CustomizationBase {
648 > /**
649 > * Session-unique opaque identifier. Used by every action that targets a
650 > * specific customization. Minted by whoever publishes the customization
651 > * (typically the agent host).
652 > */
653 > id: string;
654 > /**
655 > * Source URI for this customization. A plugin URL, a file URI, or a
656 > * directory URI.
657 > *
658 > * For declarations that live inside a larger file — e.g. an MCP
659 > * server declared inline in a `plugins.json` manifest — `uri` points
660 > * to the containing file and {@link CustomizationBase.range | `range`}
661 > * narrows it to the declaration's span.
662 > */
663 > uri: URI;
664 > /** Human-readable name. */
665 > name: string;
666 > /** Icons for UI display. */
667 > icons?: Icon[];
668 > /**
669 > * Optional span within {@link CustomizationBase.uri | `uri`} when this
670 > * customization is a subset of a larger file (for example, one entry
671 > * in an inline `mcpServers` block of a `plugins.json` manifest).
672 > * Absent when the customization covers the whole resource.
673 > */
674 > range?: TextRange;
675 > /**
676 > * Additional provider-specific metadata for this customization.
677 > *
678 > * Mirrors the MCP `_meta` convention. Optional and opaque to the
679 > * protocol; producers and consumers agree on its contents
680 > * out-of-band.
681 > */
682 > _meta?: Record<string, unknown>;
683 > }
684 >
685 > /**
686 > * Discriminant values for {@link CustomizationLoadState}.
687 > *
688 > * @category Customization Types
689 > */
690 > export const enum CustomizationLoadStatus {
691 > Loading = 'loading',
692 > Loaded = 'loaded',
693 > Degraded = 'degraded',
694 > Error = 'error',
695 > }
696 >
697 > /**
698 > * Container is being loaded by the host.
699 > *
700 > * @category Customization Types
701 > */
702 > export interface CustomizationLoadingState {
703 > kind: CustomizationLoadStatus.Loading;
704 > }
705 >
706 > /**
707 > * Container loaded successfully.
708 > *
709 > * @category Customization Types
710 > */
711 > export interface CustomizationLoadedState {
712 > kind: CustomizationLoadStatus.Loaded;
713 > }
714 >
715 > /**
716 > * Container partially loaded but has warnings.
717 > *
718 > * @category Customization Types
719 > */
720 > export interface CustomizationDegradedState {
721 > kind: CustomizationLoadStatus.Degraded;
722 > /** Human-readable description of the warning. */
723 > message: string;
724 > }
725 >
726 > /**
727 > * Container failed to load.
728 > *
729 > * @category Customization Types
730 > */
731 > export interface CustomizationErrorState {
732 > kind: CustomizationLoadStatus.Error;
733 > /** Human-readable error message. */
734 > message: string;
735 > }
736 >
737 > /**
738 > * Discriminated load state for a container customization
739 > * ({@link PluginCustomization} or {@link DirectoryCustomization}).
740 > *
741 > * @category Customization Types
742 > */
743 > export type CustomizationLoadState =
744 > | CustomizationLoadingState
745 > | CustomizationLoadedState
746 > | CustomizationDegradedState
747 > | CustomizationErrorState;
748 >
749 > /**
750 > * Fields shared by container customizations.
751 > *
752 > * @category Customization Types
753 > */
754 > interface ContainerCustomizationBase extends CustomizationBase {
755 > /** Whether this container is currently enabled. */
756 > enabled: boolean;
757 > /**
758 > * `clientId` of the client that contributed this container. Absent for
759 > * server-originated entries.
760 > */
761 > clientId?: string;
762 > /**
763 > * Host-reported load state. Absent means the host has not yet reported
764 > * a load state for this container.
765 > */
766 > load?: CustomizationLoadState;
767 > /**
768 > * Children discovered inside this container.
769 > *
770 > * Absent means the host has not parsed this container yet. An empty
771 > * array means the host parsed the container and it contributes
772 > * nothing.
773 > */
774 > children?: ChildCustomization[];
775 > }
776 >
777 > /**
778 > * An [Open Plugins](https://open-plugins.com/) plugin.
779 > *
780 > * @category Customization Types
781 > */
782 > export interface PluginCustomization extends ContainerCustomizationBase {
783 > type: CustomizationType.Plugin;
784 > /**
785 > * Version of the plugin, sourced from the
786 > * [Open Plugins](https://open-plugins.com/) manifest's optional
787 > * `version` field (semver, e.g. `"1.2.0"`). Absent when the manifest
788 > * declares no version — the field is optional there — or the source
789 > * has no version concept. Provenance / display only: the host neither
790 > * parses nor enforces it.
791 > */
792 > version?: string;
793 > }
794 >
795 > /**
796 > * A {@link PluginCustomization} as published by a client. Extends the
797 > * server-facing shape with an opaque `nonce` so the host can detect when
798 > * the client's view of a plugin has changed and re-parse only as needed.
799 > *
800 > * Clients SHOULD include a `nonce`. Server-side fields like
801 > * {@link ContainerCustomizationBase.children | `children`} and
802 > * {@link ContainerCustomizationBase.load | `load`} are typically left
803 > * absent on publication and populated by the host when the resolved
804 > * plugin appears in {@link SessionState.customizations}.
805 > *
806 > * @category Customization Types
807 > */
808 > export interface ClientPluginCustomization extends PluginCustomization {
809 > /** Opaque version token used by the host to detect changes. */
810 > nonce?: string;
811 > }
812 >
813 > /**
814 > * A directory the host watches for this session.
815 > *
816 > * Presence in the customization list signals that the host may discover
817 > * customizations from this directory. When `writable` is `true`, clients
818 > * MAY persist new customizations into the directory using
819 > * [`resourceWrite`](/reference/common#resourcewrite); the host will
820 > * then surface the resulting child via the customization actions.
821 > *
822 > * The directory may not yet exist on disk.
823 > *
824 > * @category Customization Types
825 > */
826 > export interface DirectoryCustomization extends ContainerCustomizationBase {
827 > type: CustomizationType.Directory;
828 > /** Which child customization type this directory holds. */
829 > contents: ChildCustomizationType;
830 > /** Whether clients may write into this directory. */
831 > writable: boolean;
832 > }
833 >
834 > /**
835 > * Fields shared by the leaf child customizations that live inside a
836 > * container — {@link AgentCustomization}, {@link SkillCustomization},
837 > * {@link PromptCustomization}, {@link RuleCustomization}, and
838 > * {@link HookCustomization}.
839 > *
840 > * {@link McpServerCustomization} is also a child but does not extend this
841 > * base: it always carries an explicit {@link McpServerCustomization.enabled}
842 > * because it can appear as a top-level customization too.
843 > *
844 > * @category Customization Types
845 > */
846 > interface ChildCustomizationBase extends CustomizationBase {
847 > /**
848 > * Whether this child is individually enabled. Absent means enabled, so a
849 > * producer only needs to set it to surface a child that exists but is
850 > * turned off on its own.
851 > *
852 > * This flag is independent of the parent container's: the **effective**
853 > * enabled state of a child is
854 > * `container.enabled && (child.enabled ?? true)`, so a disabled container
855 > * disables every child regardless of each child's own flag.
856 > *
857 > * A child is turned on or off by id with
858 > * {@link SessionCustomizationToggledAction | `session/customizationToggled`}.
859 > */
860 > enabled?: boolean;
861 > }
862 >
863 > /**
864 > * A custom agent contributed by a plugin or directory.
865 > *
866 > * Mirrors the [Open Plugins agent](https://open-plugins.com/agent-builders/components/agents)
867 > * format: a markdown file with YAML frontmatter, where the body is the
868 > * agent's system prompt.
869 > *
870 > * @category Customization Types
871 > */
872 > export interface AgentCustomization extends ChildCustomizationBase {
873 > type: CustomizationType.Agent;
874 > /**
875 > * Short description of what the agent specializes in and when to
876 > * invoke it. Sourced from the agent file's frontmatter `description`.
877 > */
878 > description?: string;
879 > /**
880 > * Model the agent is pinned to, sourced from the agent file's
881 > * frontmatter `model`. Absent means the agent inherits the session's
882 > * default model.
883 > */
884 > model?: string;
885 > /**
886 > * Allowlist of tool names the agent is scoped to, sourced from the
887 > * agent file's frontmatter `tools`. A non-empty list restricts the
888 > * agent to exactly those tools. Absent — or an empty list — imposes no
889 > * restriction beyond the session default: the agent may use any
890 > * available tool. Producers express "no restriction" by omitting the
891 > * field rather than sending an empty array, so an empty list carries no
892 > * meaning distinct from absence.
893 > */
894 > tools?: string[];
895 > /**
896 > * When `true`, the agent will not auto-delegate to this custom agent
897 > * as a sub-agent; it can only be selected by the user. Absent or
898 > * `false` means the agent may delegate to it.
899 > */
900 > disableModelInvocation?: boolean;
901 > /**
902 > * When `true`, the user cannot select this custom agent (for example,
903 > * in a picker); it remains available for the agent to auto-delegate
904 > * to. Absent or `false` means the user may select it.
905 > */
906 > disableUserInvocation?: boolean;
907 > }
908 >
909 > /**
910 > * A skill contributed by a plugin or directory.
911 > *
912 > * Covers both [Open Plugins skill formats](https://open-plugins.com/agent-builders/components/skills)
913 > * — the `skills/` directory layout (one subdirectory per skill, each with
914 > * a `SKILL.md`) and the flatter `commands/` directory of slash-command
915 > * skills.
916 > *
917 > * @category Customization Types
918 > */
919 > export interface SkillCustomization extends ChildCustomizationBase {
920 > type: CustomizationType.Skill;
921 > /**
922 > * Short description used for help text and auto-invocation matching.
923 > * Sourced from the skill's frontmatter `description`.
924 > */
925 > description?: string;
926 > /**
927 > * When `true`, only the user can invoke this skill — the agent will not
928 > * auto-invoke it. Sourced from the command skill's frontmatter
929 > * `disable-model-invocation` flag.
930 > */
931 > disableModelInvocation?: boolean;
932 > /**
933 > * When `true`, the user cannot directly invoke this skill (for example,
934 > * as a slash command); it remains available for the agent to
935 > * auto-invoke. Absent or `false` means the user may invoke it.
936 > */
937 > disableUserInvocation?: boolean;
938 > }
939 >
940 > /**
941 > * A prompt contributed by a plugin or directory.
942 > *
943 > * @category Customization Types
944 > */
945 > export interface PromptCustomization extends ChildCustomizationBase {
946 > type: CustomizationType.Prompt;
947 > /** Short description of what the prompt does. */
948 > description?: string;
949 > }
950 >
951 > /**
952 > * A rule contributed by a plugin or directory.
953 > *
954 > * Mirrors the [Open Plugins rule](https://open-plugins.com/agent-builders/components/rules)
955 > * format: a markdown file (e.g. `.mdc`) whose body is injected into
956 > * context while the rule is active. This type also covers tool-specific
957 > * "instruction" formats (e.g. VS Code Copilot's
958 > * `.github/instructions/*.md`), which differ only in naming — they
959 > * share the same semantics of `description`, optional always-on
960 > * activation, and optional glob scoping.
961 > *
962 > * @category Customization Types
963 > */
964 > export interface RuleCustomization extends ChildCustomizationBase {
965 > type: CustomizationType.Rule;
966 > /**
967 > * Description of what the rule enforces.
968 > */
969 > description?: string;
970 > /**
971 > * When `true`, the rule is always active (subject to `globs` if any).
972 > * When `false` or absent, the agent or user decides whether to apply
973 > * the rule.
974 > */
975 > alwaysApply?: boolean;
976 > /**
977 > * Glob patterns the rule applies to. When present, the rule is only
978 > * active for matching files.
979 > */
980 > globs?: string[];
981 > }
982 >
983 > /**
984 > * A hook manifest contributed by a plugin or directory.
985 > *
986 > * @category Customization Types
987 > */
988 > export interface HookCustomization extends ChildCustomizationBase {
989 > type: CustomizationType.Hook;
990 > }
991 >
992 > /**
993 > * An MCP server contributed by a plugin or directory.
994 > *
995 > * When the server is declared inline in the containing plugin manifest,
996 > * `uri` points at the manifest file and
997 > * {@link CustomizationBase.range | `range`} narrows it to the
998 > * declaration's span.
999 > *
1000 > * The MCP server customization also reflects its current status.
1001 > *
1002 > * @category Customization Types
1003 > */
1004 > export interface McpServerCustomization extends CustomizationBase {
1005 > type: CustomizationType.McpServer;
1006 > /**
1007 > * Whether this MCP server is currently enabled.
1008 > */
1009 > enabled: boolean;
1010 > /**
1011 > * Current lifecycle state of the MCP server.
1012 > */
1013 > state: McpServerState;
1014 > /**
1015 > * An `mcp://`-protocol channel the client uses to side-channel traffic
1016 > * into the upstream MCP server itself. The channel is NOT a fresh raw MCP
1017 > * connection: it piggybacks on the AHP transport
1018 > * and skips the MCP `initialize` sequence.
1019 > *
1020 > * The agent host MAY only serve a subset of MCP on this
1021 > * channel; the served subset is described by domain-specific
1022 > * capabilities such as those in
1023 > * {@link McpServerCustomizationApps.capabilities}.
1024 > *
1025 > * The channel URI SHOULD be stable across the server's lifetime, but
1026 > * the agent host MAY change it (for example across a restart) and
1027 > * MAY only expose it while the server is in
1028 > * {@link McpServerStatus.Ready | `Ready`}. Absence means no
1029 > * side-channel is currently available.
1030 > */
1031 > channel?: URI;
1032 > /**
1033 > * MCP App support. This property SHOULD be advertised for MCP servers
1034 > * which support apps.
1035 > */
1036 > mcpApp?: McpServerCustomizationApps;
1037 > }
1038 >
1039 > /**
1040 > * Information from the agent host needed to render MCP Apps served
1041 > * by this MCP server.
1042 > *
1043 > * @category MCP Server State
1044 > */
1045 > export interface McpServerCustomizationApps {
1046 > /**
1047 > * The subset of MCP App
1048 > * [`HostCapabilities`](https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx)
1049 > * the AHP host can satisfy for Views backed by this server. The
1050 > * client feeds these straight through into the `hostCapabilities` of
1051 > * the `ui/initialize` response delivered to the View.
1052 > */
1053 > capabilities: AhpMcpUiHostCapabilities;
1054 > }
1055 >
1056 > /**
1057 > * The subset of MCP App
1058 > * [`HostCapabilities`](https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx)
1059 > * an AHP host can derive from the upstream MCP server (and from AHP's own
1060 > * forwarding plumbing). Advertised on
1061 > * {@link McpServerCustomizationApps.capabilities} so clients can pass it
1062 > * through into the `hostCapabilities` of the `ui/initialize` response
1063 > * delivered to an MCP App View.
1064 > *
1065 > * Field names mirror the MCP Apps spec exactly, so the AHP-side producer
1066 > * can pass them straight through into the `hostCapabilities` of the
1067 > * `ui/initialize` response delivered to the View.
1068 > *
1069 > * Capabilities outside this set (`openLinks`, `downloadFile`, `sandbox`,
1070 > * `experimental`) are decided locally by whichever AHP client renders the
1071 > * View and are NOT part of this AHP-level advertisement — only the
1072 > * server-derived subset is.
1073 > *
1074 > * An agent host MUST only advertise a capability when it actually accepts the
1075 > * corresponding methods/notifications on the `mcp://` channel:
1076 > *
1077 > * - {@link serverTools}: host proxies `tools/list` and `tools/call` to
1078 > * the MCP server. When `listChanged` is `true`, the host also forwards
1079 > * `notifications/tools/list_changed`.
1080 > * - {@link serverResources}: host proxies `resources/read`,
1081 > * `resources/list`, and `resources/templates/list` to the MCP server.
1082 > * When `listChanged` is `true`, the host also forwards
1083 > * `notifications/resources/list_changed`.
1084 > * - {@link logging}: host accepts `notifications/message` log entries
1085 > * from the App and forwards them via `mcpNotification` (and forwards
1086 > * `logging/setLevel` calls to the server).
1087 > * - {@link sampling}: host serves `sampling/createMessage` via
1088 > * `mcpMethodCall`. When `sampling.tools` is present, the host also
1089 > * accepts SEP-1577 `tools` / `toolChoice` / `tool_use` content blocks
1090 > * inside `CreateMessageRequest`.
1091 > *
1092 > * @category MCP Server State
1093 > * @see {@link https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx | MCP Apps spec (SEP-1865)}
1094 > */
1095 > export interface AhpMcpUiHostCapabilities {
1096 > /** Producer proxies the MCP `tools/*` methods to the upstream server. */
1097 > serverTools?: {
1098 > /** Producer forwards `notifications/tools/list_changed` from the server. */
1099 > listChanged?: boolean;
1100 > };
1101 > /** Producer proxies the MCP `resources/*` methods to the upstream server. */
1102 > serverResources?: {
1103 > /** Producer forwards `notifications/resources/list_changed` from the server. */
1104 > listChanged?: boolean;
1105 > };
1106 > /** Producer accepts `notifications/message` log entries from the App via `mcpNotification`. */
1107 > logging?: Record<string, never>;
1108 > /** Producer serves `sampling/createMessage` via `mcpMethodCall`. */
1109 > sampling?: {
1110 > /**
1111 > * Producer accepts SEP-1577 `tools` / `toolChoice` / `tool_use` content
1112 > * blocks inside `CreateMessageRequest`.
1113 > */
1114 > tools?: Record<string, never>;
1115 > };
1116 > }
1117 >
1118 > /**
1119 > * Child customizations that live inside a {@link PluginCustomization} or
1120 > * {@link DirectoryCustomization}.
1121 > *
1122 > * @category Customization Types
1123 > */
1124 > export type ChildCustomization =
1125 > | AgentCustomization
1126 > | SkillCustomization
1127 > | PromptCustomization
1128 > | RuleCustomization
1129 > | HookCustomization
1130 > | McpServerCustomization;
1131 >
1132 > /**
1133 > * A top-level customization active in a session. Either a container
1134 > * ({@link PluginCustomization} or {@link DirectoryCustomization}) whose
1135 > * leaf customizations live in its
1136 > * {@link ContainerCustomizationBase.children | `children`} array, or a
1137 > * bare {@link McpServerCustomization} surfaced directly by the host.
1138 > *
1139 > * @category Customization Types
1140 > */
1141 > export type Customization =
1142 > | PluginCustomization
1143 > | DirectoryCustomization
1144 > | McpServerCustomization;
1145 >
1146 >
1147 > // ─── MCP Server State ────────────────────────────────────────────────────────
1148 >
1149 > /**
1150 > * Discriminant for the {@link McpServerState} union.
1151 > *
1152 > * @category MCP Server State
1153 > */
1154 > export const enum McpServerStatus {
1155 > /** Server has been registered but is not yet running. */
1156 > Starting = 'starting',
1157 > /** Server is running and serving requests. */
1158 > Ready = 'ready',
1159 > /**
1160 > * Server is reachable but requires additional authentication before it
1161 > * can start, or before it can serve a particular request. Carries the
1162 > * RFC 9728 Protected Resource Metadata the client needs to obtain a
1163 > * token; the client then pushes the token via the existing
1164 > * `authenticate` command.
1165 > */
1166 > AuthRequired = 'authRequired',
1167 > /** Server failed to start, crashed, or otherwise transitioned to a fatal error. */
1168 > Error = 'error',
1169 > /** Server has been shut down. */
1170 > Stopped = 'stopped',
1171 > }
1172 >
1173 > /**
1174 > * Why an MCP server is currently in the {@link McpServerStatus.AuthRequired}
1175 > * state. Mirrors the three failure modes defined by the
1176 > * [MCP authorization spec](https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization.md).
1177 > *
1178 > * @category MCP Server State
1179 > */
1180 > export const enum McpAuthRequiredReason {
1181 > /** No token has been provided yet (HTTP 401, no prior token). */
1182 > Required = 'required',
1183 > /** A previously valid token expired or was revoked (HTTP 401). */
1184 > Expired = 'expired',
1185 > /**
1186 > * Step-up auth: a token is present but its scopes are insufficient for
1187 > * the requested operation (HTTP 403 with
1188 > * `WWW-Authenticate: Bearer error="insufficient_scope"`).
1189 > *
1190 > * Unlike {@link Required} and {@link Expired} — which typically surface
1191 > * before any tool work is in flight — `InsufficientScope` is almost
1192 > * always triggered by an MCP request issued mid-turn (a `tools/call`,
1193 > * `resources/read`, etc.). The host SHOULD pair the
1194 > * {@link McpServerAuthRequiredState} transition with
1195 > * {@link SessionStatus.InputNeeded} on
1196 > * {@link SessionSummary.status | the session} so the activity becomes
1197 > * visible at the session-summary level, and clients SHOULD watch for
1198 > * this kind on any
1199 > * {@link McpServerCustomization | MCP server} backing a running tool
1200 > * call so they can present an explicit "grant more access" affordance
1201 > * tied to the blocked tool call.
1202 > */
1203 > InsufficientScope = 'insufficientScope',
1204 > }
1205 >
1206 > /**
1207 > * Server is registered with the host but has not yet started.
1208 > *
1209 > * @category MCP Server State
1210 > */
1211 > export interface McpServerStartingState {
1212 > kind: McpServerStatus.Starting;
1213 > }
1214 >
1215 > /**
1216 > * Server is running and serving requests.
1217 > *
1218 > * @category MCP Server State
1219 > */
1220 > export interface McpServerReadyState {
1221 > kind: McpServerStatus.Ready;
1222 > }
1223 >
1224 > /**
1225 > * A pre-registered OAuth client that clients use instead of dynamic client
1226 > * registration when resolving an MCP authentication challenge.
1227 > *
1228 > * @category MCP Server State
1229 > */
1230 > export interface McpOAuthClient {
1231 > /** OAuth client identifier registered with the authorization server. */
1232 > clientId: string;
1233 > /**
1234 > * OAuth client secret for a confidential client. Absence means the client is
1235 > * public and uses a secretless flow such as authorization code with PKCE.
1236 > */
1237 > clientSecret?: string;
1238 > }
1239 >
1240 > /**
1241 > * Reusable MCP authentication challenge — the RFC 9728 discovery info a
1242 > * client needs to obtain a token and push it via the `authenticate` command.
1243 > * Deliberately carries **no token**: this describes what is being asked for,
1244 > * never the ****** itself.
1245 > *
1246 > * Shared by two independent state machines that describe the same OAuth
1247 > * challenge from different vantage points:
1248 > *
1249 > * - {@link McpServerAuthRequiredState} — the MCP server itself cannot serve
1250 > * *any* request until the client authenticates.
1251 > * - {@link ToolCallAuthRequiredState} — a specific in-flight tool call is
1252 > * paused pending authentication (typically
1253 > * {@link McpAuthRequiredReason.InsufficientScope} step-up auth
1254 > * mid-execution). The server state and the tool-call state remain
1255 > * separate on purpose: the server saying "I need auth" and a tool
1256 > * invocation saying "I am waiting on that auth" are different facts that
1257 > * can be true independently.
1258 > *
1259 > * @category MCP Server State
1260 > */
1261 > export interface McpAuthRequirement {
1262 > /** Why authentication is required. */
1263 > reason: McpAuthRequiredReason;
1264 > /**
1265 > * Pre-registered OAuth client to use for authorization. When present, clients
1266 > * MUST use these credentials instead of dynamic client registration.
1267 > */
1268 > oauthClient?: McpOAuthClient;
1269 > /**
1270 > * RFC 9728 Protected Resource Metadata. The `resource` field is the
1271 > * canonical MCP server URI per RFC 8707, used as the OAuth `resource`
1272 > * indicator. `authorization_servers` is REQUIRED by the MCP
1273 > * authorization spec.
1274 > */
1275 > resource: ProtectedResourceMetadata;
1276 > /**
1277 > * Scopes required for the current challenge, parsed from the
1278 > * `WWW-Authenticate: ******"…"` header (or `scopes_supported`
1279 > * fallback). Authoritative for the next authorization request — clients
1280 > * MUST NOT assume any subset/superset relationship to
1281 > * `resource.scopes_supported`.
1282 > */
1283 > requiredScopes?: string[];
1284 > /** Human-readable hint, typically from the OAuth `error_description`. */
1285 > description?: string;
1286 > }
1287 >
1288 > /**
1289 > * Server is reachable but cannot serve requests until the client
1290 > * authenticates. Mirrors the discovery flow defined by
1291 > * [RFC 9728](https://datatracker.ietf.org/doc/html/rfc9728)
1292 > * (Protected Resource Metadata) and the OAuth 2.1 / RFC 6750 challenge
1293 > * semantics required by the MCP authorization spec.
1294 > *
1295 > * Clients react to this state by calling the existing `authenticate`
1296 > * command with the {@link ProtectedResourceMetadata.resource | resource}
1297 > * carried here. There is **no** `notify/authRequired` notification for
1298 > * MCP servers — the action stream is the single source of truth.
1299 > *
1300 > * When the transition is triggered by a request issued during a turn
1301 > * — most commonly
1302 > * {@link McpAuthRequiredReason.InsufficientScope | `InsufficientScope`}
1303 > * surfacing mid-tool-call — the host SHOULD also raise
1304 > * {@link SessionStatus.InputNeeded} on the session so the block is
1305 > * visible at the summary level. Clients SHOULD watch this status on
1306 > * any MCP server backing a running tool call and surface an explicit
1307 > * affordance (e.g. a "grant additional access" prompt) tied to that
1308 > * tool call, rather than relying on the user to notice the
1309 > * customization’s status badge.
1310 > *
1311 > * @category MCP Server State
1312 > */
1313 > export interface McpServerAuthRequiredState extends McpAuthRequirement {
1314 > kind: McpServerStatus.AuthRequired;
1315 > }
1316 >
1317 > /**
1318 > * Server failed to start, crashed, or otherwise transitioned to a
1319 > * non-recoverable error. Use {@link McpServerStatus.AuthRequired}
1320 > * for authentication failures.
1321 > *
1322 > * @category MCP Server State
1323 > */
1324 > export interface McpServerErrorState {
1325 > kind: McpServerStatus.Error;
1326 > /** Error details. */
1327 > error: ErrorInfo;
1328 > }
1329 >
1330 > /**
1331 > * Server has been shut down. The host MAY remove the server from the
1332 > * session entirely shortly after this state.
1333 > *
1334 > * @category MCP Server State
1335 > */
1336 > export interface McpServerStoppedState {
1337 > kind: McpServerStatus.Stopped;
1338 > }
1339 >
1340 > /**
1341 > * Discriminated union of all MCP server lifecycle states.
1342 > * Discriminated by `kind` (a {@link McpServerStatus} value).
1343 > *
1344 > * @category MCP Server State
1345 > */
1346 > export type McpServerState =
1347 > | McpServerStartingState
1348 > | McpServerReadyState
1349 > | McpServerAuthRequiredState
1350 > | McpServerErrorState
1351 > | McpServerStoppedState;
src/vs/platform/quickinput/common/quickInput.ts 1261 covered LOC · 5 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- quickInput.ts
2 > * Copyright (c) Microsoft 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 { createDecorator } from '../../instantiation/common/instantiation.js';
9 > import { IQuickAccessController } from './quickAccess.js';
10 > import { IMatch } from '../../../base/common/filters.js';
11 > import { IItemAccessor } from '../../../base/common/fuzzyScorer.js';
12 > import { ResolvedKeybinding } from '../../../base/common/keybindings.js';
13 > import { IDisposable } from '../../../base/common/lifecycle.js';
14 > import { Schemas } from '../../../base/common/network.js';
15 > import { IObservable } from '../../../base/common/observable.js';
16 > import Severity from '../../../base/common/severity.js';
17 > import { URI } from '../../../base/common/uri.js';
18 > import { IMarkdownString } from '../../../base/common/htmlContent.js';
19 >
20 > export interface IQuickItemHighlights {
21 > label?: IMatch[];
22 > description?: IMatch[];
23 > }
24 >
25 > export interface IQuickPickItemHighlights extends IQuickItemHighlights {
26 > detail?: IMatch[];
27 > }
28 >
29 > export type QuickPickItem = IQuickPickSeparator | IQuickPickItem;
30 >
31 > /**
32 > * Base properties for a quick pick and quick tree item.
33 > */
34 > export interface IQuickItem {
35 > id?: string;
36 > label: string;
37 > ariaLabel?: string;
38 > description?: string;
39 > /**
40 > * Whether the item is displayed in italics.
41 > */
42 > italic?: boolean;
43 > /**
44 > * Whether the item is displayed with a strikethrough.
45 > */
46 > strikethrough?: boolean;
47 > /**
48 > * Icon classes to be passed on as `IIconLabelValueOptions`
49 > * to the underlying `IconLabel` widget.
50 > */
51 > iconClasses?: readonly string[];
52 > iconPath?: { dark: URI; light?: URI };
53 > /**
54 > * Icon class to be assigned to the quick item container
55 > * directly.
56 > */
57 > iconClass?: string;
58 > highlights?: IQuickItemHighlights;
59 > buttons?: readonly IQuickInputButton[];
60 > /**
61 > * Used when we're in multi-select mode. Renders a disabled checkbox.
62 > */
63 > disabled?: boolean;
64 > }
65 >
66 > /**
67 > * Represents a quick pick item used in the quick pick UI.
68 > */
69 > export interface IQuickPickItem extends IQuickItem {
70 > /**
71 > * The type of the quick pick item. Used to distinguish between 'item' and 'separator'
72 > */
73 > type?: 'item';
74 > /**
75 > * The detail text of the quick pick item. Shown as the second line.
76 > */
77 > detail?: string;
78 > /**
79 > * The tooltip for the quick pick item.
80 > */
81 > tooltip?: string | IMarkdownString;
82 > highlights?: IQuickPickItemHighlights;
83 > /**
84 > * Allows to show a keybinding next to the item to indicate
85 > * how the item can be triggered outside of the picker using
86 > * keyboard shortcut.
87 > */
88 > keybinding?: ResolvedKeybinding;
89 > /**
90 > * Whether the item is picked by default when the Quick Pick is shown.
91 > */
92 > picked?: boolean;
93 > /**
94 > * Whether the item is always shown in the Quick Pick regardless of filtering.
95 > */
96 > alwaysShow?: boolean;
97 > /**
98 > * Defaults to true with `IQuickPick.canSelectMany`, can be false to disable picks for a single item
99 > */
100 > pickable?: boolean;
101 > }
102 >
103 > export interface IQuickPickSeparator {
104 > /**
105 > * The type of the quick pick item. Used to distinguish between 'item' and 'separator'
106 > */
107 > type: 'separator';
108 > id?: string;
109 > label?: string;
110 > description?: string;
111 > ariaLabel?: string;
112 > buttons?: readonly IQuickInputButton[];
113 > tooltip?: string | IMarkdownString;
114 > }
115 >
116 > export interface IKeyMods {
117 > readonly ctrlCmd: boolean;
118 > readonly alt: boolean;
119 > readonly shift: boolean;
120 > }
121 >
122 > export function isKeyModified(keyMods: IKeyMods): boolean {
123 return keyMods.ctrlCmd || keyMods.alt || keyMods.shift;
124 }
126 > export const NO_KEY_MODS: IKeyMods = { ctrlCmd: false, alt: false, shift: false };
127 >
128 > export interface IQuickNavigateConfiguration {
129 > keybindings: readonly ResolvedKeybinding[];
130 > }
131 >
132 > export interface IPickOptions<T extends IQuickPickItem> {
133 >
134 > /**
135 > * an optional string to show as the title of the quick input
136 > */
137 > title?: string;
138 >
139 > /**
140 > * the value to prefill in the input box
141 > */
142 > value?: string;
143 >
144 > /**
145 > * an optional string to show as placeholder in the input box to guide the user what she picks on
146 > */
147 > placeHolder?: string;
148 >
149 > /**
150 > * the text to display underneath the input box
151 > */
152 > prompt?: string;
153 >
154 > /**
155 > * an optional flag to include the description when filtering the picks
156 > */
157 > matchOnDescription?: boolean;
158 >
159 > /**
160 > * an optional flag to include the detail when filtering the picks
161 > */
162 > matchOnDetail?: boolean;
163 >
164 > /**
165 > * an optional flag to filter the picks based on label. Defaults to true.
166 > */
167 > matchOnLabel?: boolean;
168 >
169 > /**
170 > * an optional flag to sort the picks based by the label.
171 > */
172 > sortByLabel?: boolean;
173 >
174 > /**
175 > * an optional flag to not close the picker on focus lost
176 > */
177 > ignoreFocusLost?: boolean;
178 >
179 > /**
180 > * an optional flag to make this picker multi-select
181 > */
182 > canPickMany?: boolean;
183 >
184 > /**
185 > * enables quick navigate in the picker to open an element without typing
186 > */
187 > quickNavigate?: IQuickNavigateConfiguration;
188 >
189 > /**
190 > * Hides the input box from the picker UI. This is typically used
191 > * in combination with quick-navigation where no search UI should
192 > * be presented.
193 > */
194 > hideInput?: boolean;
195 >
196 > /**
197 > * a context key to set when this picker is active
198 > */
199 > contextKey?: string;
200 >
201 > /**
202 > * an optional property for the item to focus initially.
203 > */
204 > activeItem?: Promise<T> | T;
205 >
206 > /**
207 > * an optional anchor for the picker
208 > */
209 > anchor?: unknown /* HTMLElement */ | { x: number; y: number };
210 >
211 > /**
212 > * Placement of the quick input relative to {@link anchor}.
213 > * `'overlay'` positions the input box directly on top of the anchor (which must be an HTMLElement)
214 > * and auto-sizes its width to match. Defaults to `'above'`.
215 > */
216 > anchorPosition?: 'above' | 'overlay';
217 >
218 > onKeyMods?: (keyMods: IKeyMods) => void;
219 > onDidFocus?: (entry: T) => void;
220 > onDidTriggerItemButton?: (context: IQuickPickItemButtonContext<T>) => void;
221 > onDidTriggerSeparatorButton?: (context: IQuickPickSeparatorButtonEvent) => void;
222 > }
223 >
224 > export interface IInputOptions {
225 >
226 > /**
227 > * an optional string to show as the title of the quick input
228 > */
229 > title?: string;
230 >
231 > /**
232 > * the value to prefill in the input box
233 > */
234 > value?: string;
235 >
236 > /**
237 > * the selection of value, default to the whole prefilled value
238 > */
239 > valueSelection?: readonly [number, number];
240 >
241 > /**
242 > * the text to display underneath the input box
243 > */
244 > prompt?: string;
245 >
246 > /**
247 > * an optional string to show as placeholder in the input box to guide the user what to type
248 > */
249 > placeHolder?: string;
250 >
251 > /**
252 > * Controls if a password input is shown. Password input hides the typed text.
253 > */
254 > password?: boolean;
255 >
256 > /**
257 > * an optional flag to not close the input on focus lost
258 > */
259 > ignoreFocusLost?: boolean;
260 >
261 > /**
262 > * an optional function that is used to validate user input.
263 > */
264 > validateInput?: (input: string) => Promise<string | null | undefined | { content: string; severity: Severity }>;
265 > }
266 >
267 > export enum QuickInputHideReason {
268 >
269 > /**
270 > * Focus moved away from the quick input.
271 > */
272 > Blur = 1,
273 >
274 > /**
275 > * An explicit user gesture, e.g. pressing Escape key.
276 > */
277 > Gesture,
278 >
279 > /**
280 > * Anything else.
281 > */
282 > Other
283 > }
284 >
285 > export interface IQuickInputHideEvent {
286 > reason: QuickInputHideReason;
287 > }
288 >
289 > /**
290 > * A collection of the different types of QuickInput
291 > */
292 > export const enum QuickInputType {
293 > QuickPick = 'quickPick',
294 > InputBox = 'inputBox',
295 > QuickWidget = 'quickWidget',
296 > QuickTree = 'quickTree'
297 > }
298 >
299 > /**
300 > * Represents a quick input control that allows users to make selections or provide input quickly.
301 > */
302 > export interface IQuickInput extends IDisposable {
303 >
304 > /**
305 > * The type of the quick input.
306 > */
307 > readonly type: QuickInputType;
308 >
309 > /**
310 > * An event that is fired when the quick input is hidden.
311 > */
312 > readonly onDidHide: Event<IQuickInputHideEvent>;
313 >
314 > /**
315 > * An event that is fired when the quick input will be hidden.
316 > */
317 > readonly onWillHide: Event<IQuickInputHideEvent>;
318 >
319 > /**
320 > * An event that is fired when the quick input is disposed.
321 > */
322 > readonly onDispose: Event<void>;
323 >
324 > /**
325 > * The title of the quick input.
326 > */
327 > title: string | undefined;
328 >
329 > /**
330 > * The description of the quick input. This is rendered right below the input box.
331 > */
332 > description: string | undefined;
333 >
334 > /**
335 > * The current step of the quick input rendered in the titlebar.
336 > */
337 > step: number | undefined;
338 >
339 > /**
340 > * The total number of steps in the quick input rendered in the titlebar.
341 > */
342 > totalSteps: number | undefined;
343 >
344 > /**
345 > * The buttons displayed in the quick input titlebar.
346 > */
347 > buttons: ReadonlyArray<IQuickInputButton>;
348 >
349 > /**
350 > * An event that is fired when a button in the quick input is triggered.
351 > */
352 > readonly onDidTriggerButton: Event<IQuickInputButton>;
353 >
354 > /**
355 > * Indicates whether the input is enabled.
356 > */
357 > enabled: boolean;
358 >
359 > /**
360 > * The context key associated with the quick input.
361 > */
362 > contextKey: string | undefined;
363 >
364 > /**
365 > * Indicates whether the quick input is busy. Renders a progress bar if true.
366 > */
367 > busy: boolean;
368 >
369 > /**
370 > * Indicates whether the quick input should be hidden when it loses focus.
371 > */
372 > ignoreFocusOut: boolean;
373 >
374 > /**
375 > * An optional anchor for the quick input.
376 > */
377 > anchor?: unknown /* HTMLElement */ | { x: number; y: number };
378 >
379 > /**
380 > * Placement of the quick input relative to {@link anchor}.
381 > * `'overlay'` positions the input box directly on top of the anchor (which must be an HTMLElement)
382 > * and auto-sizes its width to match. Defaults to `'above'`.
383 > */
384 > anchorPosition?: 'above' | 'overlay';
385 >
386 > /**
387 > * Shows the quick input.
388 > */
389 > show(): void;
390 >
391 > /**
392 > * Hides the quick input.
393 > */
394 > hide(): void;
395 >
396 > /**
397 > * Notifies that the quick input has been hidden.
398 > * @param reason The reason why the quick input was hidden.
399 > */
400 > didHide(reason?: QuickInputHideReason): void;
401 >
402 > /**
403 > * Notifies that the quick input will be hidden.
404 > * @param reason The reason why the quick input will be hidden.
405 > */
406 > willHide(reason?: QuickInputHideReason): void;
407 > }
408 >
409 > export interface IQuickWidget extends IQuickInput {
410 >
411 > /**
412 > * The type of the quick input.
413 > */
414 > readonly type: QuickInputType.QuickWidget;
415 >
416 > /**
417 > * A HTML element that will be rendered inside the quick input.
418 > */
419 > widget: unknown /* HTMLElement */ | undefined;
420 > }
421 >
422 > export interface IQuickPickWillAcceptEvent {
423 >
424 > /**
425 > * Allows to disable the default accept handling
426 > * of the picker. If `veto` is called, the picker
427 > * will not trigger the `onDidAccept` event.
428 > */
429 > veto(): void;
430 > }
431 >
432 > export interface IQuickPickDidAcceptEvent {
433 >
434 > /**
435 > * Signals if the picker item is to be accepted
436 > * in the background while keeping the picker open.
437 > */
438 > inBackground: boolean;
439 > }
440 >
441 > /**
442 > * Represents the activation behavior for items in a quick input. This means which item will be
443 > * "active" (aka focused).
444 > */
445 > export enum ItemActivation {
446 > /**
447 > * No item will be active.
448 > */
449 > NONE,
450 > /**
451 > * First item will be active.
452 > */
453 > FIRST,
454 > /**
455 > * Second item will be active.
456 > */
457 > SECOND,
458 > /**
459 > * Last item will be active.
460 > */
461 > LAST
462 > }
463 >
464 > /**
465 > * Represents the focus options for a quick pick.
466 > */
467 > export enum QuickPickFocus {
468 > /**
469 > * Focus the first item in the list.
470 > */
471 > First = 1,
472 > /**
473 > * Focus the second item in the list.
474 > */
475 > Second,
476 > /**
477 > * Focus the last item in the list.
478 > */
479 > Last,
480 > /**
481 > * Focus the next item in the list.
482 > */
483 > Next,
484 > /**
485 > * Focus the previous item in the list.
486 > */
487 > Previous,
488 > /**
489 > * Focus the next page in the list.
490 > */
491 > NextPage,
492 > /**
493 > * Focus the previous page in the list.
494 > */
495 > PreviousPage,
496 > /**
497 > * Focus the first item under the next separator.
498 > */
499 > NextSeparator,
500 > /**
501 > * Focus the first item under the current separator.
502 > */
503 > PreviousSeparator
504 > }
505 >
506 > /**
507 > * Represents a quick pick control that allows the user to select an item from a list of options.
508 > */
509 > export interface IQuickPick<T extends IQuickPickItem, O extends { useSeparators: boolean } = { useSeparators: false }> extends IQuickInput {
510 >
511 > /**
512 > * The type of the quick input.
513 > */
514 > readonly type: QuickInputType.QuickPick;
515 >
516 > /**
517 > * The current value of the quick pick input.
518 > */
519 > value: string;
520 >
521 > /**
522 > * A method that allows to massage the value used for filtering, e.g, to remove certain parts.
523 > * @param value The value to be filtered.
524 > * @returns The filtered value.
525 > */
526 > filterValue: (value: string) => string;
527 >
528 > /**
529 > * The ARIA label for the quick pick input.
530 > */
531 > ariaLabel: string | undefined;
532 >
533 > /**
534 > * The placeholder text for the quick pick input.
535 > */
536 > placeholder: string | undefined;
537 >
538 > /**
539 > * Text shown below the quick pick input.
540 > */
541 > prompt: string | undefined;
542 >
543 > /**
544 > * An event that is fired when the value of the quick pick input changes.
545 > */
546 > readonly onDidChangeValue: Event<string>;
547 >
548 > /**
549 > * An event that is fired when the quick pick is about to accept the selected item.
550 > */
551 > readonly onWillAccept: Event<IQuickPickWillAcceptEvent>;
552 >
553 > /**
554 > * An event that is fired when the quick pick has accepted the selected item.
555 > */
556 > readonly onDidAccept: Event<IQuickPickDidAcceptEvent>;
557 >
558 > /**
559 > * If enabled, the `onDidAccept` event will be fired when pressing the arrow-right key to accept the selected item without closing the picker.
560 > */
561 > canAcceptInBackground: boolean;
562 >
563 > /**
564 > * The OK button state. It can be a boolean value or the string 'default'.
565 > */
566 > ok: boolean | 'default';
567 >
568 > /**
569 > * The OK button label.
570 > */
571 > okLabel: string | undefined;
572 >
573 > /**
574 > * An event that is fired when the custom button is triggered. The custom button is a button with text rendered to the right of the input.
575 > */
576 > readonly onDidCustom: Event<void>;
577 >
578 > /**
579 > * Whether to show the custom button. The custom button is a button with text rendered to the right of the input.
580 > */
581 > customButton: boolean;
582 >
583 > /**
584 > * The label for the custom button. The custom button is a button with text rendered to the right of the input.
585 > */
586 > customLabel: string | undefined;
587 >
588 > /**
589 > * The hover text for the custom button. The custom button is a button with text rendered to the right of the input.
590 > */
591 > customHover: string | undefined;
592 >
593 > /**
594 > * Whether the custom button should be rendered as a secondary button.
595 > */
596 > customButtonSecondary?: boolean;
597 >
598 > /**
599 > * An event that is fired when an item button is triggered.
600 > */
601 > readonly onDidTriggerItemButton: Event<IQuickPickItemButtonEvent<T>>;
602 >
603 > /**
604 > * An event that is fired when a separator button is triggered.
605 > */
606 > readonly onDidTriggerSeparatorButton: Event<IQuickPickSeparatorButtonEvent>;
607 >
608 > /**
609 > * The items to be displayed in the quick pick.
610 > */
611 > items: O extends { useSeparators: true } ? ReadonlyArray<T | IQuickPickSeparator> : ReadonlyArray<T>;
612 >
613 > /**
614 > * Whether multiple items can be selected. If so, checkboxes will be rendered.
615 > */
616 > canSelectMany: boolean;
617 >
618 > /**
619 > * Whether to match on the description of the items.
620 > */
621 > matchOnDescription: boolean;
622 >
623 > /**
624 > * Whether to match on the detail of the items.
625 > */
626 > matchOnDetail: boolean;
627 >
628 > /**
629 > * Whether to match on the label of the items.
630 > */
631 > matchOnLabel: boolean;
632 >
633 > /**
634 > * The mode to filter the label with. It can be 'fuzzy' or 'contiguous'. Defaults to 'fuzzy'.
635 > */
636 > matchOnLabelMode: 'fuzzy' | 'contiguous';
637 >
638 > /**
639 > * Whether to sort the items by label.
640 > */
641 > sortByLabel: boolean;
642 >
643 > /**
644 > * Whether to keep the scroll position when the quick pick input is updated.
645 > */
646 > keepScrollPosition: boolean;
647 >
648 > /**
649 > * The configuration for quick navigation.
650 > */
651 > quickNavigate: IQuickNavigateConfiguration | undefined;
652 >
653 > /**
654 > * The currently active items.
655 > */
656 > activeItems: ReadonlyArray<T>;
657 >
658 > /**
659 > * An event that is fired when the active items change.
660 > */
661 > readonly onDidChangeActive: Event<T[]>;
662 >
663 > /**
664 > * The item activation behavior for the next time `items` is set. Item activation means which
665 > * item is "active" (aka focused) when the quick pick is opened or when `items` is set.
666 > */
667 > itemActivation: ItemActivation;
668 >
669 > /**
670 > * The currently selected items.
671 > */
672 > selectedItems: ReadonlyArray<T>;
673 >
674 > /**
675 > * An event that is fired when the selected items change.
676 > */
677 > readonly onDidChangeSelection: Event<T[]>;
678 >
679 > /**
680 > * The key modifiers.
681 > */
682 > readonly keyMods: IKeyMods;
683 >
684 > /**
685 > * The selection range for the value in the input.
686 > */
687 > valueSelection: Readonly<[number, number]> | undefined;
688 >
689 > /**
690 > * The validation message for the quick pick. This is rendered below the input.
691 > */
692 > validationMessage: string | undefined;
693 >
694 > /**
695 > * The severity of the validation message.
696 > */
697 > severity: Severity;
698 >
699 > /**
700 > * Checks if the quick pick input has focus.
701 > * @returns `true` if the quick pick input has focus, `false` otherwise.
702 > */
703 > inputHasFocus(): boolean;
704 >
705 > /**
706 > * Focuses on the quick pick input.
707 > */
708 > focusOnInput(): void;
709 >
710 > /**
711 > * Hides the input box from the picker UI. This is typically used in combination with quick-navigation where no search UI should be presented.
712 > */
713 > hideInput: boolean;
714 >
715 > /**
716 > * Controls whether the count for the items should be shown.
717 > */
718 > hideCountBadge: boolean;
719 >
720 > /**
721 > * Whether to hide the "Check All" checkbox.
722 > */
723 > hideCheckAll: boolean;
724 >
725 > /**
726 > * Focus a particular item in the list. Used internally for keyboard navigation.
727 > * @param focus The focus behavior.
728 > */
729 > focus(focus: QuickPickFocus): void;
730 >
731 > /**
732 > * Programmatically accepts an item. Used internally for keyboard navigation.
733 > * @param inBackground Whether you are accepting an item in the background and keeping the picker open.
734 > */
735 > accept(inBackground?: boolean): void;
736 > }
737 >
738 > /**
739 > * Represents an input box in a quick input dialog.
740 > */
741 > export interface IInputBox extends IQuickInput {
742 >
743 > /**
744 > * The type of the quick input.
745 > */
746 > readonly type: QuickInputType.InputBox;
747 >
748 > /**
749 > * Value shown in the input box.
750 > */
751 > value: string;
752 >
753 > /**
754 > * Provide start and end values to be selected in the input box.
755 > */
756 > valueSelection: Readonly<[number, number]> | undefined;
757 >
758 > /**
759 > * Value shown as example for input.
760 > */
761 > placeholder: string | undefined;
762 >
763 > /**
764 > * Determines if the input value should be hidden while typing.
765 > */
766 > password: boolean;
767 >
768 > /**
769 > * Event called when the input value changes.
770 > */
771 > readonly onDidChangeValue: Event<string>;
772 >
773 > /**
774 > * Event called when the user submits the input.
775 > */
776 > readonly onDidAccept: Event<void>;
777 >
778 > /**
779 > * Text show below the input box.
780 > */
781 > prompt: string | undefined;
782 >
783 > /**
784 > * An optional validation message indicating a problem with the current input value.
785 > * Returning undefined clears the validation message.
786 > */
787 > validationMessage: string | undefined;
788 >
789 > /**
790 > * Severity of the input validation message.
791 > */
792 > severity: Severity;
793 >
794 > /**
795 > * Programmatically accepts an item. Used internally for keyboard navigation.
796 > */
797 > accept(): void;
798 > }
799 >
800 > export enum QuickInputButtonLocation {
801 > /**
802 > * In the title bar.
803 > */
804 > Title = 1,
805 >
806 > /**
807 > * To the right of the input box.
808 > */
809 > Inline = 2,
810 >
811 > /**
812 > * At the far end inside the input box.
813 > * Used by the public API to create toggles.
814 > */
815 > Input = 3,
816 > }
817 >
818 > /**
819 > * Represents a button in the quick input UI.
820 > */
821 > export interface IQuickInputButton {
822 > /**
823 > * The path to the icon for the button.
824 > * Either `iconPath` or `iconClass` is required.
825 > */
826 > iconPath?: { dark: URI; light?: URI };
827 > /**
828 > * The CSS class for the icon of the button.
829 > * Either `iconPath` or `iconClass` is required.
830 > */
831 > iconClass?: string;
832 > /**
833 > * The tooltip text for the button.
834 > */
835 > tooltip?: string;
836 > /**
837 > * Whether to always show the button.
838 > * By default, buttons are only visible when hovering over them with the mouse.
839 > */
840 > alwaysVisible?: boolean;
841 > /**
842 > * Where the button should be rendered. The default is {@link QuickInputButtonLocation.Title}.
843 > * @note This property is ignored if the button was added to a QuickPickItem.
844 > */
845 > location?: QuickInputButtonLocation;
846 > /**
847 > * When present, indicates that the button is a toggle button that can be checked or unchecked.
848 > * The `checked` property indicates the current state of the toggle and will be updated
849 > * when the button is clicked.
850 > */
851 > readonly toggle?: { checked: boolean };
852 > /**
853 > * Optional label for the button. When used with secondary actions, this label appears in the overflow menu.
854 > */
855 > label?: string;
856 > /**
857 > * When true, the button will be rendered as a secondary action in the toolbar overflow menu.
858 > * By default, buttons are rendered as primary actions.
859 > * @note This does not currently apply to buttons in the Input location
860 > */
861 > secondary?: boolean;
862 > }
863 >
864 > export interface IQuickInputButtonWithToggle extends IQuickInputButton {
865 > readonly toggle: { checked: boolean };
866 > }
867 >
868 > /**
869 > * Represents an event that occurs when a button associated with a quick pick item is clicked.
870 > * @template T - The type of the quick pick item.
871 > */
872 > export interface IQuickPickItemButtonEvent<T extends IQuickPickItem> {
873 > /**
874 > * The button that was clicked.
875 > */
876 > button: IQuickInputButton;
877 > /**
878 > * The quick pick item associated with the button.
879 > */
880 > item: T;
881 > }
882 >
883 > /**
884 > * Represents an event that occurs when a separator button is clicked in a quick pick.
885 > */
886 > export interface IQuickPickSeparatorButtonEvent {
887 > /**
888 > * The button that was clicked.
889 > */
890 > button: IQuickInputButton;
891 > /**
892 > * The separator associated with the button.
893 > */
894 > separator: IQuickPickSeparator;
895 > }
896 >
897 > /**
898 > * Represents a context for a button associated with a quick pick item.
899 > * @template T - The type of the quick pick item.
900 > */
901 > export interface IQuickPickItemButtonContext<T extends IQuickPickItem> extends IQuickPickItemButtonEvent<T> {
902 > /**
903 > * Removes the associated item from the quick pick.
904 > */
905 > removeItem(): void;
906 > }
907 >
908 > export type QuickPickInput<T = IQuickPickItem> = T | IQuickPickSeparator;
909 >
910 >
911 > //#region Fuzzy Scorer Support
912 >
913 > export type IQuickPickItemWithResource = IQuickPickItem & { resource?: URI };
914 >
915 > export class QuickPickItemScorerAccessor implements IItemAccessor<IQuickPickItemWithResource> {
916 >
917 > constructor(private options?: { skipDescription?: boolean; skipPath?: boolean }) { }
918 >
919 > getItemLabel(entry: IQuickPickItemWithResource): string {
920 return entry.label;
921 }
923 > getItemDescription(entry: IQuickPickItemWithResource): string | undefined {
924 if (this.options?.skipDescription) {
925 return undefined;
928 return entry.description;
929 }
931 > getItemPath(entry: IQuickPickItemWithResource): string | undefined {
932 if (this.options?.skipPath) {
933 return undefined;
940 return entry.resource?.path;
941 }
942 > } quickInput.ts
943 >
944 > export const quickPickItemScorerAccessor = new QuickPickItemScorerAccessor();
945 >
946 > //#endregion
947 >
948 > export const IQuickInputService = createDecorator<IQuickInputService>('quickInputService');
949 >
950 > export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
951 >
952 > export type QuickInputAlignment = 'top' | 'center' | 'custom';
953 >
954 > export interface IQuickInputService {
955 >
956 > readonly _serviceBrand: undefined;
957 >
958 > /**
959 > * Provides access to the back button in quick input.
960 > */
961 > readonly backButton: IQuickInputButton;
962 >
963 > /**
964 > * Provides access to the quick access providers.
965 > */
966 > readonly quickAccess: IQuickAccessController;
967 >
968 > /**
969 > * Allows to register on the event that quick input is showing.
970 > */
971 > readonly onShow: Event<void>;
972 >
973 > /**
974 > * Allows to register on the event that quick input is hiding.
975 > */
976 > readonly onHide: Event<void>;
977 >
978 > /**
979 > * The current alignment of the quick input widget.
980 > */
981 > readonly alignment: IObservable<QuickInputAlignment>;
982 >
983 > /**
984 > * Opens the quick input box for selecting items and returns a promise
985 > * with the user selected item(s) if any.
986 > */
987 > pick<T extends IQuickPickItem>(picks: Promise<QuickPickInput<T>[]> | QuickPickInput<T>[], options?: IPickOptions<T> & { canPickMany: true }, token?: CancellationToken): Promise<T[] | undefined>;
988 > pick<T extends IQuickPickItem>(picks: Promise<QuickPickInput<T>[]> | QuickPickInput<T>[], options?: IPickOptions<T> & { canPickMany: false }, token?: CancellationToken): Promise<T | undefined>;
989 > pick<T extends IQuickPickItem>(picks: Promise<QuickPickInput<T>[]> | QuickPickInput<T>[], options?: Omit<IPickOptions<T>, 'canPickMany'>, token?: CancellationToken): Promise<T | undefined>;
990 >
991 > /**
992 > * Opens the quick input box for text input and returns a promise with the user typed value if any.
993 > */
994 > input(options?: IInputOptions, token?: CancellationToken): Promise<string | undefined>;
995 >
996 > /**
997 > * Provides raw access to the quick pick controller.
998 > */
999 > createQuickPick<T extends IQuickPickItem>(options: { useSeparators: true }): IQuickPick<T, { useSeparators: true }>;
1000 > createQuickPick<T extends IQuickPickItem>(options?: { useSeparators: boolean }): IQuickPick<T, { useSeparators: false }>;
1001 >
1002 > /**
1003 > * Provides raw access to the input box controller.
1004 > */
1005 > createInputBox(): IInputBox;
1006 >
1007 > /**
1008 > * Provides raw access to the quick widget controller.
1009 > */
1010 > createQuickWidget(): IQuickWidget;
1011 >
1012 > /**
1013 > * Provides raw access to the quick tree controller.
1014 > * @template T The type of items in the quick tree.
1015 > */
1016 > createQuickTree<T extends IQuickTreeItem>(): IQuickTree<T>;
1017 >
1018 > /**
1019 > * Moves focus into quick input.
1020 > */
1021 > focus(): void;
1022 >
1023 > /**
1024 > * Toggle the checked state of the selected item.
1025 > */
1026 > toggle(): void;
1027 >
1028 > /**
1029 > * Navigate inside the opened quick input list.
1030 > */
1031 > navigate(next: boolean, quickNavigate?: IQuickNavigateConfiguration): void;
1032 >
1033 > /**
1034 > * Navigate back in a multi-step quick input.
1035 > */
1036 > back(): Promise<void>;
1037 >
1038 > /**
1039 > * Accept the selected item.
1040 > *
1041 > * @param keyMods allows to override the state of key
1042 > * modifiers that should be present when invoking.
1043 > */
1044 > accept(keyMods?: IKeyMods): Promise<void>;
1045 >
1046 > /**
1047 > * Cancels quick input and closes it.
1048 > */
1049 > cancel(reason?: QuickInputHideReason): Promise<void>;
1050 >
1051 > /**
1052 > * Toggles hover for the current quick input item
1053 > */
1054 > toggleHover(): void;
1055 >
1056 > /**
1057 > * The current quick pick that is visible. Undefined if none is open.
1058 > */
1059 > currentQuickInput: IQuickInput | undefined;
1060 >
1061 > /**
1062 > * Set the alignment of the quick input.
1063 > * @param alignment either a preset or a custom alignment
1064 > */
1065 > setAlignment(alignment: 'top' | 'center' | { top: number; left: number }): void;
1066 > }
1067 >
1068 > //#region Quick Tree
1069 >
1070 > /**
1071 > * Represents a quick tree control that displays hierarchical data with checkboxes.
1072 > */
1073 > export interface IQuickTree<T extends IQuickTreeItem> extends IQuickInput {
1074 >
1075 > /**
1076 > * The type of the quick input.
1077 > */
1078 > readonly type: QuickInputType.QuickTree;
1079 >
1080 > /**
1081 > * The current value of the quick tree filter input.
1082 > */
1083 > value: string;
1084 >
1085 > /**
1086 > * The ARIA label for the quick tree input.
1087 > */
1088 > ariaLabel: string | undefined;
1089 >
1090 > /**
1091 > * The placeholder text for the quick tree filter input.
1092 > */
1093 > placeholder: string | undefined;
1094 >
1095 > /**
1096 > * An event that is fired when the filter value changes.
1097 > */
1098 > readonly onDidChangeValue: Event<string>;
1099 >
1100 > /**
1101 > * An event that is fired when the quick tree has accepted the selected items.
1102 > */
1103 > readonly onDidAccept: Event<void>;
1104 >
1105 > /**
1106 > * Whether to match on the description of the items.
1107 > */
1108 > matchOnDescription: boolean;
1109 >
1110 > /**
1111 > * Whether to match on the label of the items.
1112 > */
1113 > matchOnLabel: boolean;
1114 >
1115 > /**
1116 > * Whether to sort the items by label. Defaults to true.
1117 > */
1118 > sortByLabel: boolean;
1119 >
1120 > /**
1121 > * The currently active items.
1122 > */
1123 > activeItems: ReadonlyArray<T>;
1124 >
1125 > /**
1126 > * The validation message for the quick pick. This is rendered below the input.
1127 > */
1128 > validationMessage: string | undefined;
1129 >
1130 > /**
1131 > * The severity of the validation message.
1132 > */
1133 > severity: Severity;
1134 >
1135 > /**
1136 > * The items currently displayed in the quick tree.
1137 > * @note modifications to this array directly will not cause updates.
1138 > */
1139 > readonly itemTree: ReadonlyArray<Readonly<T>>;
1140 >
1141 > /**
1142 > * The currently selected leaf items.
1143 > */
1144 > readonly checkedLeafItems: ReadonlyArray<T>;
1145 >
1146 > /**
1147 > * Get the parent element of the element passed in
1148 > * @param element
1149 > */
1150 > getParent(element: T): T | undefined;
1151 >
1152 > /**
1153 > * An event that is fired when the active items change.
1154 > */
1155 > readonly onDidChangeActive: Event<ReadonlyArray<T>>;
1156 >
1157 > /**
1158 > * An event that is fired when the selected items change.
1159 > */
1160 > readonly onDidChangeCheckedLeafItems: Event<ReadonlyArray<T>>;
1161 >
1162 > /**
1163 > * An event that is fired when the checkbox state of an item changes.
1164 > */
1165 > readonly onDidChangeCheckboxState: Event<T>;
1166 >
1167 > /**
1168 > * An event that is fired when an item button is triggered.
1169 > */
1170 > readonly onDidTriggerItemButton: Event<IQuickTreeItemButtonEvent<T>>;
1171 >
1172 > /**
1173 > * Sets the items to be displayed in the quick tree.
1174 > * @param itemTree The items to display.
1175 > */
1176 > setItemTree(itemTree: T[]): void;
1177 >
1178 > /**
1179 > * Expands an item.
1180 > * @param element The item to expand.
1181 > */
1182 > expand(element: T): void;
1183 >
1184 > /**
1185 > * Collapses an item.
1186 > * @param element The item to collapse.
1187 > */
1188 > collapse(element: T): void;
1189 >
1190 > /**
1191 > * Checks if an item is collapsed.
1192 > * @param element The item to check.
1193 > * @returns True if the item is collapsed.
1194 > */
1195 > isCollapsed(element: T): boolean;
1196 >
1197 > /**
1198 > * Focuses on the tree input.
1199 > */
1200 > focusOnInput(): void;
1201 >
1202 > /**
1203 > * Reveals and focuses a specific item in the tree.
1204 > * @param element The item to reveal and focus.
1205 > */
1206 > reveal(element: T): void;
1207 >
1208 > /**
1209 > * Focus a particular item in the list. Used internally for keyboard navigation.
1210 > * @param focus The focus behavior.
1211 > */
1212 > focus(focus: QuickPickFocus): void;
1213 >
1214 > /**
1215 > * Programmatically accepts an item. Used internally for keyboard navigation.
1216 > * @param inBackground Whether you are accepting an item in the background and keeping the picker open.
1217 > */
1218 > accept(inBackground?: boolean): void;
1219 > }
1220 >
1221 > /**
1222 > * Represents a tree item in the quick tree.
1223 > */
1224 > export interface IQuickTreeItem extends IQuickItem {
1225 > /**
1226 > * The checked state of the item. Can be true, false, or 'mixed' for tri-state.
1227 > * When canSelectMany is false, this is ignored and the item is treated as a single selection.
1228 > * When canSelectMany is true, this indicates the checkbox state of the item.
1229 > * If undefined, the item is unchecked by default.
1230 > */
1231 > checked?: boolean | 'mixed';
1232 >
1233 > /**
1234 > * The collapsible state of the tree item. Defaults to 'Expanded' if children are present.
1235 > */
1236 > collapsed?: boolean;
1237 >
1238 > /**
1239 > * The children of this tree item.
1240 > */
1241 > children?: readonly IQuickTreeItem[];
1242 >
1243 > /**
1244 > * Defaults to true, can be false to disable picks for a single item.
1245 > * When false, the item is not selectable and does not respond to mouse/keyboard activation.
1246 > */
1247 > pickable?: boolean;
1248 > }
1249 >
1250 > /**
1251 > * Represents an event that occurs when the checkbox state of a tree item changes.
1252 > * @template T - The type of the tree item.
1253 > */
1254 > export interface IQuickTreeCheckboxEvent<T extends IQuickTreeItem> {
1255 > /**
1256 > * The tree item whose checkbox state changed.
1257 > */
1258 > item: T;
1259 >
1260 > /**
1261 > * The new checked state.
1262 > */
1263 > checked: boolean | 'mixed';
1264 > }
1265 >
1266 > /**
1267 > * Represents an event that occurs when a button associated with a quick tree item is clicked.
1268 > * @template T - The type of the quick tree item.
1269 > */
1270 > export interface IQuickTreeItemButtonEvent<T extends IQuickTreeItem> {
1271 > /**
1272 > * The button that was clicked.
1273 > */
1274 > button: IQuickInputButton;
1275 > /**
1276 > * The quick tree item associated with the button.
1277 > */
1278 > item: T;
1279 > }
1280 >
1281 > //#endregion
src/vs/platform/terminal/common/terminal.ts 1253 covered LOC · 4 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- terminal.ts
2 > * Copyright (c) Microsoft 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 { IProcessEnvironment, OperatingSystem } from '../../../base/common/platform.js';
8 > import { URI, UriComponents } from '../../../base/common/uri.js';
9 > import { createDecorator } from '../../instantiation/common/instantiation.js';
10 > import { IPtyHostProcessReplayEvent, ISerializedCommandDetectionCapability, ITerminalCapabilityStore, type ITerminalCommand } from './capabilities/capabilities.js';
11 > import { IGetTerminalLayoutInfoArgs, IProcessDetails, ISetTerminalLayoutInfoArgs } from './terminalProcess.js';
12 > import { ThemeIcon } from '../../../base/common/themables.js';
13 > import { ISerializableEnvironmentVariableCollections } from './environmentVariable.js';
14 > import { IWorkspaceFolder } from '../../workspace/common/workspace.js';
15 > import { Registry } from '../../registry/common/platform.js';
16 > import type * as performance from '../../../base/common/performance.js';
17 > import { ILogService } from '../../log/common/log.js';
18 > import type { IAction } from '../../../base/common/actions.js';
19 > import type { IDisposable } from '../../../base/common/lifecycle.js';
20 > import type { SingleOrMany } from '../../../base/common/types.js';
21 >
22 > export const enum TerminalSettingPrefix {
23 > AutomationProfile = 'terminal.integrated.automationProfile.',
24 > DefaultProfile = 'terminal.integrated.defaultProfile.',
25 > Profiles = 'terminal.integrated.profiles.'
26 > }
27 >
28 > export const enum TerminalSettingId {
29 > SendKeybindingsToShell = 'terminal.integrated.sendKeybindingsToShell',
30 > AutomationProfileLinux = 'terminal.integrated.automationProfile.linux',
31 > AutomationProfileMacOs = 'terminal.integrated.automationProfile.osx',
32 > AutomationProfileWindows = 'terminal.integrated.automationProfile.windows',
33 > AgentHostProfileLinux = 'terminal.integrated.agentHostProfile.linux',
34 > AgentHostProfileMacOs = 'terminal.integrated.agentHostProfile.osx',
35 > AgentHostProfileWindows = 'terminal.integrated.agentHostProfile.windows',
36 > ProfilesWindows = 'terminal.integrated.profiles.windows',
37 > ProfilesMacOs = 'terminal.integrated.profiles.osx',
38 > ProfilesLinux = 'terminal.integrated.profiles.linux',
39 > DefaultProfileLinux = 'terminal.integrated.defaultProfile.linux',
40 > DefaultProfileMacOs = 'terminal.integrated.defaultProfile.osx',
41 > DefaultProfileWindows = 'terminal.integrated.defaultProfile.windows',
42 > UseWslProfiles = 'terminal.integrated.useWslProfiles',
43 > TabsDefaultColor = 'terminal.integrated.tabs.defaultColor',
44 > TabsDefaultIcon = 'terminal.integrated.tabs.defaultIcon',
45 > TabsEnabled = 'terminal.integrated.tabs.enabled',
46 > TabsEnableAnimation = 'terminal.integrated.tabs.enableAnimation',
47 > TabsHideCondition = 'terminal.integrated.tabs.hideCondition',
48 > TabsShowActiveTerminal = 'terminal.integrated.tabs.showActiveTerminal',
49 > TabsShowActions = 'terminal.integrated.tabs.showActions',
50 > TabsLocation = 'terminal.integrated.tabs.location',
51 > TabsFocusMode = 'terminal.integrated.tabs.focusMode',
52 > TabsAllowAgentCliTitle = 'terminal.integrated.tabs.allowAgentCliTitle',
53 > MacOptionIsMeta = 'terminal.integrated.macOptionIsMeta',
54 > MacOptionClickForcesSelection = 'terminal.integrated.macOptionClickForcesSelection',
55 > AltClickMovesCursor = 'terminal.integrated.altClickMovesCursor',
56 > CopyOnSelection = 'terminal.integrated.copyOnSelection',
57 > EnableMultiLinePasteWarning = 'terminal.integrated.enableMultiLinePasteWarning',
58 > DrawBoldTextInBrightColors = 'terminal.integrated.drawBoldTextInBrightColors',
59 > FontFamily = 'terminal.integrated.fontFamily',
60 > FontSize = 'terminal.integrated.fontSize',
61 > LetterSpacing = 'terminal.integrated.letterSpacing',
62 > LineHeight = 'terminal.integrated.lineHeight',
63 > MinimumContrastRatio = 'terminal.integrated.minimumContrastRatio',
64 > TabStopWidth = 'terminal.integrated.tabStopWidth',
65 > FastScrollSensitivity = 'terminal.integrated.fastScrollSensitivity',
66 > MouseWheelScrollSensitivity = 'terminal.integrated.mouseWheelScrollSensitivity',
67 > BellDuration = 'terminal.integrated.bellDuration',
68 > FontWeight = 'terminal.integrated.fontWeight',
69 > FontWeightBold = 'terminal.integrated.fontWeightBold',
70 > CursorBlinking = 'terminal.integrated.cursorBlinking',
71 > TextBlinking = 'terminal.integrated.textBlinking',
72 > CursorStyle = 'terminal.integrated.cursorStyle',
73 > CursorStyleInactive = 'terminal.integrated.cursorStyleInactive',
74 > CursorWidth = 'terminal.integrated.cursorWidth',
75 > Scrollback = 'terminal.integrated.scrollback',
76 > DetectLocale = 'terminal.integrated.detectLocale',
77 > DefaultLocation = 'terminal.integrated.defaultLocation',
78 > GpuAcceleration = 'terminal.integrated.gpuAcceleration',
79 > TerminalTitleSeparator = 'terminal.integrated.tabs.separator',
80 > TerminalTitle = 'terminal.integrated.tabs.title',
81 > TerminalDescription = 'terminal.integrated.tabs.description',
82 > RightClickBehavior = 'terminal.integrated.rightClickBehavior',
83 > MiddleClickBehavior = 'terminal.integrated.middleClickBehavior',
84 > Cwd = 'terminal.integrated.cwd',
85 > ConfirmOnExit = 'terminal.integrated.confirmOnExit',
86 > ConfirmOnKill = 'terminal.integrated.confirmOnKill',
87 > EnableBell = 'terminal.integrated.enableBell',
88 > EnableVisualBell = 'terminal.integrated.enableVisualBell',
89 > CommandsToSkipShell = 'terminal.integrated.commandsToSkipShell',
90 > AllowChords = 'terminal.integrated.allowChords',
91 > AllowMnemonics = 'terminal.integrated.allowMnemonics',
92 > TabFocusMode = 'terminal.integrated.tabFocusMode',
93 > EnvMacOs = 'terminal.integrated.env.osx',
94 > EnvLinux = 'terminal.integrated.env.linux',
95 > EnvWindows = 'terminal.integrated.env.windows',
96 > EnvironmentChangesRelaunch = 'terminal.integrated.environmentChangesRelaunch',
97 > ShowExitAlert = 'terminal.integrated.showExitAlert',
98 > SplitCwd = 'terminal.integrated.splitCwd',
99 > WindowsUseConptyDll = 'terminal.integrated.windowsUseConptyDll',
100 > WordSeparators = 'terminal.integrated.wordSeparators',
101 > EnableFileLinks = 'terminal.integrated.enableFileLinks',
102 > AllowedLinkSchemes = 'terminal.integrated.allowedLinkSchemes',
103 > UnicodeVersion = 'terminal.integrated.unicodeVersion',
104 > EnablePersistentSessions = 'terminal.integrated.enablePersistentSessions',
105 > PersistentSessionReviveProcess = 'terminal.integrated.persistentSessionReviveProcess',
106 > HideOnStartup = 'terminal.integrated.hideOnStartup',
107 > HideOnLastClosed = 'terminal.integrated.hideOnLastClosed',
108 > CustomGlyphs = 'terminal.integrated.customGlyphs',
109 > RescaleOverlappingGlyphs = 'terminal.integrated.rescaleOverlappingGlyphs',
110 > PersistentSessionScrollback = 'terminal.integrated.persistentSessionScrollback',
111 > InheritEnv = 'terminal.integrated.inheritEnv',
112 > ShowLinkHover = 'terminal.integrated.showLinkHover',
113 > IgnoreProcessNames = 'terminal.integrated.ignoreProcessNames',
114 > ShellIntegrationEnabled = 'terminal.integrated.shellIntegration.enabled',
115 > ShellIntegrationShowWelcome = 'terminal.integrated.shellIntegration.showWelcome',
116 > ShellIntegrationDecorationsEnabled = 'terminal.integrated.shellIntegration.decorationsEnabled',
117 > ShellIntegrationTimeout = 'terminal.integrated.shellIntegration.timeout',
118 > ShellIntegrationQuickFixEnabled = 'terminal.integrated.shellIntegration.quickFixEnabled',
119 > ShellIntegrationEnvironmentReporting = 'terminal.integrated.shellIntegration.environmentReporting',
120 > EnableImages = 'terminal.integrated.enableImages',
121 > SmoothScrolling = 'terminal.integrated.smoothScrolling',
122 > IgnoreBracketedPasteMode = 'terminal.integrated.ignoreBracketedPasteMode',
123 > FocusAfterRun = 'terminal.integrated.focusAfterRun',
124 > FontLigaturesEnabled = 'terminal.integrated.fontLigatures.enabled',
125 > FontLigaturesFeatureSettings = 'terminal.integrated.fontLigatures.featureSettings',
126 > FontLigaturesFallbackLigatures = 'terminal.integrated.fontLigatures.fallbackLigatures',
127 > EnableKittyKeyboardProtocol = 'terminal.integrated.enableKittyKeyboardProtocol',
128 > EnableWin32InputMode = 'terminal.integrated.enableWin32InputMode',
129 > AllowInUntrustedWorkspace = 'terminal.integrated.allowInUntrustedWorkspace',
130 >
131 > // Developer/debug settings
132 >
133 > /** Simulated latency applied to all calls made to the pty host */
134 > DeveloperPtyHostLatency = 'terminal.integrated.developer.ptyHost.latency',
135 > /** Simulated startup delay of the pty host process */
136 > DeveloperPtyHostStartupDelay = 'terminal.integrated.developer.ptyHost.startupDelay',
137 > /** Shows the textarea element */
138 > DevMode = 'terminal.integrated.developer.devMode'
139 > }
140 >
141 > export const enum PosixShellType {
142 > Bash = 'bash',
143 > Fish = 'fish',
144 > Sh = 'sh',
145 > Csh = 'csh',
146 > Ksh = 'ksh',
147 > Zsh = 'zsh',
148 >
149 > }
150 > export const enum WindowsShellType {
151 > CommandPrompt = 'cmd',
152 > Wsl = 'wsl',
153 > GitBash = 'gitbash',
154 > }
155 >
156 > export const enum GeneralShellType {
157 > Claude = 'claude',
158 > Codex = 'codex',
159 > CommandCode = 'commandcode',
160 > Copilot = 'copilot',
161 > Gemini = 'gemini',
162 > PowerShell = 'pwsh',
163 > Python = 'python',
164 > Julia = 'julia',
165 > NuShell = 'nu',
166 > Node = 'node',
167 > Xonsh = 'xonsh',
168 > }
169 > export type TerminalShellType = PosixShellType | WindowsShellType | GeneralShellType | undefined;
170 >
171 > export interface IRawTerminalInstanceLayoutInfo<T> {
172 > relativeSize: number;
173 > terminal: T;
174 > }
175 > export type ITerminalInstanceLayoutInfoById = IRawTerminalInstanceLayoutInfo<number>;
176 > export type ITerminalInstanceLayoutInfo = IRawTerminalInstanceLayoutInfo<IPtyHostAttachTarget>;
177 >
178 > export interface IRawTerminalTabLayoutInfo<T> {
179 > isActive: boolean;
180 > activePersistentProcessId: number | undefined;
181 > terminals: IRawTerminalInstanceLayoutInfo<T>[];
182 > }
183 >
184 > export type ITerminalTabLayoutInfoById = IRawTerminalTabLayoutInfo<number>;
185 >
186 > export interface IRawTerminalsLayoutInfo<T> {
187 > tabs: IRawTerminalTabLayoutInfo<T>[];
188 > background: T[] | null;
189 > }
190 >
191 > export interface IPtyHostAttachTarget {
192 > id: number;
193 > pid: number;
194 > title: string;
195 > titleSource: TitleEventSource;
196 > cwd: string;
197 > workspaceId: string;
198 > workspaceName: string;
199 > isOrphan: boolean;
200 > icon: TerminalIcon | undefined;
201 > fixedDimensions: IFixedTerminalDimensions | undefined;
202 > environmentVariableCollections: ISerializableEnvironmentVariableCollections | undefined;
203 > reconnectionProperties?: IReconnectionProperties;
204 > waitOnExit?: WaitOnExitValue;
205 > hideFromUser?: boolean;
206 > isFeatureTerminal?: boolean;
207 > type?: TerminalType;
208 > hasChildProcesses: boolean;
209 > shellIntegrationNonce: string;
210 > tabActions?: ITerminalTabAction[];
211 > }
212 >
213 > export interface IReconnectionProperties {
214 > ownerId: string;
215 > data?: unknown;
216 > }
217 >
218 > export type TerminalType = 'Task' | 'Local' | undefined;
219 >
220 > export enum TitleEventSource {
221 > /** From the API or the rename command that overrides any other type */
222 > Api,
223 > /** From the process name property*/
224 > Process,
225 > /** From the VT sequence */
226 > Sequence,
227 > /** Config changed */
228 > Config
229 > }
230 >
231 > export type ITerminalsLayoutInfo = IRawTerminalsLayoutInfo<IPtyHostAttachTarget | null>;
232 > export type ITerminalsLayoutInfoById = IRawTerminalsLayoutInfo<number>;
233 >
234 > export enum TerminalIpcChannels {
235 > /**
236 > * Communicates between the renderer process and shared process.
237 > */
238 > LocalPty = 'localPty',
239 > /**
240 > * Communicates between the shared process and the pty host process.
241 > */
242 > PtyHost = 'ptyHost',
243 > /**
244 > * Communicates between the renderer process and the pty host process.
245 > */
246 > PtyHostWindow = 'ptyHostWindow',
247 > /**
248 > * Deals with logging from the pty host process.
249 > */
250 > Logger = 'logger',
251 > /**
252 > * Enables the detection of unresponsive pty hosts.
253 > */
254 > Heartbeat = 'heartbeat'
255 > }
256 >
257 > export const enum ProcessPropertyType {
258 > Cwd = 'cwd',
259 > InitialCwd = 'initialCwd',
260 > FixedDimensions = 'fixedDimensions',
261 > Title = 'title',
262 > ShellType = 'shellType',
263 > HasChildProcesses = 'hasChildProcesses',
264 > ResolvedShellLaunchConfig = 'resolvedShellLaunchConfig',
265 > OverrideDimensions = 'overrideDimensions',
266 > FailedShellIntegrationActivation = 'failedShellIntegrationActivation',
267 > UsedShellIntegrationInjection = 'usedShellIntegrationInjection',
268 > ShellIntegrationInjectionFailureReason = 'shellIntegrationInjectionFailureReason',
269 > }
270 >
271 > export interface IProcessProperty<T extends ProcessPropertyType = ProcessPropertyType> {
272 > type: T;
273 > value: IProcessPropertyMap[T];
274 > }
275 >
276 > export interface IProcessPropertyMap {
277 > [ProcessPropertyType.Cwd]: string;
278 > [ProcessPropertyType.InitialCwd]: string;
279 > [ProcessPropertyType.FixedDimensions]: IFixedTerminalDimensions;
280 > [ProcessPropertyType.Title]: string;
281 > [ProcessPropertyType.ShellType]: TerminalShellType | undefined;
282 > [ProcessPropertyType.HasChildProcesses]: boolean;
283 > [ProcessPropertyType.ResolvedShellLaunchConfig]: IShellLaunchConfig;
284 > [ProcessPropertyType.OverrideDimensions]: ITerminalDimensionsOverride | undefined;
285 > [ProcessPropertyType.FailedShellIntegrationActivation]: boolean | undefined;
286 > [ProcessPropertyType.UsedShellIntegrationInjection]: boolean | undefined;
287 > [ProcessPropertyType.ShellIntegrationInjectionFailureReason]: ShellIntegrationInjectionFailureReason | undefined;
288 > }
289 >
290 > export interface IFixedTerminalDimensions {
291 > /**
292 > * The fixed columns of the terminal.
293 > */
294 > cols?: number;
295 >
296 > /**
297 > * The fixed rows of the terminal.
298 > */
299 > rows?: number;
300 > }
301 >
302 > export interface ITerminalLaunchResult {
303 > injectedArgs: string[];
304 > }
305 >
306 > /**
307 > * A service that communicates with a pty host.
308 > */
309 > export interface IPtyService {
310 > readonly _serviceBrand: undefined;
311 >
312 > readonly onProcessData: Event<{ id: number; event: IProcessDataEvent | string }>;
313 > readonly onProcessReady: Event<{ id: number; event: IProcessReadyEvent }>;
314 > readonly onProcessReplay: Event<{ id: number; event: IPtyHostProcessReplayEvent }>;
315 > readonly onProcessOrphanQuestion: Event<{ id: number }>;
316 > readonly onDidRequestDetach: Event<{ requestId: number; workspaceId: string; instanceId: number }>;
317 > readonly onDidChangeProperty: Event<{ id: number; property: IProcessProperty }>;
318 > readonly onProcessExit: Event<{ id: number; event: number | undefined }>;
319 >
320 > createProcess(
321 > shellLaunchConfig: IShellLaunchConfig,
322 > cwd: string,
323 > cols: number,
324 > rows: number,
325 > unicodeVersion: '6' | '11',
326 > env: IProcessEnvironment,
327 > executableEnv: IProcessEnvironment,
328 > options: ITerminalProcessOptions,
329 > shouldPersist: boolean,
330 > workspaceId: string,
331 > workspaceName: string
332 > ): Promise<number>;
333 > attachToProcess(id: number): Promise<void>;
334 > detachFromProcess(id: number, forcePersist?: boolean): Promise<void>;
335 > shutdownAll(): Promise<void>;
336 >
337 > /**
338 > * Lists all orphaned processes, ie. those without a connected frontend.
339 > */
340 > listProcesses(): Promise<IProcessDetails[]>;
341 > getPerformanceMarks(): Promise<performance.PerformanceMark[]>;
342 > /**
343 > * Measures and returns the latency of the current and all other processes to the pty host.
344 > */
345 > getLatency(): Promise<IPtyHostLatencyMeasurement[]>;
346 >
347 > start(id: number): Promise<ITerminalLaunchError | ITerminalLaunchResult | undefined>;
348 > shutdown(id: number, immediate: boolean): Promise<void>;
349 > input(id: number, data: string): Promise<void>;
350 > sendSignal(id: number, signal: string): Promise<void>;
351 > resize(id: number, cols: number, rows: number, pixelWidth?: number, pixelHeight?: number): Promise<void>;
352 > clearBuffer(id: number): Promise<void>;
353 > getInitialCwd(id: number): Promise<string>;
354 > getCwd(id: number): Promise<string>;
355 > acknowledgeDataEvent(id: number, charCount: number): Promise<void>;
356 > setNextCommandId(id: number, commandLine: string, commandId: string): Promise<void>;
357 > setUnicodeVersion(id: number, version: '6' | '11'): Promise<void>;
358 > processBinary(id: number, data: string): Promise<void>;
359 > /** Confirm the process is _not_ an orphan. */
360 > orphanQuestionReply(id: number): Promise<void>;
361 > updateTitle(id: number, title: string, titleSource: TitleEventSource): Promise<void>;
362 > updateIcon(id: number, userInitiated: boolean, icon: TerminalIcon, color?: string): Promise<void>;
363 >
364 > getDefaultSystemShell(osOverride?: OperatingSystem): Promise<string>;
365 > getEnvironment(): Promise<IProcessEnvironment>;
366 > getWslPath(original: string, direction: 'unix-to-win' | 'win-to-unix'): Promise<string>;
367 > getRevivedPtyNewId(workspaceId: string, id: number): Promise<number | undefined>;
368 > setTerminalLayoutInfo(args: ISetTerminalLayoutInfoArgs): Promise<void>;
369 > getTerminalLayoutInfo(args: IGetTerminalLayoutInfoArgs): Promise<ITerminalsLayoutInfo | undefined>;
370 > reduceConnectionGraceTime(): Promise<void>;
371 > requestDetachInstance(workspaceId: string, instanceId: number): Promise<IProcessDetails | undefined>;
372 > acceptDetachInstanceReply(requestId: number, persistentProcessId?: number): Promise<void>;
373 > freePortKillProcess(port: string): Promise<{ port: string; processId: string }>;
374 > /**
375 > * Serializes and returns terminal state.
376 > * @param ids The persistent terminal IDs to serialize.
377 > */
378 > serializeTerminalState(ids: number[]): Promise<string>;
379 > /**
380 > * Revives a workspaces terminal processes, these can then be reconnected to using the normal
381 > * flow for restoring terminals after reloading.
382 > */
383 > reviveTerminalProcesses(workspaceId: string, state: ISerializedTerminalState[], dateTimeFormatLocate: string): Promise<void>;
384 > refreshProperty<T extends ProcessPropertyType>(id: number, property: T): Promise<IProcessPropertyMap[T]>;
385 > updateProperty<T extends ProcessPropertyType>(id: number, property: T, value: IProcessPropertyMap[T]): Promise<void>;
386 >
387 > // TODO: Make mandatory and remove impl from pty host service
388 > refreshIgnoreProcessNames?(names: string[]): Promise<void>;
389 >
390 > // #region Pty service contribution RPC calls
391 >
392 > installAutoReply(match: string, reply: string): Promise<void>;
393 > uninstallAllAutoReplies(): Promise<void>;
394 >
395 > // #endregion
396 > }
397 > export const IPtyService = createDecorator<IPtyService>('ptyService');
398 >
399 > export interface IPtyServiceContribution {
400 > handleProcessReady(persistentProcessId: number, process: ITerminalChildProcess): void;
401 > handleProcessDispose(persistentProcessId: number): void;
402 > handleProcessInput(persistentProcessId: number, data: string): void;
403 > handleProcessResize(persistentProcessId: number, cols: number, rows: number, pixelWidth?: number, pixelHeight?: number): void;
404 > }
405 >
406 > export interface IPtyHostController {
407 > readonly onPtyHostExit: Event<number>;
408 > readonly onPtyHostStart: Event<void>;
409 > readonly onPtyHostUnresponsive: Event<void>;
410 > readonly onPtyHostResponsive: Event<void>;
411 > readonly onPtyHostRequestResolveVariables: Event<IRequestResolveVariablesEvent>;
412 >
413 > restartPtyHost(): Promise<void>;
414 > acceptPtyHostResolvedVariables(requestId: number, resolved: string[]): Promise<void>;
415 > getProfiles(workspaceId: string, profiles: unknown, defaultProfile: unknown, includeDetectedProfiles?: boolean): Promise<ITerminalProfile[]>;
416 > }
417 >
418 > /**
419 > * A service that communicates with a pty host controller (eg. main or server
420 > * process) and is able to launch and forward requests to the pty host.
421 > */
422 > export interface IPtyHostService extends IPtyService, IPtyHostController {
423 > }
424 >
425 > export interface IPtyHostLatencyMeasurement {
426 > label: string;
427 > latency: number;
428 > }
429 >
430 > /**
431 > * Serialized terminal state matching the interface that can be used across versions, the version
432 > * should be verified before using the state payload.
433 > */
434 > export interface ICrossVersionSerializedTerminalState {
435 > version: number;
436 > state: unknown;
437 > }
438 >
439 > export interface ISerializedTerminalState {
440 > id: number;
441 > shellLaunchConfig: IShellLaunchConfig;
442 > processDetails: IProcessDetails;
443 > processLaunchConfig: IPersistentTerminalProcessLaunchConfig;
444 > unicodeVersion: '6' | '11';
445 > replayEvent: IPtyHostProcessReplayEvent;
446 > timestamp: number;
447 > }
448 >
449 > export interface IPersistentTerminalProcessLaunchConfig {
450 > env: IProcessEnvironment;
451 > executableEnv: IProcessEnvironment;
452 > options: ITerminalProcessOptions;
453 > }
454 >
455 > export interface IRequestResolveVariablesEvent {
456 > requestId: number;
457 > workspaceId: string;
458 > originalText: string[];
459 > }
460 >
461 > export enum HeartbeatConstants {
462 > /**
463 > * The duration between heartbeats
464 > */
465 > BeatInterval = 5000,
466 > /**
467 > * The duration of the first heartbeat while the pty host is starting up. This is much larger
468 > * than the regular BeatInterval to accommodate slow machines, we still want to warn about the
469 > * pty host's unresponsiveness eventually though.
470 > */
471 > ConnectingBeatInterval = 20000,
472 > /**
473 > * Defines a multiplier for BeatInterval for how long to wait before starting the second wait
474 > * timer.
475 > */
476 > FirstWaitMultiplier = 1.2,
477 > /**
478 > * Defines a multiplier for BeatInterval for how long to wait before telling the user about
479 > * non-responsiveness. The second timer is to avoid informing the user incorrectly when waking
480 > * the computer up from sleep
481 > */
482 > SecondWaitMultiplier = 1,
483 > /**
484 > * How long to wait before telling the user about non-responsiveness when they try to create a
485 > * process. This short circuits the standard wait timeouts to tell the user sooner and only
486 > * create process is handled to avoid additional perf overhead.
487 > */
488 > CreateProcessTimeout = 5000
489 > }
490 >
491 > export interface IHeartbeatService {
492 > readonly onBeat: Event<void>;
493 > }
494 >
495 >
496 > export interface IShellLaunchConfig {
497 > /**
498 > * The name of the terminal, if this is not set the name of the process will be used.
499 > */
500 > name?: string;
501 >
502 > /**
503 > * A string to follow the name of the terminal with, indicating the type of terminal
504 > */
505 > type?: 'Task' | 'Local';
506 >
507 > /**
508 > * The shell executable (bash, cmd, etc.).
509 > */
510 > executable?: string;
511 >
512 > /**
513 > * The CLI arguments to use with executable, a string[] is in argv format and will be escaped,
514 > * a string is in "CommandLine" pre-escaped format and will be used as is. The string option is
515 > * only supported on Windows and will throw an exception if used on macOS or Linux.
516 > */
517 > args?: string[] | string;
518 >
519 > /**
520 > * The current working directory of the terminal, this overrides the `terminal.integrated.cwd`
521 > * settings key.
522 > */
523 > cwd?: string | URI;
524 >
525 > /**
526 > * A custom environment for the terminal, if this is not set the environment will be inherited
527 > * from the VS Code process.
528 > */
529 > env?: ITerminalEnvironment;
530 >
531 > /**
532 > * Whether to ignore a custom cwd from the `terminal.integrated.cwd` settings key (e.g. if the
533 > * shell is being launched by an extension).
534 > */
535 > ignoreConfigurationCwd?: boolean;
536 >
537 > /**
538 > * The reconnection properties for this terminal
539 > */
540 > reconnectionProperties?: IReconnectionProperties;
541 >
542 > /** Whether to wait for a key press before closing the terminal. */
543 > waitOnExit?: WaitOnExitValue;
544 >
545 > /**
546 > * A string including ANSI escape sequences that will be written to the terminal emulator
547 > * _before_ the terminal process has launched, when a string is specified, a trailing \n is
548 > * added at the end. This allows for example the terminal instance to display a styled message
549 > * as the first line of the terminal. Use \x1b over \033 or \e for the escape control character.
550 > */
551 > initialText?: string | { text: string; trailingNewLine: boolean };
552 >
553 > /**
554 > * Custom PTY/pseudoterminal process to use.
555 > */
556 > customPtyImplementation?: (terminalId: number, cols: number, rows: number) => ITerminalChildProcess;
557 >
558 > /**
559 > * A UUID generated by the extension host process for terminals created on the extension host process.
560 > */
561 > extHostTerminalId?: string;
562 >
563 > /**
564 > * This is a terminal that attaches to an already running terminal.
565 > */
566 > attachPersistentProcess?: {
567 > id: number;
568 > findRevivedId?: boolean;
569 > pid: number;
570 > title: string;
571 > titleSource: TitleEventSource;
572 > cwd: string;
573 > icon?: TerminalIcon;
574 > color?: string;
575 > hasChildProcesses?: boolean;
576 > fixedDimensions?: IFixedTerminalDimensions;
577 > environmentVariableCollections?: ISerializableEnvironmentVariableCollections;
578 > reconnectionProperties?: IReconnectionProperties;
579 > type?: TerminalType;
580 > waitOnExit?: WaitOnExitValue;
581 > hideFromUser?: boolean;
582 > isFeatureTerminal?: boolean;
583 > shellIntegrationNonce: string;
584 > tabActions?: ITerminalTabAction[];
585 > };
586 >
587 > /**
588 > * Whether the terminal process environment should be exactly as provided in
589 > * `TerminalOptions.env`. When this is false (default), the environment will be based on the
590 > * window's environment and also apply configured platform settings like
591 > * `terminal.integrated.env.windows` on top. When this is true, the complete environment must be
592 > * provided as nothing will be inherited from the process or any configuration.
593 > */
594 > strictEnv?: boolean;
595 >
596 > /**
597 > * Whether the terminal process environment will inherit VS Code's "shell environment" that may
598 > * get sourced from running a login shell depnding on how the application was launched.
599 > * Consumers that rely on development tools being present in the $PATH should set this to true.
600 > * This will overwrite the value of the inheritEnv setting.
601 > */
602 > useShellEnvironment?: boolean;
603 >
604 > /**
605 > * When enabled the terminal will run the process as normal but not be surfaced to the user
606 > * until `Terminal.show` is called. The typical usage for this is when you need to run
607 > * something that may need interactivity but only want to tell the user about it when
608 > * interaction is needed. Note that the terminals will still be exposed to all extensions
609 > * as normal. The hidden terminals will not be restored when the workspace is next opened.
610 > */
611 > hideFromUser?: boolean;
612 >
613 > /**
614 > * Whether to force the terminal to persist across sessions regardless of the other
615 > * launch config, like `hideFromUser`.
616 > */
617 > forcePersist?: boolean;
618 >
619 > /**
620 > * Whether this terminal is not a terminal that the user directly created and uses, but rather
621 > * a terminal used to drive some VS Code feature.
622 > */
623 > isFeatureTerminal?: boolean;
624 >
625 > /**
626 > * Whether this terminal was created by an extension.
627 > */
628 > isExtensionOwnedTerminal?: boolean;
629 >
630 > /**
631 > * The icon for the terminal, used primarily in the terminal tab.
632 > */
633 > icon?: TerminalIcon;
634 >
635 > /**
636 > * The color ID to use for this terminal. If not specified it will use the default fallback
637 > */
638 > color?: string;
639 >
640 > /**
641 > * When a parent terminal is provided via API, the group needs
642 > * to find the index in order to place the child
643 > * directly to the right of its parent.
644 > */
645 > parentTerminalId?: number;
646 >
647 > /**
648 > * The dimensions for the instance as set by the user
649 > * or via Size to Content Width
650 > */
651 > fixedDimensions?: IFixedTerminalDimensions;
652 >
653 > /**
654 > * Opt-out of the default terminal persistence on restart and reload
655 > */
656 > isTransient?: boolean;
657 >
658 > /**
659 > * Attempt to force shell integration to be enabled by bypassing the {@link isFeatureTerminal}
660 > * equals false requirement.
661 > */
662 > forceShellIntegration?: boolean;
663 >
664 > /**
665 > * Create a terminal without shell integration even when it's enabled
666 > */
667 > ignoreShellIntegration?: boolean;
668 >
669 > /**
670 > * Actions to include inline on hover of the terminal tab. E.g. the "Rerun task" action
671 > */
672 > tabActions?: ITerminalTabAction[];
673 > /**
674 > * Report terminal's shell environment variables to VS Code and extensions
675 > */
676 > shellIntegrationEnvironmentReporting?: boolean;
677 >
678 > /**
679 > * A custom nonce to use for shell integration when provided by an extension.
680 > * This allows extensions to control shell integration for terminals they create.
681 > */
682 > shellIntegrationNonce?: string;
683 >
684 > /**
685 > * A title template string that supports the same variables as the
686 > * `terminal.integrated.tabs.title` setting. When set, this overrides the config-based
687 > * title template for this terminal instance.
688 > */
689 > titleTemplate?: string;
690 > }
691 >
692 > export interface ITerminalTabAction {
693 > id: string;
694 > label: string;
695 > icon?: ThemeIcon;
696 > }
697 >
698 > export type WaitOnExitValue = boolean | string | ((exitCode: number) => string);
699 >
700 > export interface ICreateContributedTerminalProfileOptions {
701 > icon?: URI | string | { light: URI; dark: URI };
702 > color?: string;
703 > location?: TerminalLocation | { viewColumn: number; preserveState?: boolean } | { splitActiveTerminal: boolean };
704 > cwd?: string | URI;
705 > titleTemplate?: string;
706 > }
707 >
708 > export enum TerminalLocation {
709 > Panel = 1,
710 > Editor = 2
711 > }
712 >
713 > export const enum TerminalLocationConfigValue {
714 > TerminalView = 'view',
715 > Editor = 'editor'
716 > }
717 >
718 > export type TerminalIcon = ThemeIcon | URI | { light: URI; dark: URI };
719 >
720 > export interface IShellLaunchConfigDto {
721 > name?: string;
722 > executable?: string;
723 > args?: string[] | string;
724 > cwd?: string | UriComponents;
725 > env?: ITerminalEnvironment;
726 > useShellEnvironment?: boolean;
727 > hideFromUser?: boolean;
728 > reconnectionProperties?: IReconnectionProperties;
729 > type?: 'Task' | 'Local';
730 > isFeatureTerminal?: boolean;
731 > forceShellIntegration?: boolean;
732 > tabActions?: ITerminalTabAction[];
733 > shellIntegrationEnvironmentReporting?: boolean;
734 > titleTemplate?: string;
735 > }
736 >
737 > /**
738 > * A set of options for the terminal process. These differ from the shell launch config in that they
739 > * are set internally to the terminal component, not from the outside.
740 > */
741 > export interface ITerminalProcessOptions {
742 > shellIntegration: {
743 > enabled: boolean;
744 > suggestEnabled: boolean;
745 > nonce: string;
746 > };
747 > windowsUseConptyDll: boolean;
748 > environmentVariableCollections: ISerializableEnvironmentVariableCollections | undefined;
749 > workspaceFolder: IWorkspaceFolder | undefined;
750 > isScreenReaderOptimized: boolean;
751 > }
752 >
753 > export interface ITerminalEnvironment {
754 > [key: string]: string | null | undefined;
755 > }
756 >
757 > export interface ITerminalLaunchError {
758 > message: string;
759 > code?: number;
760 > }
761 >
762 > export interface IProcessReadyEvent {
763 > pid: number;
764 > cwd: string;
765 > windowsPty: IProcessReadyWindowsPty | undefined;
766 > }
767 >
768 > export interface IProcessReadyWindowsPty {
769 > /**
770 > * What pty emulation backend is being used.
771 > */
772 > backend: 'conpty';
773 > /**
774 > * The Windows build version (eg. 19045)
775 > */
776 > buildNumber: number;
777 > }
778 >
779 > /**
780 > * An interface representing a raw terminal child process, this contains a subset of the
781 > * child_process.ChildProcess node.js interface.
782 > */
783 > export interface ITerminalChildProcess {
784 > /**
785 > * A unique identifier for the terminal process. Note that the uniqueness only applies to a
786 > * given pty service connection, IDs will be duplicated for remote and local terminals for
787 > * example. The ID will be 0 if it does not support reconnection.
788 > */
789 > id: number;
790 >
791 > /**
792 > * Whether the process should be persisted across reloads.
793 > */
794 > shouldPersist: boolean;
795 >
796 > readonly onProcessData: Event<IProcessDataEvent | string>;
797 > readonly onProcessReady: Event<IProcessReadyEvent>;
798 > readonly onProcessReplayComplete?: Event<void>;
799 > readonly onDidChangeProperty: Event<IProcessProperty>;
800 > readonly onProcessExit: Event<number | undefined>;
801 > readonly onRestoreCommands?: Event<ISerializedCommandDetectionCapability>;
802 >
803 > /**
804 > * Starts the process.
805 > *
806 > * @returns undefined when the process was successfully started, otherwise an object containing
807 > * information on what went wrong.
808 > */
809 > start(): Promise<ITerminalLaunchError | ITerminalLaunchResult | undefined>;
810 >
811 > /**
812 > * Detach the process from the UI and await reconnect.
813 > * @param forcePersist Whether to force the process to persist if it supports persistence.
814 > */
815 > detach?(forcePersist?: boolean): Promise<void>;
816 >
817 > /**
818 > * Frees the port and kills the process
819 > */
820 > freePortKillProcess?(port: string): Promise<{ port: string; processId: string }>;
821 >
822 > /**
823 > * Shutdown the terminal process.
824 > *
825 > * @param immediate When true the process will be killed immediately, otherwise the process will
826 > * be given some time to make sure no additional data comes through.
827 > */
828 > shutdown(immediate: boolean): void;
829 > input(data: string): void;
830 > sendSignal(signal: string): void;
831 > processBinary(data: string): Promise<void>;
832 > resize(cols: number, rows: number, pixelWidth?: number, pixelHeight?: number): void;
833 > clearBuffer(): void | Promise<void>;
834 >
835 > /**
836 > * Acknowledge a data event has been parsed by the terminal, this is used to implement flow
837 > * control to ensure remote processes to not get too far ahead of the client and flood the
838 > * connection.
839 > * @param charCount The number of characters being acknowledged.
840 > */
841 > acknowledgeDataEvent(charCount: number): void;
842 >
843 > /**
844 > * Sets the unicode version for the process, this drives the size of some characters in the
845 > * xterm-headless instance.
846 > */
847 > setUnicodeVersion(version: '6' | '11'): Promise<void>;
848 >
849 > getInitialCwd(): Promise<string>;
850 > getCwd(): Promise<string>;
851 > refreshProperty<T extends ProcessPropertyType>(property: T): Promise<IProcessPropertyMap[T]>;
852 > updateProperty<T extends ProcessPropertyType>(property: T, value: IProcessPropertyMap[T]): Promise<void>;
853 > }
854 >
855 > export interface IReconnectConstants {
856 > graceTime: number;
857 > shortGraceTime: number;
858 > scrollback: number;
859 > }
860 >
861 > export const enum LocalReconnectConstants {
862 > /**
863 > * If there is no reconnection within this time-frame, consider the connection permanently closed...
864 > */
865 > GraceTime = 60000, // 60 seconds
866 > /**
867 > * Maximal grace time between the first and the last reconnection...
868 > */
869 > ShortGraceTime = 6000, // 6 seconds
870 > }
871 >
872 > export const enum FlowControlConstants {
873 > /**
874 > * The number of _unacknowledged_ chars to have been sent before the pty is paused in order for
875 > * the client to catch up.
876 > */
877 > HighWatermarkChars = 100000,
878 > /**
879 > * After flow control pauses the pty for the client the catch up, this is the number of
880 > * _unacknowledged_ chars to have been caught up to on the client before resuming the pty again.
881 > * This is used to attempt to prevent pauses in the flowing data; ideally while the pty is
882 > * paused the number of unacknowledged chars would always be greater than 0 or the client will
883 > * appear to stutter. In reality this balance is hard to accomplish though so heavy commands
884 > * will likely pause as latency grows, not flooding the connection is the important thing as
885 > * it's shared with other core functionality.
886 > */
887 > LowWatermarkChars = 5000,
888 > /**
889 > * The number characters that are accumulated on the client side before sending an ack event.
890 > * This must be less than or equal to LowWatermarkChars or the terminal max never unpause.
891 > */
892 > CharCountAckSize = 5000
893 > }
894 >
895 > export interface IProcessDataEvent {
896 > data: string;
897 > trackCommit: boolean;
898 > /**
899 > * When trackCommit is set, this will be set to a promise that resolves when the data is parsed.
900 > */
901 > writePromise?: Promise<void>;
902 > }
903 >
904 > export interface ITerminalDimensions {
905 > /**
906 > * The columns of the terminal.
907 > */
908 > cols: number;
909 >
910 > /**
911 > * The rows of the terminal.
912 > */
913 > rows: number;
914 > }
915 >
916 > export interface ITerminalProfile {
917 > profileName: string;
918 > path: string;
919 > isDefault: boolean;
920 > /**
921 > * Whether the terminal profile contains a potentially unsafe {@link path}. For example, the path
922 > * `C:\Cygwin` is the default install for Cygwin on Windows, but it could be created by any
923 > * user in a multi-user environment. As such, we don't want to blindly present it as a profile
924 > * without a warning.
925 > */
926 > isUnsafePath?: boolean;
927 > /**
928 > * An additional unsafe path that must exist, for example a script that appears in {@link args}.
929 > */
930 > requiresUnsafePath?: string;
931 > isAutoDetected?: boolean;
932 > /**
933 > * Whether the profile path was found on the `$PATH` environment variable, if so it will be
934 > * cleaner to display this profile in the UI using only `basename(path)`.
935 > */
936 > isFromPath?: boolean;
937 > args?: SingleOrMany<string> | undefined;
938 > env?: ITerminalEnvironment;
939 > overrideName?: boolean;
940 > color?: string;
941 > icon?: ThemeIcon | URI | { light: URI; dark: URI };
942 > }
943 >
944 > export interface ITerminalDimensionsOverride extends Readonly<ITerminalDimensions> {
945 > /**
946 > * indicate that xterm must receive these exact dimensions, even if they overflow the ui!
947 > */
948 > forceExactSize?: boolean;
949 > }
950 >
951 > export const enum ProfileSource {
952 > GitBash = 'Git Bash',
953 > Pwsh = 'PowerShell'
954 > }
955 >
956 > export interface IBaseUnresolvedTerminalProfile {
957 > args?: SingleOrMany<string> | undefined;
958 > isAutoDetected?: boolean;
959 > overrideName?: boolean;
960 > icon?: string | ThemeIcon | URI | { light: URI; dark: URI };
961 > color?: string;
962 > env?: ITerminalEnvironment;
963 > requiresPath?: string | ITerminalUnsafePath;
964 > }
965 >
966 > export interface ITerminalUnsafePath {
967 > path: string;
968 > isUnsafe: true;
969 > }
970 >
971 > export interface ITerminalExecutable extends IBaseUnresolvedTerminalProfile {
972 > path: SingleOrMany<string | ITerminalUnsafePath>;
973 > }
974 >
975 > export interface ITerminalProfileSource extends IBaseUnresolvedTerminalProfile {
976 > source: ProfileSource;
977 > }
978 >
979 > export interface ITerminalProfileContribution {
980 > title: string;
981 > id: string;
982 > icon?: URI | { light: URI; dark: URI } | string;
983 > color?: string;
984 > titleTemplate?: string;
985 > }
986 >
987 > export interface IExtensionTerminalProfile extends ITerminalProfileContribution {
988 > extensionIdentifier: string;
989 > }
990 >
991 > export type ITerminalProfileObject = ITerminalExecutable | ITerminalProfileSource | IExtensionTerminalProfile | null;
992 >
993 > export interface IShellIntegration {
994 > readonly capabilities: ITerminalCapabilityStore;
995 > readonly seenSequences: ReadonlySet<string>;
996 > readonly status: ShellIntegrationStatus;
997 >
998 > readonly onDidChangeStatus: Event<ShellIntegrationStatus>;
999 > readonly onDidChangeSeenSequences: Event<ReadonlySet<string>>;
1000 >
1001 > deserialize(serialized: ISerializedCommandDetectionCapability): void;
1002 >
1003 > setNextCommandId(command: string, commandId: string): void;
1004 > }
1005 >
1006 > export interface IDecorationAddon {
1007 > registerMenuItems(command: ITerminalCommand, items: IAction[]): IDisposable;
1008 > }
1009 >
1010 > export interface ITerminalCompletionProviderContribution {
1011 > description?: string;
1012 > }
1013 >
1014 > export interface ITerminalContributions {
1015 > profiles?: ITerminalProfileContribution[];
1016 > completionProviders?: ITerminalCompletionProviderContribution[];
1017 > }
1018 >
1019 > export const enum ShellIntegrationStatus {
1020 > /** No shell integration sequences have been encountered. */
1021 > Off,
1022 > /** Final term shell integration sequences have been encountered. */
1023 > FinalTerm,
1024 > /** VS Code shell integration sequences have been encountered. Supercedes FinalTerm. */
1025 > VSCode
1026 > }
1027 >
1028 >
1029 > export const enum ShellIntegrationInjectionFailureReason {
1030 > /**
1031 > * The setting is disabled.
1032 > */
1033 > InjectionSettingDisabled = 'injectionSettingDisabled',
1034 > /**
1035 > * There is no executable (so there's no way to determine how to inject).
1036 > */
1037 > NoExecutable = 'noExecutable',
1038 > /**
1039 > * It's a feature terminal (tasks, debug), unless it's explicitly being forced.
1040 > */
1041 > FeatureTerminal = 'featureTerminal',
1042 > /**
1043 > * The ignoreShellIntegration flag is passed (eg. relaunching without shell integration).
1044 > */
1045 > IgnoreShellIntegrationFlag = 'ignoreShellIntegrationFlag',
1046 > /**
1047 > * Shell integration doesn't work on older Windows builds that don't support ConPTY.
1048 > */
1049 > UnsupportedWindowsBuild = 'unsupportedWindowsBuild',
1050 > /**
1051 > * We're conservative whether we inject when we don't recognize the arguments used for the
1052 > * shell as we would prefer launching one without shell integration than breaking their profile.
1053 > */
1054 > UnsupportedArgs = 'unsupportedArgs',
1055 > /**
1056 > * The shell doesn't have built-in shell integration. Note that this doesn't mean the shell
1057 > * won't have shell integration in the end.
1058 > */
1059 > UnsupportedShell = 'unsupportedShell',
1060 >
1061 >
1062 > /**
1063 > * For zsh, we failed to set the sticky bit on the shell integration script folder.
1064 > */
1065 > FailedToSetStickyBit = 'failedToSetStickyBit',
1066 >
1067 > /**
1068 > * For zsh, we failed to create a temp directory for the shell integration script.
1069 > */
1070 > FailedToCreateTmpDir = 'failedToCreateTmpDir',
1071 > }
1072 >
1073 > export const enum ShellIntegrationTimeoutOverride {
1074 > DisableForTests = -2
1075 > }
1076 >
1077 > export enum TerminalExitReason {
1078 > Unknown = 0,
1079 > Shutdown = 1,
1080 > Process = 2,
1081 > User = 3,
1082 > Extension = 4,
1083 > }
1084 >
1085 > export interface ITerminalOutputMatch {
1086 > regexMatch: RegExpMatchArray;
1087 > outputLines: string[];
1088 > }
1089 >
1090 > /**
1091 > * A matcher that runs on a sub-section of a terminal command's output
1092 > */
1093 > export interface ITerminalOutputMatcher {
1094 > /**
1095 > * A string or regex to match against the unwrapped line. If this is a regex with the multiline
1096 > * flag, it will scan an amount of lines equal to `\n` instances in the regex + 1.
1097 > */
1098 > lineMatcher: string | RegExp;
1099 > /**
1100 > * Which side of the output to anchor the {@link offset} and {@link length} against.
1101 > */
1102 > anchor: 'top' | 'bottom';
1103 > /**
1104 > * The number of rows above or below the {@link anchor} to start matching against.
1105 > */
1106 > offset: number;
1107 > /**
1108 > * The number of rows to match against, this should be as small as possible for performance
1109 > * reasons. This is capped at 40.
1110 > */
1111 > length: number;
1112 >
1113 > /**
1114 > * If multiple matches are expected - this will result in {@link outputLines} being returned
1115 > * when there's a {@link regexMatch} from {@link offset} to {@link length}
1116 > */
1117 > multipleMatches?: boolean;
1118 > }
1119 >
1120 > export interface ITerminalCommandSelector {
1121 > id: string;
1122 > commandLineMatcher: string | RegExp;
1123 > outputMatcher?: ITerminalOutputMatcher;
1124 > exitStatus: boolean;
1125 > commandExitResult: 'success' | 'error';
1126 > kind?: 'fix' | 'explain';
1127 > }
1128 >
1129 > export interface ITerminalBackend extends ITerminalBackendPtyServiceContributions {
1130 > readonly remoteAuthority: string | undefined;
1131 >
1132 > readonly isResponsive: boolean;
1133 >
1134 > /**
1135 > * A promise that resolves when the backend is ready to be used, ie. after terminal persistence
1136 > * has been actioned.
1137 > */
1138 > readonly whenReady: Promise<void>;
1139 >
1140 > /**
1141 > * Signal to the backend that persistence has been actioned and is ready for use.
1142 > */
1143 > setReady(): void;
1144 >
1145 > /**
1146 > * Fired when the ptyHost process becomes non-responsive, this should disable stdin for all
1147 > * terminals using this pty host connection and mark them as disconnected.
1148 > */
1149 > readonly onPtyHostUnresponsive: Event<void>;
1150 > /**
1151 > * Fired when the ptyHost process becomes responsive after being non-responsive. Allowing
1152 > * previously disconnected terminals to reconnect.
1153 > */
1154 > readonly onPtyHostResponsive: Event<void>;
1155 > /**
1156 > * Fired when the ptyHost has been restarted, this is used as a signal for listening terminals
1157 > * that its pty has been lost and will remain disconnected.
1158 > */
1159 > readonly onPtyHostRestart: Event<void>;
1160 >
1161 > readonly onDidRequestDetach: Event<{ requestId: number; workspaceId: string; instanceId: number }>;
1162 >
1163 > attachToProcess(id: number): Promise<ITerminalChildProcess | undefined>;
1164 > attachToRevivedProcess(id: number): Promise<ITerminalChildProcess | undefined>;
1165 > listProcesses(): Promise<IProcessDetails[]>;
1166 > getLatency(): Promise<IPtyHostLatencyMeasurement[]>;
1167 > getDefaultSystemShell(osOverride?: OperatingSystem): Promise<string>;
1168 > getProfiles(profiles: unknown, defaultProfile: unknown, includeDetectedProfiles?: boolean): Promise<ITerminalProfile[]>;
1169 > getWslPath(original: string, direction: 'unix-to-win' | 'win-to-unix'): Promise<string>;
1170 > getEnvironment(): Promise<IProcessEnvironment>;
1171 > getShellEnvironment(): Promise<IProcessEnvironment | undefined>;
1172 > setTerminalLayoutInfo(layoutInfo?: ITerminalsLayoutInfoById): Promise<void>;
1173 > updateTitle(id: number, title: string, titleSource: TitleEventSource): Promise<void>;
1174 > updateIcon(id: number, userInitiated: boolean, icon: TerminalIcon, color?: string): Promise<void>;
1175 > setNextCommandId(id: number, commandLine: string, commandId: string): Promise<void>;
1176 > getTerminalLayoutInfo(): Promise<ITerminalsLayoutInfo | undefined>;
1177 > getPerformanceMarks(): Promise<performance.PerformanceMark[]>;
1178 > reduceConnectionGraceTime(): Promise<void>;
1179 > requestDetachInstance(workspaceId: string, instanceId: number): Promise<IProcessDetails | undefined>;
1180 > acceptDetachInstanceReply(requestId: number, persistentProcessId?: number): Promise<void>;
1181 > persistTerminalState(): Promise<void>;
1182 >
1183 > createProcess(
1184 > shellLaunchConfig: IShellLaunchConfig,
1185 > cwd: string,
1186 > cols: number,
1187 > rows: number,
1188 > unicodeVersion: '6' | '11',
1189 > env: IProcessEnvironment,
1190 > options: ITerminalProcessOptions,
1191 > shouldPersist: boolean
1192 > ): Promise<ITerminalChildProcess>;
1193 >
1194 > restartPtyHost(): void;
1195 > }
1196 >
1197 > export interface ITerminalBackendPtyServiceContributions {
1198 > installAutoReply(match: string, reply: string): Promise<void>;
1199 > uninstallAllAutoReplies(): Promise<void>;
1200 > }
1201 >
1202 > export const TerminalExtensions = {
1203 > Backend: 'workbench.contributions.terminal.processBackend'
1204 > };
1205 >
1206 > export interface ITerminalBackendRegistry {
1207 > /**
1208 > * Gets all backends in the registry.
1209 > */
1210 > backends: ReadonlyMap<string, ITerminalBackend>;
1211 >
1212 > /**
1213 > * Registers a terminal backend for a remote authority.
1214 > */
1215 > registerTerminalBackend(backend: ITerminalBackend): void;
1216 >
1217 > /**
1218 > * Returns the registered terminal backend for a remote authority.
1219 > */
1220 > getTerminalBackend(remoteAuthority?: string): ITerminalBackend | undefined;
1221 > }
1222 >
1223 > class TerminalBackendRegistry implements ITerminalBackendRegistry {
1224 > private readonly _backends = new Map<string, ITerminalBackend>();
1225 >
1226 > get backends(): ReadonlyMap<string, ITerminalBackend> { return this._backends; }
1227 >
1228 > registerTerminalBackend(backend: ITerminalBackend): void {
1229 const key = this._sanitizeRemoteAuthority(backend.remoteAuthority);
1230 if (this._backends.has(key)) {
1233 this._backends.set(key, backend);
1234 }
1235 > terminal.ts
1236 > getTerminalBackend(remoteAuthority: string | undefined): ITerminalBackend | undefined {
1237 return this._backends.get(this._sanitizeRemoteAuthority(remoteAuthority));
1238 }
1239 > terminal.ts
1240 > private _sanitizeRemoteAuthority(remoteAuthority: string | undefined) {
1241 // Normalize the key to lowercase as the authority is case-insensitive
1242 return remoteAuthority?.toLowerCase() ?? '';
1243 }
1244 > } terminal.ts
1245 > Registry.add(TerminalExtensions.Backend, new TerminalBackendRegistry());
1246 >
1247 > export const ILocalPtyService = createDecorator<ILocalPtyService>('localPtyService');
1248 >
1249 > /**
1250 > * A service responsible for communicating with the pty host process on Electron.
1251 > *
1252 > * **This service should only be used within the terminal component.**
1253 > */
1254 > export interface ILocalPtyService extends IPtyHostService { }
1255 >
1256 > export const ITerminalLogService = createDecorator<ITerminalLogService>('terminalLogService');
1257 > export interface ITerminalLogService extends ILogService {
1258 > /**
1259 > * Similar to _serviceBrand but used to differentiate this service at compile time from
1260 > * ILogService; ITerminalLogService is an ILogService, but ILogService is not an
1261 > * ITerminalLogService.
1262 > */
1263 > readonly _logBrand: undefined;
1264 > }
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/oauth.ts 1122 covered LOC · 68 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- oauth.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { decodeBase64 } from './buffer.js';
7 >
8 > const WELL_KNOWN_ROUTE = '/.well-known';
9 > export const AUTH_PROTECTED_RESOURCE_METADATA_DISCOVERY_PATH = `${WELL_KNOWN_ROUTE}/oauth-protected-resource`;
10 > export const AUTH_SERVER_METADATA_DISCOVERY_PATH = `${WELL_KNOWN_ROUTE}/oauth-authorization-server`;
11 > export const OPENID_CONNECT_DISCOVERY_PATH = `${WELL_KNOWN_ROUTE}/openid-configuration`;
12 > export const AUTH_SCOPE_SEPARATOR = ' ';
13 >
14 > /**
15 > * RFC 8693 grant type for OAuth token exchange.
16 > */
17 > export const GRANT_TYPE_TOKEN_EXCHANGE = 'urn:ietf:params:oauth:grant-type:token-exchange';
18 >
19 > /**
20 > * RFC 8693 token type for an OAuth 2.0 access token used as the `subject_token`
21 > * during a token exchange.
22 > */
23 > export const TOKEN_TYPE_ACCESS_TOKEN = 'urn:ietf:params:oauth:token-type:access_token';
24 >
25 > /**
26 > * Token type for an OpenID Connect ID Token. Used as the `subject_token_type` in
27 > * the IdP-side token exchange that mints an ID-JAG.
28 > */
29 > export const TOKEN_TYPE_ID_TOKEN = 'urn:ietf:params:oauth:token-type:id_token';
30 >
31 > /**
32 > * Token type for an Identity Assertion Authorization Grant (ID-JAG) used in
33 > * Cross App Access (XAA) flows.
34 > */
35 > export const TOKEN_TYPE_ID_JAG = 'urn:ietf:params:oauth:token-type:id-jag';
36 >
37 > /**
38 > * RFC 7523 grant type used to exchange a JWT assertion (e.g. an ID-JAG) for an
39 > * access token at the resource's authorization server.
40 > */
41 > export const GRANT_TYPE_JWT_BEARER = 'urn:ietf:params:oauth:grant-type:jwt-bearer';
42 >
43 > /**
44 > * Build the request body for the IdP-side token exchange that mints an ID-JAG
45 > * for the requested audience. See draft-ietf-oauth-identity-assertion-authz-grant.
46 > *
47 > * @param clientId the requesting app's client_id at the IdP.
48 > * @param clientSecret the requesting app's client_secret at the IdP, if applicable.
49 > * Omit (or pass `undefined`) for public clients (`token_endpoint_auth_method=none`).
50 > * @param idToken the OpenID Connect `id_token` previously issued by the IdP to
51 > * the requesting app. Per the spec the subject token MUST be an ID Token
52 > * (not an access token).
53 > * @param audience the *authorization server* URL of the resource (the issuer
54 > * that will redeem the ID-JAG). Required.
55 > * @param resource the resource indicator (RFC 8707) — the URL of the actual
56 > * protected resource (e.g. the MCP server URL). Optional but typically required
57 > * in practice.
58 > * @param scopes scopes the requesting app wants granted at the resource.
59 > */
60 > export function buildIdJagExchangeBody(clientId: string, clientSecret: string | undefined, idToken: string, audience: string, resource: string | undefined, scopes: readonly string[]): URLSearchParams {
61 const body = new URLSearchParams();
62 body.append('client_id', clientId);
77 return body;
78 }
79 > oauth.ts
80 > /**
81 > * Build the request body sent to a resource server's authorization server to
82 > * redeem an ID-JAG for a resource-scoped access token (RFC 7523 JWT-bearer grant).
83 > */
84 > export function buildResourceRedemptionBody(clientId: string, clientSecret: string | undefined, idJag: string, resource: string | undefined, scopes: readonly string[]): URLSearchParams {
85 const body = new URLSearchParams();
86 body.append('client_id', clientId);
98 return body;
99 }
100 > oauth.ts
101 > //#region types
102 >
103 > /**
104 > * Base OAuth 2.0 error codes as specified in RFC 6749.
105 > */
106 > export const enum AuthorizationErrorType {
107 > InvalidRequest = 'invalid_request',
108 > InvalidClient = 'invalid_client',
109 > InvalidGrant = 'invalid_grant',
110 > UnauthorizedClient = 'unauthorized_client',
111 > UnsupportedGrantType = 'unsupported_grant_type',
112 > InvalidScope = 'invalid_scope'
113 > }
114 >
115 > /**
116 > * Device authorization grant specific error codes as specified in RFC 8628 section 3.5.
117 > */
118 > export const enum AuthorizationDeviceCodeErrorType {
119 > /**
120 > * The authorization request is still pending as the end user hasn't completed the user interaction steps.
121 > */
122 > AuthorizationPending = 'authorization_pending',
123 > /**
124 > * A variant of "authorization_pending", polling should continue but interval must be increased by 5 seconds.
125 > */
126 > SlowDown = 'slow_down',
127 > /**
128 > * The authorization request was denied.
129 > */
130 > AccessDenied = 'access_denied',
131 > /**
132 > * The "device_code" has expired and the device authorization session has concluded.
133 > */
134 > ExpiredToken = 'expired_token'
135 > }
136 >
137 > /**
138 > * Dynamic client registration specific error codes as specified in RFC 7591.
139 > */
140 > export const enum AuthorizationRegistrationErrorType {
141 > /**
142 > * The value of one or more redirection URIs is invalid.
143 > */
144 > InvalidRedirectUri = 'invalid_redirect_uri',
145 > /**
146 > * The value of one of the client metadata fields is invalid and the server has rejected this request.
147 > */
148 > InvalidClientMetadata = 'invalid_client_metadata',
149 > /**
150 > * The software statement presented is invalid.
151 > */
152 > InvalidSoftwareStatement = 'invalid_software_statement',
153 > /**
154 > * The software statement presented is not approved for use by this authorization server.
155 > */
156 > UnapprovedSoftwareStatement = 'unapproved_software_statement'
157 > }
158 >
159 > /**
160 > * Metadata about a protected resource.
161 > */
162 > export interface IAuthorizationProtectedResourceMetadata {
163 > /**
164 > * REQUIRED. The protected resource's resource identifier URL that uses https scheme and has no fragment components.
165 > */
166 > resource: string;
167 >
168 > /**
169 > * OPTIONAL. Human-readable name of the protected resource intended for display to the end user.
170 > */
171 > resource_name?: string;
172 >
173 > /**
174 > * OPTIONAL. JSON array containing a list of OAuth authorization server identifiers.
175 > */
176 > authorization_servers?: string[];
177 >
178 > /**
179 > * OPTIONAL. URL of the protected resource's JWK Set document.
180 > */
181 > jwks_uri?: string;
182 >
183 > /**
184 > * RECOMMENDED. JSON array containing a list of the OAuth 2.0 scope values used in authorization requests.
185 > */
186 > scopes_supported?: string[];
187 >
188 > /**
189 > * OPTIONAL. JSON array containing a list of the OAuth 2.0 Bearer Token presentation methods supported.
190 > */
191 > bearer_methods_supported?: string[];
192 >
193 > /**
194 > * OPTIONAL. JSON array containing a list of the JWS signing algorithms supported.
195 > */
196 > resource_signing_alg_values_supported?: string[];
197 >
198 > /**
199 > * OPTIONAL. JSON array containing a list of the JWE encryption algorithms supported.
200 > */
201 > resource_encryption_alg_values_supported?: string[];
202 >
203 > /**
204 > * OPTIONAL. JSON array containing a list of the JWE encryption algorithms supported.
205 > */
206 > resource_encryption_enc_values_supported?: string[];
207 >
208 > /**
209 > * OPTIONAL. URL of a page containing human-readable documentation.
210 > */
211 > resource_documentation?: string;
212 >
213 > /**
214 > * OPTIONAL. URL that provides the resource's requirements on how clients can use the data.
215 > */
216 > resource_policy_uri?: string;
217 >
218 > /**
219 > * OPTIONAL. URL that provides the resource's terms of service.
220 > */
221 > resource_tos_uri?: string;
222 > }
223 >
224 > /**
225 > * Metadata about an OAuth 2.0 Authorization Server.
226 > */
227 > export interface IAuthorizationServerMetadata {
228 > /**
229 > * REQUIRED. The authorization server's issuer identifier URL that uses https scheme and has no query or fragment components.
230 > */
231 > issuer: string;
232 >
233 > /**
234 > * URL of the authorization server's authorization endpoint.
235 > * This is REQUIRED unless no grant types are supported that use the authorization endpoint.
236 > */
237 > authorization_endpoint?: string;
238 >
239 > /**
240 > * URL of the authorization server's token endpoint.
241 > * This is REQUIRED unless only the implicit grant type is supported.
242 > */
243 > token_endpoint?: string;
244 >
245 > /**
246 > * OPTIONAL. URL of the authorization server's device code endpoint.
247 > */
248 > device_authorization_endpoint?: string;
249 >
250 > /**
251 > * OPTIONAL. URL of the authorization server's JWK Set document containing signing keys.
252 > */
253 > jwks_uri?: string;
254 >
255 > /**
256 > * OPTIONAL. URL of the authorization server's OAuth 2.0 Dynamic Client Registration endpoint.
257 > */
258 > registration_endpoint?: string;
259 >
260 > /**
261 > * RECOMMENDED. JSON array containing a list of the OAuth 2.0 scope values supported.
262 > */
263 > scopes_supported?: string[];
264 >
265 > /**
266 > * REQUIRED. JSON array containing a list of the OAuth 2.0 response_type values supported.
267 > */
268 > response_types_supported: string[];
269 >
270 > /**
271 > * OPTIONAL. JSON array containing a list of the OAuth 2.0 response_mode values supported.
272 > * Default is ["query", "fragment"].
273 > */
274 > response_modes_supported?: string[];
275 >
276 > /**
277 > * OPTIONAL. JSON array containing a list of OAuth 2.0 grant type values supported.
278 > * Default is ["authorization_code", "implicit"].
279 > */
280 > grant_types_supported?: string[];
281 >
282 > /**
283 > * OPTIONAL. JSON array containing a list of client authentication methods supported by the token endpoint.
284 > * Default is "client_secret_basic".
285 > */
286 > token_endpoint_auth_methods_supported?: string[];
287 >
288 > /**
289 > * OPTIONAL. JSON array containing a list of JWS signing algorithms supported by the token endpoint.
290 > */
291 > token_endpoint_auth_signing_alg_values_supported?: string[];
292 >
293 > /**
294 > * OPTIONAL. URL of a page containing human-readable documentation for developers.
295 > */
296 > service_documentation?: string;
297 >
298 > /**
299 > * OPTIONAL. Languages and scripts supported for the user interface, as a JSON array of BCP 47 language tags.
300 > */
301 > ui_locales_supported?: string[];
302 >
303 > /**
304 > * OPTIONAL. URL that the authorization server provides to read about the authorization server's requirements.
305 > */
306 > op_policy_uri?: string;
307 >
308 > /**
309 > * OPTIONAL. URL that the authorization server provides to read about the authorization server's terms of service.
310 > */
311 > op_tos_uri?: string;
312 >
313 > /**
314 > * OPTIONAL. URL of the authorization server's OAuth 2.0 revocation endpoint.
315 > */
316 > revocation_endpoint?: string;
317 >
318 > /**
319 > * OPTIONAL. JSON array containing a list of client authentication methods supported by the revocation endpoint.
320 > */
321 > revocation_endpoint_auth_methods_supported?: string[];
322 >
323 > /**
324 > * OPTIONAL. JSON array containing a list of JWS signing algorithms supported by the revocation endpoint.
325 > */
326 > revocation_endpoint_auth_signing_alg_values_supported?: string[];
327 >
328 > /**
329 > * OPTIONAL. URL of the authorization server's OAuth 2.0 introspection endpoint.
330 > */
331 > introspection_endpoint?: string;
332 >
333 > /**
334 > * OPTIONAL. JSON array containing a list of client authentication methods supported by the introspection endpoint.
335 > */
336 > introspection_endpoint_auth_methods_supported?: string[];
337 >
338 > /**
339 > * OPTIONAL. JSON array containing a list of JWS signing algorithms supported by the introspection endpoint.
340 > */
341 > introspection_endpoint_auth_signing_alg_values_supported?: string[];
342 >
343 > /**
344 > * OPTIONAL. JSON array containing a list of PKCE code challenge methods supported.
345 > */
346 > code_challenge_methods_supported?: string[];
347 >
348 > /**
349 > * OPTIONAL. Boolean flag indicating whether the authorization server supports the
350 > * client_id_metadata document.
351 > * ref https://datatracker.ietf.org/doc/html/draft-parecki-oauth-client-id-metadata-document-03
352 > */
353 > client_id_metadata_document_supported?: boolean;
354 > }
355 >
356 > /**
357 > * Request for the dynamic client registration endpoint.
358 > * @see https://datatracker.ietf.org/doc/html/rfc7591#section-2
359 > */
360 > export interface IAuthorizationDynamicClientRegistrationRequest {
361 > /**
362 > * OPTIONAL. Array of redirection URI strings for use in redirect-based flows
363 > * such as the authorization code and implicit flows.
364 > */
365 > redirect_uris?: string[];
366 >
367 > /**
368 > * OPTIONAL. String indicator of the requested authentication method for the token endpoint.
369 > * Values: "none", "client_secret_post", "client_secret_basic".
370 > * Default is "client_secret_basic".
371 > */
372 > token_endpoint_auth_method?: string;
373 >
374 > /**
375 > * OPTIONAL. Array of OAuth 2.0 grant type strings that the client can use at the token endpoint.
376 > * Default is ["authorization_code"].
377 > */
378 > grant_types?: string[];
379 >
380 > /**
381 > * OPTIONAL. Array of the OAuth 2.0 response type strings that the client can use at the authorization endpoint.
382 > * Default is ["code"].
383 > */
384 > response_types?: string[];
385 >
386 > /**
387 > * OPTIONAL. Human-readable string name of the client to be presented to the end-user during authorization.
388 > */
389 > client_name?: string;
390 >
391 > /**
392 > * OPTIONAL. URL string of a web page providing information about the client.
393 > */
394 > client_uri?: string;
395 >
396 > /**
397 > * OPTIONAL. URL string that references a logo for the client.
398 > */
399 > logo_uri?: string;
400 >
401 > /**
402 > * OPTIONAL. String containing a space-separated list of scope values that the client can use when requesting access tokens.
403 > */
404 > scope?: string;
405 >
406 > /**
407 > * OPTIONAL. Array of strings representing ways to contact people responsible for this client, typically email addresses.
408 > */
409 > contacts?: string[];
410 >
411 > /**
412 > * OPTIONAL. URL string that points to a human-readable terms of service document for the client.
413 > */
414 > tos_uri?: string;
415 >
416 > /**
417 > * OPTIONAL. URL string that points to a human-readable privacy policy document.
418 > */
419 > policy_uri?: string;
420 >
421 > /**
422 > * OPTIONAL. URL string referencing the client's JSON Web Key (JWK) Set document.
423 > */
424 > jwks_uri?: string;
425 >
426 > /**
427 > * OPTIONAL. Client's JSON Web Key Set document value.
428 > */
429 > jwks?: object;
430 >
431 > /**
432 > * OPTIONAL. A unique identifier string assigned by the client developer or software publisher.
433 > */
434 > software_id?: string;
435 >
436 > /**
437 > * OPTIONAL. A version identifier string for the client software.
438 > */
439 > software_version?: string;
440 >
441 > /**
442 > * OPTIONAL. A software statement containing client metadata values about the client software as claims.
443 > */
444 > software_statement?: string;
445 >
446 > /**
447 > * OPTIONAL. Application type. Usually "native" for OAuth clients.
448 > * https://openid.net/specs/openid-connect-registration-1_0.html
449 > */
450 > application_type?: 'native' | 'web' | string;
451 >
452 > /**
453 > * OPTIONAL. Additional metadata fields as defined by extensions.
454 > */
455 > [key: string]: unknown;
456 > }
457 >
458 > /**
459 > * Response from the dynamic client registration endpoint.
460 > */
461 > export interface IAuthorizationDynamicClientRegistrationResponse {
462 > /**
463 > * REQUIRED. The client identifier issued by the authorization server.
464 > */
465 > client_id: string;
466 >
467 > /**
468 > * OPTIONAL. The client secret issued by the authorization server.
469 > * Not returned for public clients.
470 > */
471 > client_secret?: string;
472 >
473 > /**
474 > * OPTIONAL. Time at which the client secret will expire in seconds since the Unix Epoch.
475 > */
476 > client_secret_expires_at?: number;
477 >
478 > /**
479 > * OPTIONAL. Client name as provided during registration.
480 > */
481 > client_name?: string;
482 >
483 > /**
484 > * OPTIONAL. Client URI as provided during registration.
485 > */
486 > client_uri?: string;
487 >
488 > /**
489 > * OPTIONAL. Array of redirection URIs as provided during registration.
490 > */
491 > redirect_uris?: string[];
492 >
493 > /**
494 > * OPTIONAL. Array of grant types allowed for the client.
495 > */
496 > grant_types?: string[];
497 >
498 > /**
499 > * OPTIONAL. Array of response types allowed for the client.
500 > */
501 > response_types?: string[];
502 >
503 > /**
504 > * OPTIONAL. Type of authentication method used by the client.
505 > */
506 > token_endpoint_auth_method?: string;
507 > }
508 >
509 > /**
510 > * Response from the authorization endpoint.
511 > * Typically returned as query parameters in a redirect.
512 > */
513 > export interface IAuthorizationAuthorizeResponse {
514 > /**
515 > * REQUIRED. The authorization code generated by the authorization server.
516 > */
517 > code: string;
518 >
519 > /**
520 > * REQUIRED. The state value that was sent in the authorization request.
521 > * Used to prevent CSRF attacks.
522 > */
523 > state: string;
524 > }
525 >
526 > /**
527 > * Error response from the authorization endpoint.
528 > */
529 > export interface IAuthorizationAuthorizeErrorResponse {
530 > /**
531 > * REQUIRED. Error code as specified in OAuth 2.0.
532 > */
533 > error: string;
534 >
535 > /**
536 > * OPTIONAL. Human-readable description of the error.
537 > */
538 > error_description?: string;
539 >
540 > /**
541 > * OPTIONAL. URI to a human-readable web page with more information about the error.
542 > */
543 > error_uri?: string;
544 >
545 > /**
546 > * REQUIRED. The state value that was sent in the authorization request.
547 > */
548 > state: string;
549 > }
550 >
551 > /**
552 > * Response from the token endpoint.
553 > */
554 > export interface IAuthorizationTokenResponse {
555 > /**
556 > * REQUIRED. The access token issued by the authorization server.
557 > */
558 > access_token: string;
559 >
560 > /**
561 > * REQUIRED. The type of the token issued. Usually "Bearer".
562 > */
563 > token_type: string;
564 >
565 > /**
566 > * RECOMMENDED. The lifetime in seconds of the access token.
567 > */
568 > expires_in?: number;
569 >
570 > /**
571 > * OPTIONAL. The refresh token, which can be used to obtain new access tokens.
572 > */
573 > refresh_token?: string;
574 >
575 > /**
576 > * OPTIONAL. The scope of the access token as a space-delimited list of strings.
577 > */
578 > scope?: string;
579 >
580 > /**
581 > * OPTIONAL. ID Token value associated with the authenticated session for OpenID Connect flows.
582 > */
583 > id_token?: string;
584 > }
585 >
586 > /**
587 > * Error response from the token endpoint.
588 > */
589 > export interface IAuthorizationTokenErrorResponse {
590 > /**
591 > * REQUIRED. Error code as specified in OAuth 2.0.
592 > */
593 > error: string;
594 >
595 > /**
596 > * OPTIONAL. Human-readable description of the error.
597 > */
598 > error_description?: string;
599 >
600 > /**
601 > * OPTIONAL. URI to a human-readable web page with more information about the error.
602 > */
603 > error_uri?: string;
604 > }
605 >
606 > /**
607 > * Response from the device authorization endpoint as per RFC 8628 section 3.2.
608 > */
609 > export interface IAuthorizationDeviceResponse {
610 > /**
611 > * REQUIRED. The device verification code.
612 > */
613 > device_code: string;
614 >
615 > /**
616 > * REQUIRED. The end-user verification code.
617 > */
618 > user_code: string;
619 >
620 > /**
621 > * REQUIRED. The end-user verification URI on the authorization server.
622 > */
623 > verification_uri: string;
624 >
625 > /**
626 > * OPTIONAL. A verification URI that includes the user_code, designed for non-textual transmission.
627 > */
628 > verification_uri_complete?: string;
629 >
630 > /**
631 > * REQUIRED. The lifetime in seconds of the device_code and user_code.
632 > */
633 > expires_in: number;
634 >
635 > /**
636 > * OPTIONAL. The minimum amount of time in seconds that the client should wait between polling requests.
637 > * If no value is provided, clients must use 5 as the default.
638 > */
639 > interval?: number;
640 > }
641 >
642 > /**
643 > * Error response from the token endpoint when using device authorization grant.
644 > * As defined in RFC 8628 section 3.5.
645 > */
646 > export interface IAuthorizationErrorResponse {
647 > /**
648 > * REQUIRED. Error code as specified in OAuth 2.0 or in RFC 8628 section 3.5.
649 > */
650 > error: AuthorizationErrorType | string;
651 >
652 > /**
653 > * OPTIONAL. Human-readable description of the error.
654 > */
655 > error_description?: string;
656 >
657 > /**
658 > * OPTIONAL. URI to a human-readable web page with more information about the error.
659 > */
660 > error_uri?: string;
661 > }
662 >
663 > /**
664 > * Error response from the token endpoint when using device authorization grant.
665 > * As defined in RFC 8628 section 3.5.
666 > */
667 > export interface IAuthorizationDeviceTokenErrorResponse extends IAuthorizationErrorResponse {
668 > /**
669 > * REQUIRED. Error code as specified in OAuth 2.0 or in RFC 8628 section 3.5.
670 > */
671 > error: AuthorizationErrorType | AuthorizationDeviceCodeErrorType | string;
672 > }
673 >
674 > export interface IAuthorizationRegistrationErrorResponse {
675 > /**
676 > * REQUIRED. Error code as specified in OAuth 2.0 or Dynamic Client Registration.
677 > */
678 > error: AuthorizationRegistrationErrorType | string;
679 >
680 > /**
681 > * OPTIONAL. Human-readable description of the error.
682 > */
683 > error_description?: string;
684 > }
685 >
686 > export interface IAuthorizationJWTClaims {
687 > /**
688 > * REQUIRED. JWT ID. Unique identifier for the token.
689 > */
690 > jti: string;
691 >
692 > /**
693 > * REQUIRED. Subject. Principal about which the token asserts information.
694 > */
695 > sub: string;
696 >
697 > /**
698 > * REQUIRED. Issuer. Entity that issued the token.
699 > */
700 > iss: string;
701 >
702 > /**
703 > * OPTIONAL. Audience. Recipients that the token is intended for.
704 > */
705 > aud?: string | string[];
706 >
707 > /**
708 > * OPTIONAL. Expiration time. Time after which the token is invalid (seconds since Unix epoch).
709 > */
710 > exp?: number;
711 >
712 > /**
713 > * OPTIONAL. Not before time. Time before which the token is not valid (seconds since Unix epoch).
714 > */
715 > nbf?: number;
716 >
717 > /**
718 > * OPTIONAL. Issued at time when the token was issued (seconds since Unix epoch).
719 > */
720 > iat?: number;
721 >
722 > /**
723 > * OPTIONAL. Authorized party. The party to which the token was issued.
724 > */
725 > azp?: string;
726 >
727 > /**
728 > * OPTIONAL. Scope values for which the token is valid.
729 > */
730 > scope?: string;
731 >
732 > /**
733 > * OPTIONAL. Full name of the user.
734 > */
735 > name?: string;
736 >
737 > /**
738 > * OPTIONAL. Given or first name of the user.
739 > */
740 > given_name?: string;
741 >
742 > /**
743 > * OPTIONAL. Family name or last name of the user.
744 > */
745 > family_name?: string;
746 >
747 > /**
748 > * OPTIONAL. Middle name of the user.
749 > */
750 > middle_name?: string;
751 >
752 > /**
753 > * OPTIONAL. Preferred username or email the user wishes to be referred to.
754 > */
755 > preferred_username?: string;
756 >
757 > /**
758 > * OPTIONAL. Email address of the user.
759 > */
760 > email?: string;
761 >
762 > /**
763 > * OPTIONAL. True if the user's email has been verified.
764 > */
765 > email_verified?: boolean;
766 >
767 > /**
768 > * OPTIONAL. User's profile picture URL.
769 > */
770 > picture?: string;
771 >
772 > /**
773 > * OPTIONAL. Authentication time. Time when the user authentication occurred.
774 > */
775 > auth_time?: number;
776 >
777 > /**
778 > * OPTIONAL. Authentication context class reference.
779 > */
780 > acr?: string;
781 >
782 > /**
783 > * OPTIONAL. Authentication methods references.
784 > */
785 > amr?: string[];
786 >
787 > /**
788 > * OPTIONAL. Session ID. String identifier for a session.
789 > */
790 > sid?: string;
791 >
792 > /**
793 > * OPTIONAL. Address component.
794 > */
795 > address?: {
796 > formatted?: string;
797 > street_address?: string;
798 > locality?: string;
799 > region?: string;
800 > postal_code?: string;
801 > country?: string;
802 > };
803 >
804 > /**
805 > * OPTIONAL. Groups that the user belongs to.
806 > */
807 > groups?: string[];
808 >
809 > /**
810 > * OPTIONAL. Roles assigned to the user.
811 > */
812 > roles?: string[];
813 >
814 > /**
815 > * OPTIONAL. Handles optional claims that are not explicitly defined in the standard.
816 > */
817 > [key: string]: unknown;
818 > }
819 >
820 > //#endregion
821 >
822 > //#region is functions
823 >
824 > export function isAuthorizationProtectedResourceMetadata(obj: unknown): obj is IAuthorizationProtectedResourceMetadata {
825 > if (typeof obj !== 'object' || obj === null) { oauth.ts
826 return false;
827 }
828 > oauth.ts
829 > const metadata = obj as IAuthorizationProtectedResourceMetadata;
830 > if (!metadata.resource) {
831 return false;
832 }
833 > if (metadata.scopes_supported !== undefined && !Array.isArray(metadata.scopes_supported)) { oauth.ts
834 return false;
835 }
836 > return true; oauth.ts
837 > }
838 > oauth.ts
839 > const urisToCheck: Array<keyof IAuthorizationServerMetadata> = [
840 > 'issuer',
841 > 'authorization_endpoint',
842 > 'token_endpoint',
843 > 'registration_endpoint',
844 > 'jwks_uri'
845 > ];
846 > export function isAuthorizationServerMetadata(obj: unknown): obj is IAuthorizationServerMetadata {
847 > if (typeof obj !== 'object' || obj === null) { oauth.ts
848 return false;
849 }
850 > const metadata = obj as IAuthorizationServerMetadata; oauth.ts
851 > if (!metadata.issuer) {
852 throw new Error('Authorization server metadata must have an issuer');
853 }
854 > oauth.ts
855 > for (const uri of urisToCheck) {
856 > if (!metadata[uri]) {
857 > continue; oauth.ts
858 > }
859 > if (typeof metadata[uri] !== 'string') { oauth.ts
860 throw new Error(`Authorization server metadata '${uri}' must be a string`);
861 }
862 > if (!metadata[uri].startsWith('https://') && !metadata[uri].startsWith('http://')) { oauth.ts
863 throw new Error(`Authorization server metadata '${uri}' must start with http:// or https://`);
864 }
865 > } oauth.ts
866 > return true;
867 > }
868 > oauth.ts
869 > export function isAuthorizationDynamicClientRegistrationResponse(obj: unknown): obj is IAuthorizationDynamicClientRegistrationResponse {
870 if (typeof obj !== 'object' || obj === null) {
871 return false;
874 return response.client_id !== undefined;
875 }
876 > oauth.ts
877 > export function isAuthorizationAuthorizeResponse(obj: unknown): obj is IAuthorizationAuthorizeResponse {
878 if (typeof obj !== 'object' || obj === null) {
879 return false;
882 return response.code !== undefined && response.state !== undefined;
883 }
884 > oauth.ts
885 > export function isAuthorizationTokenResponse(obj: unknown): obj is IAuthorizationTokenResponse {
886 if (typeof obj !== 'object' || obj === null) {
887 return false;
890 return response.access_token !== undefined && response.token_type !== undefined;
891 }
892 > oauth.ts
893 > export function isAuthorizationDeviceResponse(obj: unknown): obj is IAuthorizationDeviceResponse {
894 if (typeof obj !== 'object' || obj === null) {
895 return false;
898 return response.device_code !== undefined && response.user_code !== undefined && response.verification_uri !== undefined && response.expires_in !== undefined;
899 }
900 > oauth.ts
901 > export function isAuthorizationErrorResponse(obj: unknown): obj is IAuthorizationErrorResponse {
902 if (typeof obj !== 'object' || obj === null) {
903 return false;
906 return response.error !== undefined;
907 }
908 > oauth.ts
909 > export function isAuthorizationRegistrationErrorResponse(obj: unknown): obj is IAuthorizationRegistrationErrorResponse {
910 if (typeof obj !== 'object' || obj === null) {
911 return false;
914 return response.error !== undefined;
915 }
916 > oauth.ts
917 > //#endregion
918 >
919 > export function getDefaultMetadataForUrl(authorizationServer: URL): IAuthorizationServerMetadata {
920 return {
921 issuer: authorizationServer.toString(),
928 };
929 }
930 > oauth.ts
931 > /**
932 > * The grant types that we support
933 > */
934 > const grantTypesSupported = ['authorization_code', 'refresh_token', 'urn:ietf:params:oauth:grant-type:device_code'];
935 >
936 > /**
937 > * Default port for the authorization flow. We try to use this port so that
938 > * the redirect URI does not change when running on localhost. This is useful
939 > * for servers that only allow exact matches on the redirect URI. The spec
940 > * says that the port should not matter, but some servers do not follow
941 > * the spec and require an exact match.
942 > */
943 > export const DEFAULT_AUTH_FLOW_PORT = 33418;
944 export async function fetchDynamicRegistration(serverMetadata: IAuthorizationServerMetadata, clientName: string, scopes?: string[]): Promise<IAuthorizationDynamicClientRegistrationResponse> {
945 if (!serverMetadata.registration_endpoint) {
999 throw new Error(`Invalid authorization dynamic client registration response: ${JSON.stringify(registration)}`);
1000 }
1001 > oauth.ts
1002 > export interface IAuthenticationChallenge {
1003 > scheme: string;
1004 > params: Record<string, string>;
1005 > }
1006 >
1007 > export function parseWWWAuthenticateHeader(wwwAuthenticateHeaderValue: string): IAuthenticationChallenge[] {
1008 > const challenges: IAuthenticationChallenge[] = []; oauth.ts
1009 >
1010 > // According to RFC 7235, multiple challenges are separated by commas
1011 > // But parameters within a challenge can also be separated by commas
1012 > // We need to identify scheme names to know where challenges start
1013 >
1014 > // First, split by commas while respecting quoted strings
1015 > const tokens: string[] = [];
1016 > let current = '';
1017 > let inQuotes = false;
1018 >
1019 > for (let i = 0; i < wwwAuthenticateHeaderValue.length; i++) {
1020 > const char = wwwAuthenticateHeaderValue[i];
1021 >
1022 > if (char === '"') {
1023 > inQuotes = !inQuotes; oauth.ts
1024 > current += char;
1025 > } else if (char === ',' && !inQuotes) { oauth.ts
1026 if (current.trim()) {
1027 tokens.push(current.trim());
1028 }
1029 current = '';
1030 > } else { oauth.ts
1031 > current += char;
1032 > }
1033 > }
1034 >
1035 > if (current.trim()) {
1036 > tokens.push(current.trim());
1037 > }
1038 >
1039 > // Now process tokens to identify challenges
1040 > // A challenge starts with a scheme name (a token that doesn't contain '=' and is followed by parameters or is standalone)
1041 > let currentChallenge: { scheme: string; params: Record<string, string> } | undefined;
1042 >
1043 > for (const token of tokens) {
1044 > const hasEquals = token.includes('=');
1045 >
1046 > if (!hasEquals) {
1047 // This token doesn't have '=', so it's likely a scheme name
1048 if (currentChallenge) {
1050 }
1051 currentChallenge = { scheme: token.trim(), params: {} };
1052 > } else { oauth.ts
1053 > // This token has '=', it could be: oauth.ts
1054 > // 1. A parameter for the current challenge
1055 > // 2. A new challenge that starts with "Scheme param=value"
1056 >
1057 > const spaceIndex = token.indexOf(' ');
1058 > if (spaceIndex > 0) {
1059 > const beforeSpace = token.substring(0, spaceIndex);
1060 > const afterSpace = token.substring(spaceIndex + 1);
1061 >
1062 > // Check if what's before the space looks like a scheme name (no '=')
1063 > if (!beforeSpace.includes('=') && afterSpace.includes('=')) {
1064 > // This is a new challenge starting with "Scheme param=value"
1065 > if (currentChallenge) {
1066 challenges.push(currentChallenge);
1067 }
1068 > currentChallenge = { scheme: beforeSpace.trim(), params: {} }; oauth.ts
1069 >
1070 > // Parse the parameter part
1071 > const equalIndex = afterSpace.indexOf('=');
1072 > if (equalIndex > 0) {
1073 > const key = afterSpace.substring(0, equalIndex).trim();
1074 > const value = afterSpace.substring(equalIndex + 1).trim().replace(/^"|"$/g, '');
1075 > if (key && value !== undefined) {
1076 > currentChallenge.params[key] = value;
1077 > }
1078 > }
1079 > continue;
1080 > }
1081 > }
1082
1083 // This is a parameter for the current challenge
1092 }
1093 }
1094 > } oauth.ts
1095 > } oauth.ts
1096 >
1097 > // Don't forget the last challenge
1098 > if (currentChallenge) {
1099 > challenges.push(currentChallenge);
1100 > }
1101 >
1102 > return challenges;
1103 > }
1104 > oauth.ts
1105 > export function getClaimsFromJWT(token: string): IAuthorizationJWTClaims {
1106 const parts = token.split('.');
1107 if (parts.length !== 3) {
1130 }
1131 }
1132 > oauth.ts
1133 > /**
1134 > * Checks if two scope lists are equivalent, regardless of order.
1135 > * This is useful for comparing OAuth scopes where the order should not matter.
1136 > *
1137 > * @param scopes1 First list of scopes to compare (can be undefined)
1138 > * @param scopes2 Second list of scopes to compare (can be undefined)
1139 > * @returns true if the scope lists contain the same scopes (order-independent), false otherwise
1140 > *
1141 > * @example
1142 > * ```typescript
1143 > * scopesMatch(['read', 'write'], ['write', 'read']) // Returns: true
1144 > * scopesMatch(['read'], ['write']) // Returns: false
1145 > * scopesMatch(undefined, undefined) // Returns: true
1146 > * scopesMatch(['read'], undefined) // Returns: false
1147 > * ```
1148 > */
1149 > export function scopesMatch(scopes1: readonly string[] | undefined, scopes2: readonly string[] | undefined): boolean {
1150 if (scopes1 === scopes2) {
1151 return true;
1164 return sortedScopes1.every((scope, index) => scope === sortedScopes2[index]);
1165 }
1166 > oauth.ts
1167 > interface CommonResponse {
1168 > status: number;
1169 > statusText: string;
1170 > json(): Promise<unknown>;
1171 > text(): Promise<string>;
1172 > }
1173 >
1174 > interface IFetcher {
1175 > (input: string, init: { method: string; headers: Record<string, string> }): Promise<CommonResponse>;
1176 > }
1177 >
1178 > export interface IFetchResourceMetadataOptions {
1179 > /**
1180 > * Headers to include only when the resource metadata URL has the same origin as the target resource
1181 > */
1182 > sameOriginHeaders?: Record<string, string>;
1183 > /**
1184 > * Optional custom fetch implementation (defaults to global fetch)
1185 > */
1186 > fetch?: IFetcher;
1187 > }
1188 >
1189 > /**
1190 > * Fetches and validates OAuth 2.0 protected resource metadata from the given URL.
1191 > *
1192 > * @param targetResource The target resource URL to compare origins with (e.g., the MCP server URL)
1193 > * @param resourceMetadataUrl Optional URL to fetch the resource metadata from. If not provided, will try well-known URIs.
1194 > * @param options Configuration options for the fetch operation
1195 > * @returns Promise that resolves to an object containing the validated resource metadata and any errors encountered during discovery
1196 > * @throws Error if the fetch fails, returns non-200 status, or the response is invalid on all attempted URLs
1197 > */
1198 > export async function fetchResourceMetadata( oauth.ts
1199 > targetResource: string,
1200 > resourceMetadataUrl: string | undefined,
1201 > options: IFetchResourceMetadataOptions = {}
1202 > ): Promise<{ metadata: IAuthorizationProtectedResourceMetadata; discoveryUrl: string; errors: Error[] }> {
1203 > const {
1204 > sameOriginHeaders = {},
1205 > fetch: fetchImpl = fetch
1206 > } = options;
1207 >
1208 > const targetResourceUrlObj = new URL(targetResource);
1209 >
1210 > const fetchPrm = async (prmUrl: string, validateUrl: string) => {
1211 > // Determine if we should include same-origin headers
1212 > let headers: Record<string, string> = {
1213 > 'Accept': 'application/json'
1214 > };
1215 >
1216 > const resourceMetadataUrlObj = new URL(prmUrl);
1217 > if (resourceMetadataUrlObj.origin === targetResourceUrlObj.origin) {
1218 > headers = { oauth.ts
1219 > ...headers,
1220 > ...sameOriginHeaders
1221 > };
1222 > }
1223 > oauth.ts
1224 > const response = await fetchImpl(prmUrl, { method: 'GET', headers });
1225 > if (response.status !== 200) { oauth.ts
1226 let errorText: string;
1227 try {
1232 throw new Error(`Failed to fetch resource metadata from ${prmUrl}: ${response.status} ${errorText}`);
1233 }
1234 > oauth.ts
1235 > const body = await response.json();
1236 > if (isAuthorizationProtectedResourceMetadata(body)) { oauth.ts
1237 > // Validate that the resource matches the target resource oauth.ts
1238 > // Use URL constructor for normalization - it handles hostname case and trailing slashes
1239 > const prmValue = new URL(body.resource).toString();
1240 > const expectedResource = new URL(validateUrl).toString();
1241 > if (prmValue !== expectedResource) {
1242 throw new Error(`Protected Resource Metadata 'resource' property value "${prmValue}" does not match expected value "${expectedResource}" for URL ${prmUrl}. Per RFC 9728, these MUST match. See https://datatracker.ietf.org/doc/html/rfc9728#PRConfigurationValidation`);
1243 }
1244 > return body; oauth.ts
1245 > } else { oauth.ts
1246 throw new Error(`Invalid resource metadata from ${prmUrl}. Expected to follow shape of https://datatracker.ietf.org/doc/html/rfc9728#name-protected-resource-metadata (Hints: is scopes_supported an array? Is resource a string?). Current payload: ${JSON.stringify(body)}`);
1247 }
1248 > }; oauth.ts
1249 >
1250 > const errors: Error[] = [];
1251 > if (resourceMetadataUrl) {
1252 try {
1253 const metadata = await fetchPrm(resourceMetadataUrl, targetResource);
1257 }
1258 }
1259 > oauth.ts
1260 > // Try well-known URIs starting with path-appended, then root
1261 > const hasPathComponent = targetResourceUrlObj.pathname !== '/';
1262 > const rootUrl = `${targetResourceUrlObj.origin}${AUTH_PROTECTED_RESOURCE_METADATA_DISCOVERY_PATH}`;
1263 >
1264 > if (hasPathComponent) {
1265 > const pathAppendedUrl = `${rootUrl}${targetResourceUrlObj.pathname}`; oauth.ts
1266 > try {
1267 > const metadata = await fetchPrm(pathAppendedUrl, targetResource);
1268 > return { metadata, discoveryUrl: pathAppendedUrl, errors }; oauth.ts
1269 > } catch (e) { oauth.ts
1270 errors.push(e instanceof Error ? e : new Error(String(e)));
1271 }
1272 > } oauth.ts
1273
1274 // Finally, try root discovery
1286 throw new AggregateError(errors, 'Failed to fetch resource metadata from all attempted URLs');
1287 }
1288 > } oauth.ts
1289 > oauth.ts
1290 > export interface IFetchAuthorizationServerMetadataOptions {
1291 > /**
1292 > * Headers to include in the requests
1293 > */
1294 > additionalHeaders?: Record<string, string>;
1295 > /**
1296 > * Optional custom fetch implementation (defaults to global fetch)
1297 > */
1298 > fetch?: IFetcher;
1299 > }
1300 >
1301 > /** Helper to try parsing the response as authorization server metadata */
1302 > async function tryParseAuthServerMetadata(response: CommonResponse): Promise<IAuthorizationServerMetadata | undefined> { oauth.ts
1303 > if (response.status !== 200) {
1304 return undefined;
1305 }
1306 > try { oauth.ts
1307 > const body = await response.json();
1308 > if (isAuthorizationServerMetadata(body)) { oauth.ts
1309 > return body; oauth.ts
1310 > }
1311 > } catch { oauth.ts
1312 // Failed to parse as JSON or not valid metadata
1313 }
1314 return undefined;
1315 }
1316 > oauth.ts
1317 > /** Helper to get error text from response */
1318 async function getErrText(res: CommonResponse): Promise<string> {
1319 try {
1323 }
1324 }
1325 > oauth.ts
1326 > /**
1327 > * Fetches and validates OAuth 2.0 authorization server metadata from the given authorization server URL.
1328 > *
1329 > * This function tries multiple discovery endpoints in the following order:
1330 > * 1. OAuth 2.0 Authorization Server Metadata with path insertion (RFC 8414)
1331 > * 2. OpenID Connect Discovery with path insertion
1332 > * 3. OpenID Connect Discovery with path addition
1333 > *
1334 > * Path insertion: For issuer URLs with path components (e.g., https://example.com/tenant),
1335 > * the well-known path is inserted after the origin and before the path:
1336 > * https://example.com/.well-known/oauth-authorization-server/tenant
1337 > *
1338 > * Path addition: The well-known path is simply appended to the existing path:
1339 > * https://example.com/tenant/.well-known/openid-configuration
1340 > *
1341 > * @param authorizationServer The authorization server URL (issuer identifier)
1342 > * @param options Configuration options for the fetch operation
1343 > * @returns Promise that resolves to the validated authorization server metadata
1344 > * @throws Error if all discovery attempts fail or the response is invalid
1345 > *
1346 > * @see https://datatracker.ietf.org/doc/html/rfc8414#section-3
1347 > */
1348 > export async function fetchAuthorizationServerMetadata( oauth.ts
1349 > authorizationServer: string,
1350 > options: IFetchAuthorizationServerMetadataOptions = {}
1351 > ): Promise<{ metadata: IAuthorizationServerMetadata; discoveryUrl: string; errors: Error[] }> {
1352 > const {
1353 > additionalHeaders = {},
1354 > fetch: fetchImpl = fetch
1355 > } = options;
1356 >
1357 > const authorizationServerUrl = new URL(authorizationServer);
1358 > const extraPath = authorizationServerUrl.pathname === '/' ? '' : authorizationServerUrl.pathname;
1359 >
1360 > const errors: Error[] = [];
1361 >
1362 > const doFetch = async (url: string): Promise<IAuthorizationServerMetadata | undefined> => {
1363 > try {
1364 > const rawResponse = await fetchImpl(url, {
1365 > method: 'GET',
1366 > headers: {
1367 > ...additionalHeaders,
1368 > 'Accept': 'application/json'
1369 > }
1370 > });
1371 > const metadata = await tryParseAuthServerMetadata(rawResponse); oauth.ts
1372 > if (metadata) { oauth.ts
1373 > return metadata; oauth.ts
1374 > }
1375 // No metadata found, collect error from response
1376 errors.push(new Error(`Failed to fetch authorization server metadata from ${url}: ${rawResponse.status} ${await getErrText(rawResponse)}`));
1381 return undefined;
1382 }
1383 > }; oauth.ts
1384 >
1385 > // For the oauth server metadata discovery path, we _INSERT_
1386 > // the well known path after the origin and before the path.
1387 > // https://datatracker.ietf.org/doc/html/rfc8414#section-3
1388 > const pathToFetch = new URL(AUTH_SERVER_METADATA_DISCOVERY_PATH, authorizationServer).toString() + extraPath;
1389 > let metadata = await doFetch(pathToFetch);
1390 > if (metadata) {
1391 > return { metadata, discoveryUrl: pathToFetch, errors }; oauth.ts
1392 > }
1393
1394 // Try fetching the OpenID Connect Discovery with path insertion.
1407 ? authorizationServer + OPENID_CONNECT_DISCOVERY_PATH.substring(1) // Remove leading slash if authServer ends with slash
1408 : authorizationServer + OPENID_CONNECT_DISCOVERY_PATH;
1409 > metadata = await doFetch(openidPathAdditionUrl); oauth.ts
1410 if (metadata) {
1411 return { metadata, discoveryUrl: openidPathAdditionUrl, errors };
1418 throw new AggregateError(errors, 'Failed to fetch authorization server metadata from all attempted URLs');
1419 }
1420 > } oauth.ts
src/vs/workbench/api/common/extHostTypeConverters.ts 1080 covered LOC · 268 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostTypeConverters.ts
2 > * Copyright (c) Microsoft 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 * as vscode from 'vscode';
7 > import { asArray, coalesce, isNonEmptyArray } from '../../../base/common/arrays.js';
8 > import { VSBuffer, decodeBase64, encodeBase64 } from '../../../base/common/buffer.js';
9 > import { IStringDictionary } from '../../../base/common/collections.js';
10 > import { IDataTransferFile, IDataTransferItem, UriList } from '../../../base/common/dataTransfer.js';
11 > import { createSingleCallFunction } from '../../../base/common/functional.js';
12 > import * as htmlContent from '../../../base/common/htmlContent.js';
13 > import { DisposableStore } from '../../../base/common/lifecycle.js';
14 > import { ResourceMap, ResourceSet } from '../../../base/common/map.js';
15 > import * as marked from '../../../base/common/marked/marked.js';
16 > import { parse, revive } from '../../../base/common/marshalling.js';
17 > import { MarshalledId } from '../../../base/common/marshallingIds.js';
18 > import { Mimes } from '../../../base/common/mime.js';
19 > import { cloneAndChange } from '../../../base/common/objects.js';
20 > import { OS } from '../../../base/common/platform.js';
21 > import { IPrefixTreeNode, WellDefinedPrefixTree } from '../../../base/common/prefixTree.js';
22 > import { basename } from '../../../base/common/resources.js';
23 > import { ThemeIcon } from '../../../base/common/themables.js';
24 > import { isDefined, isEmptyObject, isNumber, isString, isUndefinedOrNull } from '../../../base/common/types.js';
25 > import { URI, UriComponents, isUriComponents } from '../../../base/common/uri.js';
26 > import { IURITransformer } from '../../../base/common/uriIpc.js';
27 > import { generateUuid } from '../../../base/common/uuid.js';
28 > import { RenderLineNumbersType } from '../../../editor/common/config/editorOptions.js';
29 > import { IPosition } from '../../../editor/common/core/position.js';
30 > import * as editorRange from '../../../editor/common/core/range.js';
31 > import { ISelection } from '../../../editor/common/core/selection.js';
32 > import { IContentDecorationRenderOptions, IDecorationOptions, IDecorationRenderOptions, IThemeDecorationRenderOptions } from '../../../editor/common/editorCommon.js';
33 > import * as encodedTokenAttributes from '../../../editor/common/encodedTokenAttributes.js';
34 > import * as languageSelector from '../../../editor/common/languageSelector.js';
35 > import * as languages from '../../../editor/common/languages.js';
36 > import { EndOfLineSequence, TrackedRangeStickiness } from '../../../editor/common/model.js';
37 > import { ITextEditorOptions } from '../../../platform/editor/common/editor.js';
38 > import { IExtensionDescription, IRelaxedExtensionDescription } from '../../../platform/extensions/common/extensions.js';
39 > import { ILogService } from '../../../platform/log/common/log.js';
40 > import { IMarkerData, IRelatedInformation, MarkerSeverity, MarkerTag } from '../../../platform/markers/common/markers.js';
41 > import { ProgressLocation as MainProgressLocation } from '../../../platform/progress/common/progress.js';
42 > import { DEFAULT_EDITOR_ASSOCIATION, SaveReason } from '../../common/editor.js';
43 > import { IViewBadge } from '../../common/views.js';
44 > import { IChatAgentRequest, IChatAgentResult } from '../../contrib/chat/common/participants/chatAgents.js';
45 > import { IChatRequestModeInstructions } from '../../contrib/chat/common/model/chatModel.js';
46 > import { IChatAgentMarkdownContentWithVulnerability, IChatAutoModeResolutionPart, IChatCodeCitation, IChatCommandButton, IChatConfirmation, IChatContentInlineReference, IChatContentReference, IChatExtensionsContent, IChatExternalToolInvocationUpdate, IChatFollowup, IChatHookPart, IChatMarkdownContent, IChatMoveMessage, IChatMultiDiffDataSerialized, IChatProgressMessage, IChatPullRequestContent, IChatQuestionCarousel, IChatResponseCodeblockUriPart, IChatTaskDto, IChatTaskResult, IChatTerminalToolInvocationData, IChatTextEdit, IChatThinkingPart, IChatToolInvocationSerialized, IChatTreeData, IChatUserActionEvent, IChatWarningMessage, IChatInfoMessage, IChatWorkspaceEdit } from '../../contrib/chat/common/chatService/chatService.js';
47 > import { LocalChatSessionUri } from '../../contrib/chat/common/model/chatUri.js';
48 > import { ChatRequestToolReferenceEntry, IChatRequestVariableEntry, isImageVariableEntry, isPromptFileVariableEntry, isPromptTextVariableEntry } from '../../contrib/chat/common/attachments/chatVariableEntries.js';
49 > import { ChatSessionStatus, IChatSessionItem } from '../../contrib/chat/common/chatSessionsService.js';
50 > import { ChatAgentLocation } from '../../contrib/chat/common/constants.js';
51 > import { ChatRequestHooks, resolveEffectiveCommand } from '../../contrib/chat/common/promptSyntax/hookSchema.js';
52 > import { type IParsedHookCommand } from '../../../platform/agentPlugins/common/pluginParsers.js';
53 > import { IToolInvocationContext, IToolResult, IToolResultInputOutputDetails, IToolResultOutputDetails, ToolDataSource, ToolInvocationPresentation } from '../../contrib/chat/common/tools/languageModelToolsService.js';
54 > import * as chatProvider from '../../contrib/chat/common/languageModels.js';
55 > import { IChatMessageDataPart, IChatResponseDataPart, IChatResponsePromptTsxPart, IChatResponseTextPart } from '../../contrib/chat/common/languageModels.js';
56 > import { DebugTreeItemCollapsibleState, IDebugVisualizationTreeItem } from '../../contrib/debug/common/debug.js';
57 > import { McpServerDefinition as McpServerDefinitionType, McpServerLaunch, McpServerTransportType } from '../../contrib/mcp/common/mcpTypes.js';
58 > import * as notebooks from '../../contrib/notebook/common/notebookCommon.js';
59 > import { CellEditType } from '../../contrib/notebook/common/notebookCommon.js';
60 > import { ICellRange } from '../../contrib/notebook/common/notebookRange.js';
61 > import { InputValidationType } from '../../contrib/scm/common/scm.js';
62 > import * as search from '../../contrib/search/common/search.js';
63 > import { TestId } from '../../contrib/testing/common/testId.js';
64 > import { CoverageDetails, DetailType, ICoverageCount, IFileCoverage, ISerializedTestResults, ITestErrorMessage, ITestItem, ITestRunProfileReference, ITestTag, TestMessageType, TestResultItem, TestRunProfileBitset, denamespaceTestTag, namespaceTestTag } from '../../contrib/testing/common/testTypes.js';
65 > import { AiSettingsSearchResult, AiSettingsSearchResultKind } from '../../services/aiSettingsSearch/common/aiSettingsSearch.js';
66 > import { EditorGroupColumn } from '../../services/editor/common/editorGroupColumn.js';
67 > import { ACTIVE_GROUP, SIDE_GROUP } from '../../services/editor/common/editorService.js';
68 > import { checkProposedApiEnabled, isProposedApiEnabled } from '../../services/extensions/common/extensions.js';
69 > import { Dto, SerializableObjectWithBuffers } from '../../services/extensions/common/proxyIdentifier.js';
70 > import * as extHostProtocol from './extHost.protocol.js';
71 > import { CommandsConverter } from './extHostCommands.js';
72 > import { getPrivateApiFor } from './extHostTestingPrivateApi.js';
73 > import * as types from './extHostTypes.js';
74 > import { LanguageModelDataPart, LanguageModelPromptTsxPart, LanguageModelTextPart } from './extHostTypes.js';
75 >
76 > export namespace Command {
77 >
78 > export interface ICommandsConverter {
79 > fromInternal(command: extHostProtocol.ICommandDto): vscode.Command | undefined;
80 > toInternal(command: vscode.Command | undefined, disposables: DisposableStore): extHostProtocol.ICommandDto | undefined;
81 > }
82 > }
83 >
84 > export interface PositionLike {
85 > line: number;
86 > character: number;
87 > }
88 >
89 > export interface RangeLike {
90 > start: PositionLike;
91 > end: PositionLike;
92 > }
93 >
94 > export interface SelectionLike extends RangeLike {
95 > anchor: PositionLike;
96 > active: PositionLike;
97 > }
98 > export namespace Selection {
99 >
100 > export function to(selection: ISelection): types.Selection {
101 const { selectionStartLineNumber, selectionStartColumn, positionLineNumber, positionColumn } = selection;
102 const start = new types.Position(selectionStartLineNumber - 1, selectionStartColumn - 1);
104 return new types.Selection(start, end);
105 }
107 > export function from(selection: SelectionLike): ISelection {
108 const { anchor, active } = selection;
109 return {
114 };
115 }
117 > export namespace Range {
118 >
119 > export function from(range: undefined): undefined;
120 > export function from(range: RangeLike): editorRange.IRange;
121 > export function from(range: RangeLike | undefined): editorRange.IRange | undefined;
122 > export function from(range: RangeLike | undefined): editorRange.IRange | undefined {
123 if (!range) {
124 return undefined;
132 };
133 }
135 > export function to(range: undefined): types.Range;
136 > export function to(range: editorRange.IRange): types.Range;
137 > export function to(range: editorRange.IRange | undefined): types.Range | undefined;
138 > export function to(range: editorRange.IRange | undefined): types.Range | undefined {
139 if (!range) {
140 return undefined;
143 return new types.Range(startLineNumber - 1, startColumn - 1, endLineNumber - 1, endColumn - 1);
144 }
146 >
147 > export namespace Location {
148 >
149 > export function from(location: vscode.Location): Dto<languages.Location> {
150 return {
151 uri: location.uri,
153 };
154 }
156 > export function to(location: Dto<languages.Location>): vscode.Location {
157 return new types.Location(URI.revive(location.uri), Range.to(location.range));
158 }
160 >
161 > export namespace TokenType {
162 > export function to(type: encodedTokenAttributes.StandardTokenType): types.StandardTokenType {
163 switch (type) {
164 case encodedTokenAttributes.StandardTokenType.Comment: return types.StandardTokenType.Comment;
168 }
169 }
171 >
172 > export namespace Position {
173 > export function to(position: IPosition): types.Position {
174 return new types.Position(position.lineNumber - 1, position.column - 1);
175 }
176 > export function from(position: types.Position | vscode.Position): IPosition { extHostTypeConverters.ts
177 return { lineNumber: position.line + 1, column: position.character + 1 };
178 }
180 >
181 > export namespace DocumentSelector {
182 >
183 > export function from(value: vscode.DocumentSelector, uriTransformer?: IURITransformer, extension?: IExtensionDescription): extHostProtocol.IDocumentFilterDto[] {
184 return coalesce(asArray(value).map(sel => _doTransformDocumentSelector(sel, uriTransformer, extension)));
185 }
187 > function _doTransformDocumentSelector(selector: string | vscode.DocumentFilter, uriTransformer: IURITransformer | undefined, extension: IExtensionDescription | undefined): extHostProtocol.IDocumentFilterDto | undefined {
188 if (typeof selector === 'string') {
189 return {
208 return undefined;
209 }
211 > function _transformScheme(scheme: string | undefined, uriTransformer: IURITransformer | undefined): string | undefined {
212 if (uriTransformer && typeof scheme === 'string') {
213 return uriTransformer.transformOutgoingScheme(scheme);
215 return scheme;
216 }
218 >
219 > export namespace TabSelector {
220 >
221 > function isViewTypeSelector(value: vscode.TabSelector): value is { viewType: string } {
222 return (value as { viewType?: string }).viewType !== undefined;
223 }
225 > export function from(value: vscode.TabSelector, uriTransformer?: IURITransformer, extension?: IExtensionDescription): extHostProtocol.ITabSelectorDto {
226 if (isViewTypeSelector(value)) {
227 return { viewType: value.viewType };
229 return { uri: DocumentSelector.from(value.uri, uriTransformer, extension) };
230 }
232 >
233 > export namespace DiagnosticTag {
234 > export function from(value: vscode.DiagnosticTag): MarkerTag | undefined {
235 switch (value) {
236 case types.DiagnosticTag.Unnecessary:
241 return undefined;
242 }
243 > export function to(value: MarkerTag): vscode.DiagnosticTag | undefined { extHostTypeConverters.ts
244 switch (value) {
245 case MarkerTag.Unnecessary:
251 }
252 }
254 >
255 > export namespace Diagnostic {
256 > export function from(value: vscode.Diagnostic): IMarkerData {
257 let code: string | { value: string; target: URI } | undefined;
258
278 };
279 }
281 > export function to(value: IMarkerData): vscode.Diagnostic {
282 const res = new types.Diagnostic(Range.to(value), value.message, DiagnosticSeverity.to(value.severity));
283 res.source = value.source;
287 return res;
288 }
290 >
291 > export namespace DiagnosticRelatedInformation {
292 > export function from(value: vscode.DiagnosticRelatedInformation): IRelatedInformation {
293 return {
294 ...Range.from(value.location.range),
297 };
298 }
299 > export function to(value: IRelatedInformation): types.DiagnosticRelatedInformation { extHostTypeConverters.ts
300 return new types.DiagnosticRelatedInformation(new types.Location(value.resource, Range.to(value)), value.message);
301 }
303 > export namespace DiagnosticSeverity {
304 >
305 > export function from(value: number): MarkerSeverity {
306 switch (value) {
307 case types.DiagnosticSeverity.Error:
316 return MarkerSeverity.Error;
317 }
319 > export function to(value: MarkerSeverity): types.DiagnosticSeverity {
320 switch (value) {
321 case MarkerSeverity.Info:
331 }
332 }
334 >
335 > export namespace ViewColumn {
336 > export function from(column?: vscode.ViewColumn): EditorGroupColumn {
337 if (typeof column === 'number' && column >= types.ViewColumn.One) {
338 return column - 1; // adjust zero index (ViewColumn.ONE => 0)
345 return ACTIVE_GROUP; // default is always the active group
346 }
348 > export function to(position: EditorGroupColumn): vscode.ViewColumn {
349 if (typeof position === 'number' && position >= 0) {
350 return position + 1; // adjust to index (ViewColumn.ONE => 1)
353 throw new Error(`invalid 'EditorGroupColumn'`);
354 }
356 >
357 function isDecorationOptions(something: any): something is vscode.DecorationOptions {
358 return (typeof something.range !== 'undefined');
359 }
361 > export function isDecorationOptionsArr(something: vscode.Range[] | vscode.DecorationOptions[]): something is vscode.DecorationOptions[] {
362 if (something.length === 0) {
363 return true;
365 return isDecorationOptions(something[0]) ? true : false;
366 }
368 > export namespace MarkdownString {
369 >
370 > export function fromMany(markup: (vscode.MarkdownString | vscode.MarkedString)[]): htmlContent.IMarkdownString[] {
371 return markup.map(MarkdownString.from);
372 }
374 > interface Codeblock {
375 > language: string;
376 > value: string;
377 > }
378 >
379 > function isCodeblock(thing: any): thing is Codeblock {
380 return thing && typeof thing === 'object'
381 && typeof (<Codeblock>thing).language === 'string'
382 && typeof (<Codeblock>thing).value === 'string';
383 }
385 > export function from(markup: vscode.MarkdownString | vscode.MarkedString): htmlContent.IMarkdownString {
386 let res: htmlContent.IMarkdownString;
387 if (isCodeblock(markup)) {
423 return res;
424 }
426 > function _uriMassage(part: string, bucket: { [n: string]: UriComponents }): string {
427 if (!part) {
428 return part;
455 return JSON.stringify(data);
456 }
458 > export function to(value: htmlContent.IMarkdownString): vscode.MarkdownString {
459 const result = new types.MarkdownString(value.value, value.supportThemeIcons);
460 result.isTrusted = value.isTrusted;
464 return result;
465 }
467 > export function fromStrict(value: string | vscode.MarkdownString | undefined | null): undefined | string | htmlContent.IMarkdownString {
468 if (!value) {
469 return undefined;
471 return typeof value === 'string' ? value : MarkdownString.from(value);
472 }
474 >
475 > export function fromRangeOrRangeWithMessage(ranges: vscode.Range[] | vscode.DecorationOptions[]): IDecorationOptions[] {
476 if (isDecorationOptionsArr(ranges)) {
477 return ranges.map((r): IDecorationOptions => {
493 }
494 }
496 > export function pathOrURIToURI(value: string | URI): URI {
497 if (typeof value === 'undefined') {
498 return value;
504 }
505 }
507 > export namespace ThemableDecorationAttachmentRenderOptions {
508 > export function from(options: vscode.ThemableDecorationAttachmentRenderOptions): IContentDecorationRenderOptions {
509 if (typeof options === 'undefined') {
510 return options;
525 };
526 }
528 >
529 > export namespace ThemableDecorationRenderOptions {
530 > export function from(options: vscode.ThemableDecorationRenderOptions): IThemeDecorationRenderOptions {
531 if (typeof options === 'undefined') {
532 return options;
558 };
559 }
561 >
562 > export namespace DecorationRangeBehavior {
563 > export function from(value: types.DecorationRangeBehavior): TrackedRangeStickiness {
564 if (typeof value === 'undefined') {
565 return value;
576 }
577 }
579 >
580 > export namespace DecorationRenderOptions {
581 > export function from(options: vscode.DecorationRenderOptions): IDecorationRenderOptions {
582 return {
583 isWholeLine: options.isWholeLine,
612 };
613 }
615 >
616 > export namespace TextEdit {
617 >
618 > export function from(edit: vscode.TextEdit): languages.TextEdit {
619 return {
620 text: edit.newText,
623 };
624 }
626 > export function to(edit: languages.TextEdit): types.TextEdit {
627 const result = new types.TextEdit(Range.to(edit.range), edit.text);
628 result.newEol = (typeof edit.eol === 'undefined' ? undefined : EndOfLine.to(edit.eol))!;
629 return result;
630 }
632 >
633 > export namespace WorkspaceEdit {
634 >
635 > export interface IVersionInformationProvider {
636 > getTextDocumentVersion(uri: URI): number | undefined;
637 > getNotebookDocumentVersion(uri: URI): number | undefined;
638 > }
639 >
640 > export function from(value: vscode.WorkspaceEdit, versionInfo?: IVersionInformationProvider): extHostProtocol.IWorkspaceEditDto {
641 const result: extHostProtocol.IWorkspaceEditDto = {
642 edits: []
722 return result;
723 }
725 > export function to(value: extHostProtocol.IWorkspaceEditDto) {
726 const result = new types.WorkspaceEdit();
727 const edits = new ResourceMap<(types.TextEdit | types.SnippetTextEdit)[]>();
763 return result;
764 }
766 >
767 >
768 > export namespace SymbolKind {
769 >
770 > const _fromMapping: { [kind: number]: languages.SymbolKind } = Object.create(null);
771 > _fromMapping[types.SymbolKind.File] = languages.SymbolKind.File;
772 > _fromMapping[types.SymbolKind.Module] = languages.SymbolKind.Module;
773 > _fromMapping[types.SymbolKind.Namespace] = languages.SymbolKind.Namespace;
774 > _fromMapping[types.SymbolKind.Package] = languages.SymbolKind.Package;
775 > _fromMapping[types.SymbolKind.Class] = languages.SymbolKind.Class;
776 > _fromMapping[types.SymbolKind.Method] = languages.SymbolKind.Method;
777 > _fromMapping[types.SymbolKind.Property] = languages.SymbolKind.Property;
778 > _fromMapping[types.SymbolKind.Field] = languages.SymbolKind.Field;
779 > _fromMapping[types.SymbolKind.Constructor] = languages.SymbolKind.Constructor;
780 > _fromMapping[types.SymbolKind.Enum] = languages.SymbolKind.Enum;
781 > _fromMapping[types.SymbolKind.Interface] = languages.SymbolKind.Interface;
782 > _fromMapping[types.SymbolKind.Function] = languages.SymbolKind.Function;
783 > _fromMapping[types.SymbolKind.Variable] = languages.SymbolKind.Variable;
784 > _fromMapping[types.SymbolKind.Constant] = languages.SymbolKind.Constant;
785 > _fromMapping[types.SymbolKind.String] = languages.SymbolKind.String;
786 > _fromMapping[types.SymbolKind.Number] = languages.SymbolKind.Number;
787 > _fromMapping[types.SymbolKind.Boolean] = languages.SymbolKind.Boolean;
788 > _fromMapping[types.SymbolKind.Array] = languages.SymbolKind.Array;
789 > _fromMapping[types.SymbolKind.Object] = languages.SymbolKind.Object;
790 > _fromMapping[types.SymbolKind.Key] = languages.SymbolKind.Key;
791 > _fromMapping[types.SymbolKind.Null] = languages.SymbolKind.Null;
792 > _fromMapping[types.SymbolKind.EnumMember] = languages.SymbolKind.EnumMember;
793 > _fromMapping[types.SymbolKind.Struct] = languages.SymbolKind.Struct;
794 > _fromMapping[types.SymbolKind.Event] = languages.SymbolKind.Event;
795 > _fromMapping[types.SymbolKind.Operator] = languages.SymbolKind.Operator;
796 > _fromMapping[types.SymbolKind.TypeParameter] = languages.SymbolKind.TypeParameter;
797 >
798 > export function from(kind: vscode.SymbolKind): languages.SymbolKind {
799 return typeof _fromMapping[kind] === 'number' ? _fromMapping[kind] : languages.SymbolKind.Property;
800 }
802 > export function to(kind: languages.SymbolKind): vscode.SymbolKind {
803 for (const k in _fromMapping) {
804 if (_fromMapping[k] === kind) {
808 return types.SymbolKind.Property;
809 }
811 >
812 > export namespace SymbolTag {
813 >
814 > export function from(kind: types.SymbolTag): languages.SymbolTag {
815 switch (kind) {
816 case types.SymbolTag.Deprecated: return languages.SymbolTag.Deprecated;
817 }
818 }
820 > export function to(kind: languages.SymbolTag): types.SymbolTag {
821 switch (kind) {
822 case languages.SymbolTag.Deprecated: return types.SymbolTag.Deprecated;
823 }
824 }
826 >
827 > export namespace WorkspaceSymbol {
828 > export function from(info: vscode.SymbolInformation): search.IWorkspaceSymbol {
829 return {
830 name: info.name,
835 };
836 }
837 > export function to(info: search.IWorkspaceSymbol): types.SymbolInformation { extHostTypeConverters.ts
838 const result = new types.SymbolInformation(
839 info.name,
845 return result;
846 }
848 >
849 > export namespace DocumentSymbol {
850 > export function from(info: vscode.DocumentSymbol): languages.DocumentSymbol {
851 const result: languages.DocumentSymbol = {
852 name: info.name || '!!MISSING: name!!',
862 return result;
863 }
864 > export function to(info: languages.DocumentSymbol): vscode.DocumentSymbol { extHostTypeConverters.ts
865 const result = new types.DocumentSymbol(
866 info.name,
879 return result;
880 }
882 >
883 > export namespace CallHierarchyItem {
884 >
885 > export function to(item: extHostProtocol.ICallHierarchyItemDto): types.CallHierarchyItem {
886 const result = new types.CallHierarchyItem(
887 SymbolKind.to(item.kind),
898 return result;
899 }
901 > export function from(item: vscode.CallHierarchyItem, sessionId?: string, itemId?: string): extHostProtocol.ICallHierarchyItemDto {
902
903 sessionId = sessionId ?? (<types.CallHierarchyItem>item)._sessionId;
920 };
921 }
923 >
924 > export namespace CallHierarchyIncomingCall {
925 >
926 > export function to(item: extHostProtocol.IIncomingCallDto): types.CallHierarchyIncomingCall {
927 return new types.CallHierarchyIncomingCall(
928 CallHierarchyItem.to(item.from),
930 );
931 }
933 >
934 > export namespace CallHierarchyOutgoingCall {
935 >
936 > export function to(item: extHostProtocol.IOutgoingCallDto): types.CallHierarchyOutgoingCall {
937 return new types.CallHierarchyOutgoingCall(
938 CallHierarchyItem.to(item.to),
940 );
941 }
943 >
944 >
945 > export namespace location {
946 > export function from(value: vscode.Location): languages.Location {
947 return {
948 range: value.range && Range.from(value.range),
950 };
951 }
953 > export function to(value: extHostProtocol.ILocationDto): types.Location {
954 return new types.Location(URI.revive(value.uri), Range.to(value.range));
955 }
957 >
958 > export namespace DefinitionLink {
959 > export function from(value: vscode.Location | vscode.DefinitionLink): languages.LocationLink {
960 const definitionLink = <vscode.DefinitionLink>value;
961 const location = <vscode.Location>value;
971 };
972 }
973 > export function to(value: extHostProtocol.ILocationLinkDto): vscode.LocationLink { extHostTypeConverters.ts
974 return {
975 targetUri: URI.revive(value.uri),
983 };
984 }
986 >
987 > export namespace Hover {
988 > export function from(hover: vscode.VerboseHover): languages.Hover {
989 const convertedHover: languages.Hover = {
990 range: Range.from(hover.range),
995 return convertedHover;
996 }
998 > export function to(info: languages.Hover): types.VerboseHover {
999 const contents = info.contents.map(MarkdownString.to);
1000 const range = Range.to(info.range);
1003 return new types.VerboseHover(contents, range, canIncreaseVerbosity, canDecreaseVerbosity);
1004 }
1006 >
1007 > export namespace EvaluatableExpression {
1008 > export function from(expression: vscode.EvaluatableExpression): languages.EvaluatableExpression {
1009 return {
1010 range: Range.from(expression.range),
1012 };
1013 }
1015 > export function to(info: languages.EvaluatableExpression): types.EvaluatableExpression {
1016 return new types.EvaluatableExpression(Range.to(info.range), info.expression);
1017 }
1019 >
1020 > export namespace InlineValue {
1021 > export function from(inlineValue: vscode.InlineValue): languages.InlineValue {
1022 if (inlineValue instanceof types.InlineValueText) {
1023 return {
1043 }
1044 }
1046 > export function to(inlineValue: languages.InlineValue): vscode.InlineValue {
1047 switch (inlineValue.type) {
1048 case 'text':
1064 }
1065 }
1067 >
1068 > export namespace InlineValueContext {
1069 > export function from(inlineValueContext: vscode.InlineValueContext): extHostProtocol.IInlineValueContextDto {
1070 return {
1071 frameId: inlineValueContext.frameId,
1073 };
1074 }
1076 > export function to(inlineValueContext: extHostProtocol.IInlineValueContextDto): types.InlineValueContext {
1077 return new types.InlineValueContext(inlineValueContext.frameId, Range.to(inlineValueContext.stoppedLocation));
1078 }
1080 >
1081 > export namespace DocumentHighlight {
1082 > export function from(documentHighlight: vscode.DocumentHighlight): languages.DocumentHighlight {
1083 return {
1084 range: Range.from(documentHighlight.range),
1086 };
1087 }
1088 > export function to(occurrence: languages.DocumentHighlight): types.DocumentHighlight { extHostTypeConverters.ts
1089 return new types.DocumentHighlight(Range.to(occurrence.range), occurrence.kind);
1090 }
1092 >
1093 > export namespace MultiDocumentHighlight {
1094 > export function from(multiDocumentHighlight: vscode.MultiDocumentHighlight): languages.MultiDocumentHighlight {
1095 return {
1096 uri: multiDocumentHighlight.uri,
1098 };
1099 }
1101 > export function to(multiDocumentHighlight: languages.MultiDocumentHighlight): types.MultiDocumentHighlight {
1102 return new types.MultiDocumentHighlight(URI.revive(multiDocumentHighlight.uri), multiDocumentHighlight.highlights.map(DocumentHighlight.to));
1103 }
1105 >
1106 > export namespace CompletionTriggerKind {
1107 > export function to(kind: languages.CompletionTriggerKind) {
1108 switch (kind) {
1109 case languages.CompletionTriggerKind.TriggerCharacter:
1116 }
1117 }
1119 >
1120 > export namespace CompletionContext {
1121 > export function to(context: languages.CompletionContext): types.CompletionContext {
1122 return {
1123 triggerKind: CompletionTriggerKind.to(context.triggerKind),
1125 };
1126 }
1128 >
1129 > export namespace CompletionItemTag {
1130 >
1131 > export function from(kind: types.CompletionItemTag): languages.CompletionItemTag {
1132 switch (kind) {
1133 case types.CompletionItemTag.Deprecated: return languages.CompletionItemTag.Deprecated;
1134 }
1135 }
1137 > export function to(kind: languages.CompletionItemTag): types.CompletionItemTag {
1138 switch (kind) {
1139 case languages.CompletionItemTag.Deprecated: return types.CompletionItemTag.Deprecated;
1140 }
1141 }
1143 >
1144 > export namespace CompletionCommand {
1145 > export function from(c: vscode.Command | { command: vscode.Command; icon: vscode.ThemeIcon }, converter: CommandsConverter, disposables: DisposableStore): { command: extHostProtocol.ICommandDto; icon?: languages.IconPath } {
1146 if ('icon' in c && 'command' in c) {
1147 return {
1152 return { command: converter.toInternal(c, disposables) };
1153 }
1155 >
1156 > export namespace CompletionItemKind {
1157 >
1158 > const _from = new Map<types.CompletionItemKind, languages.CompletionItemKind>([
1159 > [types.CompletionItemKind.Method, languages.CompletionItemKind.Method],
1160 > [types.CompletionItemKind.Function, languages.CompletionItemKind.Function],
1161 > [types.CompletionItemKind.Constructor, languages.CompletionItemKind.Constructor],
1162 > [types.CompletionItemKind.Field, languages.CompletionItemKind.Field],
1163 > [types.CompletionItemKind.Variable, languages.CompletionItemKind.Variable],
1164 > [types.CompletionItemKind.Class, languages.CompletionItemKind.Class],
1165 > [types.CompletionItemKind.Interface, languages.CompletionItemKind.Interface],
1166 > [types.CompletionItemKind.Struct, languages.CompletionItemKind.Struct],
1167 > [types.CompletionItemKind.Module, languages.CompletionItemKind.Module],
1168 > [types.CompletionItemKind.Property, languages.CompletionItemKind.Property],
1169 > [types.CompletionItemKind.Unit, languages.CompletionItemKind.Unit],
1170 > [types.CompletionItemKind.Value, languages.CompletionItemKind.Value],
1171 > [types.CompletionItemKind.Constant, languages.CompletionItemKind.Constant],
1172 > [types.CompletionItemKind.Enum, languages.CompletionItemKind.Enum],
1173 > [types.CompletionItemKind.EnumMember, languages.CompletionItemKind.EnumMember],
1174 > [types.CompletionItemKind.Keyword, languages.CompletionItemKind.Keyword],
1175 > [types.CompletionItemKind.Snippet, languages.CompletionItemKind.Snippet],
1176 > [types.CompletionItemKind.Text, languages.CompletionItemKind.Text],
1177 > [types.CompletionItemKind.Color, languages.CompletionItemKind.Color],
1178 > [types.CompletionItemKind.File, languages.CompletionItemKind.File],
1179 > [types.CompletionItemKind.Reference, languages.CompletionItemKind.Reference],
1180 > [types.CompletionItemKind.Folder, languages.CompletionItemKind.Folder],
1181 > [types.CompletionItemKind.Event, languages.CompletionItemKind.Event],
1182 > [types.CompletionItemKind.Operator, languages.CompletionItemKind.Operator],
1183 > [types.CompletionItemKind.TypeParameter, languages.CompletionItemKind.TypeParameter],
1184 > [types.CompletionItemKind.Issue, languages.CompletionItemKind.Issue],
1185 > [types.CompletionItemKind.User, languages.CompletionItemKind.User],
1186 > ]);
1187 >
1188 > export function from(kind: types.CompletionItemKind): languages.CompletionItemKind {
1189 return _from.get(kind) ?? languages.CompletionItemKind.Property;
1190 }
1192 > const _to = new Map<languages.CompletionItemKind, types.CompletionItemKind>([
1193 > [languages.CompletionItemKind.Method, types.CompletionItemKind.Method],
1194 > [languages.CompletionItemKind.Function, types.CompletionItemKind.Function],
1195 > [languages.CompletionItemKind.Constructor, types.CompletionItemKind.Constructor],
1196 > [languages.CompletionItemKind.Field, types.CompletionItemKind.Field],
1197 > [languages.CompletionItemKind.Variable, types.CompletionItemKind.Variable],
1198 > [languages.CompletionItemKind.Class, types.CompletionItemKind.Class],
1199 > [languages.CompletionItemKind.Interface, types.CompletionItemKind.Interface],
1200 > [languages.CompletionItemKind.Struct, types.CompletionItemKind.Struct],
1201 > [languages.CompletionItemKind.Module, types.CompletionItemKind.Module],
1202 > [languages.CompletionItemKind.Property, types.CompletionItemKind.Property],
1203 > [languages.CompletionItemKind.Unit, types.CompletionItemKind.Unit],
1204 > [languages.CompletionItemKind.Value, types.CompletionItemKind.Value],
1205 > [languages.CompletionItemKind.Constant, types.CompletionItemKind.Constant],
1206 > [languages.CompletionItemKind.Enum, types.CompletionItemKind.Enum],
1207 > [languages.CompletionItemKind.EnumMember, types.CompletionItemKind.EnumMember],
1208 > [languages.CompletionItemKind.Keyword, types.CompletionItemKind.Keyword],
1209 > [languages.CompletionItemKind.Snippet, types.CompletionItemKind.Snippet],
1210 > [languages.CompletionItemKind.Text, types.CompletionItemKind.Text],
1211 > [languages.CompletionItemKind.Color, types.CompletionItemKind.Color],
1212 > [languages.CompletionItemKind.File, types.CompletionItemKind.File],
1213 > [languages.CompletionItemKind.Reference, types.CompletionItemKind.Reference],
1214 > [languages.CompletionItemKind.Folder, types.CompletionItemKind.Folder],
1215 > [languages.CompletionItemKind.Event, types.CompletionItemKind.Event],
1216 > [languages.CompletionItemKind.Operator, types.CompletionItemKind.Operator],
1217 > [languages.CompletionItemKind.TypeParameter, types.CompletionItemKind.TypeParameter],
1218 > [languages.CompletionItemKind.User, types.CompletionItemKind.User],
1219 > [languages.CompletionItemKind.Issue, types.CompletionItemKind.Issue],
1220 > ]);
1221 >
1222 > export function to(kind: languages.CompletionItemKind): types.CompletionItemKind {
1223 return _to.get(kind) ?? types.CompletionItemKind.Property;
1224 }
1226 >
1227 > export namespace CompletionItem {
1228 >
1229 > export function to(suggestion: languages.CompletionItem, converter?: Command.ICommandsConverter): types.CompletionItem {
1230
1231 const result = new types.CompletionItem(suggestion.label);
1262 return result;
1263 }
1265 >
1266 > export namespace ParameterInformation {
1267 > export function from(info: types.ParameterInformation): languages.ParameterInformation {
1268 if (typeof info.label !== 'string' && !Array.isArray(info.label)) {
1269 throw new TypeError('Invalid label');
1275 };
1276 }
1277 > export function to(info: languages.ParameterInformation): types.ParameterInformation { extHostTypeConverters.ts
1278 return {
1279 label: info.label,
1281 };
1282 }
1284 >
1285 > export namespace SignatureInformation {
1286 >
1287 > export function from(info: types.SignatureInformation): languages.SignatureInformation {
1288 return {
1289 label: info.label,
1293 };
1294 }
1296 > export function to(info: languages.SignatureInformation): types.SignatureInformation {
1297 return {
1298 label: info.label,
1302 };
1303 }
1305 >
1306 > export namespace SignatureHelp {
1307 >
1308 > export function from(help: types.SignatureHelp): languages.SignatureHelp {
1309 return {
1310 activeSignature: help.activeSignature,
1313 };
1314 }
1316 > export function to(help: languages.SignatureHelp): types.SignatureHelp {
1317 return {
1318 activeSignature: help.activeSignature,
1321 };
1322 }
1324 >
1325 > export namespace InlayHint {
1326 >
1327 > export function to(converter: Command.ICommandsConverter, hint: languages.InlayHint): vscode.InlayHint {
1328 const res = new types.InlayHint(
1329 Position.to(hint.position),
1337 return res;
1338 }
1340 >
1341 > export namespace InlayHintLabelPart {
1342 >
1343 > export function to(converter: Command.ICommandsConverter, part: languages.InlayHintLabelPart): types.InlayHintLabelPart {
1344 const result = new types.InlayHintLabelPart(part.label);
1345 result.tooltip = htmlContent.isMarkdownString(part.tooltip)
1354 return result;
1355 }
1357 >
1358 > export namespace InlayHintKind {
1359 > export function from(kind: vscode.InlayHintKind): languages.InlayHintKind {
1360 return kind;
1361 }
1362 > export function to(kind: languages.InlayHintKind): vscode.InlayHintKind { extHostTypeConverters.ts
1363 return kind;
1364 }
1366 >
1367 > export namespace DocumentLink {
1368 >
1369 > export function from(link: vscode.DocumentLink): languages.ILink {
1370 return {
1371 range: Range.from(link.range),
1374 };
1375 }
1377 > export function to(link: languages.ILink): vscode.DocumentLink {
1378 let target: URI | undefined = undefined;
1379 if (link.url) {
1388 return result;
1389 }
1391 >
1392 > export namespace ColorPresentation {
1393 > export function to(colorPresentation: languages.IColorPresentation): types.ColorPresentation {
1394 const cp = new types.ColorPresentation(colorPresentation.label);
1395 if (colorPresentation.textEdit) {
1401 return cp;
1402 }
1404 > export function from(colorPresentation: vscode.ColorPresentation): languages.IColorPresentation {
1405 return {
1406 label: colorPresentation.label,
1409 };
1410 }
1412 >
1413 > export namespace Color {
1414 > export function to(c: [number, number, number, number]): types.Color {
1415 return new types.Color(c[0], c[1], c[2], c[3]);
1416 }
1417 > export function from(color: types.Color): [number, number, number, number] { extHostTypeConverters.ts
1418 return [color.red, color.green, color.blue, color.alpha];
1419 }
1421 >
1422 >
1423 > export namespace SelectionRange {
1424 > export function from(obj: vscode.SelectionRange): languages.SelectionRange {
1425 return { range: Range.from(obj.range) };
1426 }
1428 > export function to(obj: languages.SelectionRange): vscode.SelectionRange {
1429 return new types.SelectionRange(Range.to(obj.range));
1430 }
1432 >
1433 > export namespace TextDocumentSaveReason {
1434 >
1435 > export function to(reason: SaveReason): vscode.TextDocumentSaveReason {
1436 switch (reason) {
1437 case SaveReason.AUTO:
1444 }
1445 }
1447 >
1448 > export namespace TextEditorLineNumbersStyle {
1449 > export function from(style: vscode.TextEditorLineNumbersStyle): RenderLineNumbersType {
1450 switch (style) {
1451 case types.TextEditorLineNumbersStyle.Off:
1460 }
1461 }
1462 > export function to(style: RenderLineNumbersType): vscode.TextEditorLineNumbersStyle { extHostTypeConverters.ts
1463 switch (style) {
1464 case RenderLineNumbersType.Off:
1473 }
1474 }
1476 >
1477 > export namespace EndOfLine {
1478 >
1479 > export function from(eol: vscode.EndOfLine): EndOfLineSequence | undefined {
1480 if (eol === types.EndOfLine.CRLF) {
1481 return EndOfLineSequence.CRLF;
1485 return undefined;
1486 }
1488 > export function to(eol: EndOfLineSequence): vscode.EndOfLine | undefined {
1489 if (eol === EndOfLineSequence.CRLF) {
1490 return types.EndOfLine.CRLF;
1494 return undefined;
1495 }
1497 >
1498 > export namespace ProgressLocation {
1499 > export function from(loc: vscode.ProgressLocation | { viewId: string }): MainProgressLocation | string {
1500 if (typeof loc === 'object') {
1501 return loc.viewId;
1509 throw new Error(`Unknown 'ProgressLocation'`);
1510 }
1512 >
1513 > export namespace FoldingRange {
1514 > export function from(r: vscode.FoldingRange): languages.FoldingRange {
1515 const range: languages.FoldingRange = { start: r.start + 1, end: r.end + 1 };
1516 if (r.kind) {
1519 return range;
1520 }
1521 > export function to(r: languages.FoldingRange): vscode.FoldingRange { extHostTypeConverters.ts
1522 const range: vscode.FoldingRange = { start: r.start - 1, end: r.end - 1 };
1523 if (r.kind) {
1526 return range;
1527 }
1529 >
1530 > export namespace FoldingRangeKind {
1531 > export function from(kind: vscode.FoldingRangeKind | undefined): languages.FoldingRangeKind | undefined {
1532 if (kind) {
1533 switch (kind) {
1542 return undefined;
1543 }
1544 > export function to(kind: languages.FoldingRangeKind | undefined): vscode.FoldingRangeKind | undefined { extHostTypeConverters.ts
1545 if (kind) {
1546 switch (kind.value) {
1555 return undefined;
1556 }
1558 >
1559 > export interface TextEditorOpenOptions extends vscode.TextDocumentShowOptions {
1560 > background?: boolean;
1561 > override?: boolean;
1562 > }
1563 >
1564 > export namespace TextEditorOpenOptions {
1565 >
1566 > export function from(options?: TextEditorOpenOptions): ITextEditorOptions | undefined {
1567 if (options) {
1568 return {
1577 return undefined;
1578 }
1580 > }
1581 >
1582 > export namespace GlobPattern {
1583 >
1584 > export function from(pattern: vscode.GlobPattern): string | extHostProtocol.IRelativePatternDto;
1585 > export function from(pattern: undefined): undefined;
1586 > export function from(pattern: null): null;
1587 > export function from(pattern: vscode.GlobPattern | undefined | null): string | extHostProtocol.IRelativePatternDto | undefined | null;
1588 > export function from(pattern: vscode.GlobPattern | undefined | null): string | extHostProtocol.IRelativePatternDto | undefined | null {
1589 if (pattern instanceof types.RelativePattern) {
1590 return pattern.toJSON();
1606 return pattern; // preserve `undefined` and `null`
1607 }
1609 > function isRelativePatternShape(obj: unknown): obj is { base: string; baseUri: URI; pattern: string } {
1610 const rp = obj as { base: string; baseUri: URI; pattern: string } | undefined | null;
1611 if (!rp) {
1615 return URI.isUri(rp.baseUri) && typeof rp.pattern === 'string';
1616 }
1618 > function isLegacyRelativePatternShape(obj: unknown): obj is { base: string; pattern: string } {
1619
1620 // Before 1.64.x, `RelativePattern` did not have any `baseUri: Uri`
1629 return typeof rp.base === 'string' && typeof rp.pattern === 'string';
1630 }
1632 > export function to(pattern: string | extHostProtocol.IRelativePatternDto): vscode.GlobPattern {
1633 if (typeof pattern === 'string') {
1634 return pattern;
1637 return new types.RelativePattern(URI.revive(pattern.baseUri), pattern.pattern);
1638 }
1640 >
1641 > export namespace LanguageSelector {
1642 >
1643 > export function from(selector: undefined): undefined;
1644 > export function from(selector: vscode.DocumentSelector): languageSelector.LanguageSelector;
1645 > export function from(selector: vscode.DocumentSelector | undefined): languageSelector.LanguageSelector | undefined;
1646 > export function from(selector: vscode.DocumentSelector | undefined): languageSelector.LanguageSelector | undefined {
1647 if (!selector) {
1648 return undefined;
1662 }
1663 }
1665 >
1666 > export namespace NotebookRange {
1667 >
1668 > export function from(range: vscode.NotebookRange): ICellRange {
1669 return { start: range.start, end: range.end };
1670 }
1672 > export function to(range: ICellRange): types.NotebookRange {
1673 return new types.NotebookRange(range.start, range.end);
1674 }
1676 >
1677 > export namespace NotebookCellExecutionSummary {
1678 > export function to(data: notebooks.NotebookCellInternalMetadata): vscode.NotebookCellExecutionSummary {
1679 return {
1680 timing: typeof data.runStartTime === 'number' && typeof data.runEndTime === 'number' ? { startTime: data.runStartTime, endTime: data.runEndTime } : undefined,
1683 };
1684 }
1686 > export function from(data: vscode.NotebookCellExecutionSummary): Partial<notebooks.NotebookCellInternalMetadata> {
1687 return {
1688 lastRunSuccess: data.success,
1692 };
1693 }
1695 >
1696 > export namespace NotebookCellKind {
1697 > export function from(data: vscode.NotebookCellKind): notebooks.CellKind {
1698 switch (data) {
1699 case types.NotebookCellKind.Markup:
1704 }
1705 }
1707 > export function to(data: notebooks.CellKind): vscode.NotebookCellKind {
1708 switch (data) {
1709 case notebooks.CellKind.Markup:
1714 }
1715 }
1717 >
1718 > export namespace NotebookData {
1719 >
1720 > export function from(data: vscode.NotebookData): extHostProtocol.NotebookDataDto {
1721 const res: extHostProtocol.NotebookDataDto = {
1722 metadata: data.metadata ?? Object.create(null),
1729 return res;
1730 }
1732 > export function to(data: extHostProtocol.NotebookDataDto): vscode.NotebookData {
1733 const res = new types.NotebookData(
1734 data.cells.map(NotebookCellData.to),
1739 return res;
1740 }
1742 >
1743 > export namespace NotebookCellData {
1744 >
1745 > export function from(data: vscode.NotebookCellData): extHostProtocol.NotebookCellDataDto {
1746 return {
1747 cellKind: NotebookCellKind.from(data.kind),
1754 };
1755 }
1757 > export function to(data: extHostProtocol.NotebookCellDataDto): vscode.NotebookCellData {
1758 return new types.NotebookCellData(
1759 NotebookCellKind.to(data.cellKind),
1766 );
1767 }
1769 >
1770 > export namespace NotebookCellOutputItem {
1771 > export function from(item: types.NotebookCellOutputItem): extHostProtocol.NotebookOutputItemDto {
1772 return {
1773 mime: item.mime,
1775 };
1776 }
1778 > export function to(item: extHostProtocol.NotebookOutputItemDto): types.NotebookCellOutputItem {
1779 return new types.NotebookCellOutputItem(item.valueBytes.buffer, item.mime);
1780 }
1782 >
1783 > export namespace NotebookCellOutput {
1784 > export function from(output: vscode.NotebookCellOutput): extHostProtocol.NotebookOutputDto {
1785 return {
1786 outputId: output.id,
1789 };
1790 }
1792 > export function to(output: extHostProtocol.NotebookOutputDto): vscode.NotebookCellOutput {
1793 const items = output.items.map(NotebookCellOutputItem.to);
1794 return new types.NotebookCellOutput(items, output.outputId, output.metadata);
1795 }
1797 >
1798 >
1799 > export namespace NotebookExclusiveDocumentPattern {
1800 > export function from(pattern: { include: vscode.GlobPattern | undefined; exclude: vscode.GlobPattern | undefined }): { include: string | extHostProtocol.IRelativePatternDto | undefined; exclude: string | extHostProtocol.IRelativePatternDto | undefined };
1801 > export function from(pattern: vscode.GlobPattern): string | extHostProtocol.IRelativePatternDto;
1802 > export function from(pattern: undefined): undefined;
1803 > export function from(pattern: { include: vscode.GlobPattern | undefined | null; exclude: vscode.GlobPattern | undefined } | vscode.GlobPattern | undefined): string | extHostProtocol.IRelativePatternDto | { include: string | extHostProtocol.IRelativePatternDto | undefined; exclude: string | extHostProtocol.IRelativePatternDto | undefined } | undefined;
1804 > export function from(pattern: { include: vscode.GlobPattern | undefined | null; exclude: vscode.GlobPattern | undefined } | vscode.GlobPattern | undefined): string | extHostProtocol.IRelativePatternDto | { include: string | extHostProtocol.IRelativePatternDto | undefined; exclude: string | extHostProtocol.IRelativePatternDto | undefined } | undefined {
1805 if (isExclusivePattern(pattern)) {
1806 return {
1812 return GlobPattern.from(pattern) ?? undefined;
1813 }
1815 > export function to(pattern: string | extHostProtocol.IRelativePatternDto | { include: string | extHostProtocol.IRelativePatternDto; exclude: string | extHostProtocol.IRelativePatternDto }): { include: vscode.GlobPattern; exclude: vscode.GlobPattern } | vscode.GlobPattern {
1816 if (isExclusivePattern(pattern)) {
1817 return {
1823 return GlobPattern.to(pattern);
1824 }
1826 > function isExclusivePattern<T>(obj: any): obj is { include?: T; exclude?: T } {
1827 const ep = obj as { include?: T; exclude?: T } | undefined | null;
1828 if (!ep) {
1831 return !isUndefinedOrNull(ep.include) && !isUndefinedOrNull(ep.exclude);
1832 }
1834 >
1835 > export namespace NotebookStatusBarItem {
1836 > export function from(item: vscode.NotebookCellStatusBarItem, commandsConverter: Command.ICommandsConverter, disposables: DisposableStore): notebooks.INotebookCellStatusBarItem {
1837 const command = typeof item.command === 'string' ? { title: '', command: item.command } : item.command;
1838 return {
1845 };
1846 }
1848 >
1849 > export namespace NotebookKernelSourceAction {
1850 > export function from(item: vscode.NotebookKernelSourceAction, commandsConverter: Command.ICommandsConverter, disposables: DisposableStore): notebooks.INotebookKernelSourceAction {
1851 const command = typeof item.command === 'string' ? { title: '', command: item.command } : item.command;
1852
1859 };
1860 }
1862 >
1863 > export namespace NotebookDocumentContentOptions {
1864 > export function from(options: vscode.NotebookDocumentContentOptions | undefined): notebooks.TransientOptions {
1865 return {
1866 transientOutputs: options?.transientOutputs ?? false,
1870 };
1871 }
1873 >
1874 > export namespace NotebookRendererScript {
1875 > export function from(preload: vscode.NotebookRendererScript): { uri: UriComponents; provides: readonly string[] } {
1876 return {
1877 uri: preload.uri,
1879 };
1880 }
1882 > export function to(preload: { uri: UriComponents; provides: readonly string[] }): vscode.NotebookRendererScript {
1883 return new types.NotebookRendererScript(URI.revive(preload.uri), preload.provides);
1884 }
1886 >
1887 > export namespace TestMessage {
1888 > export function from(message: vscode.TestMessage): ITestErrorMessage.Serialized {
1889 return {
1890 message: MarkdownString.fromStrict(message.message) || '',
1901 };
1902 }
1904 > export function to(item: ITestErrorMessage.Serialized): vscode.TestMessage {
1905 const message = new types.TestMessage(typeof item.message === 'string' ? item.message : MarkdownString.to(item.message));
1906 message.actualOutput = item.actual;
1910 return message;
1911 }
1913 >
1914 > export namespace TestTag {
1915 > export const namespace = namespaceTestTag;
1916 >
1917 > export const denamespace = denamespaceTestTag;
1918 > }
1919 >
1920 > export namespace TestRunProfile {
1921 > export function from(item: types.TestRunProfileBase): ITestRunProfileReference {
1922 return {
1923 controllerId: item.controllerId,
1926 };
1927 }
1929 >
1930 > export namespace TestRunProfileKind {
1931 > const profileGroupToBitset: { [K in vscode.TestRunProfileKind]: TestRunProfileBitset } = {
1932 > [types.TestRunProfileKind.Coverage]: TestRunProfileBitset.Coverage,
1933 > [types.TestRunProfileKind.Debug]: TestRunProfileBitset.Debug,
1934 > [types.TestRunProfileKind.Run]: TestRunProfileBitset.Run,
1935 > };
1936 >
1937 > export function from(kind: types.TestRunProfileKind): TestRunProfileBitset {
1938 return profileGroupToBitset.hasOwnProperty(kind) ? profileGroupToBitset[kind] : TestRunProfileBitset.Run;
1939 }
1941 >
1942 > export namespace TestItem {
1943 > export type Raw = vscode.TestItem;
1944 >
1945 > export function from(item: vscode.TestItem): ITestItem {
1946 const ctrlId = getPrivateApiFor(item).controllerId;
1947 return {
1957 };
1958 }
1960 > export function toPlain(item: ITestItem.Serialized): vscode.TestItem {
1961 return {
1962 parent: undefined,
1985 };
1986 }
1988 >
1989 > export namespace TestTag {
1990 > export function from(tag: vscode.TestTag): ITestTag {
1991 return { id: tag.id };
1992 }
1994 > export function to(tag: ITestTag): vscode.TestTag {
1995 return new types.TestTag(tag.id);
1996 }
1998 >
1999 > export namespace TestResults {
2000 > const convertTestResultItem = (node: IPrefixTreeNode<TestResultItem.Serialized>, parent?: vscode.TestResultSnapshot): vscode.TestResultSnapshot | undefined => {
2001 const item = node.value;
2002 if (!item) {
2028 return snapshot;
2029 };
2031 > export function to(serialized: ISerializedTestResults): vscode.TestRunResult {
2032 const tree = new WellDefinedPrefixTree<TestResultItem.Serialized>();
2033 for (const item of serialized.items) {
2053 };
2054 }
2056 >
2057 > export namespace TestCoverage {
2058 > function fromCoverageCount(count: vscode.TestCoverageCount): ICoverageCount {
2059 return { covered: count.covered, total: count.total };
2060 }
2062 > function fromLocation(location: vscode.Range | vscode.Position) {
2063 return 'line' in location ? Position.from(location) : Range.from(location);
2064 }
2066 > function toLocation(location: IPosition | editorRange.IRange): types.Position | types.Range;
2067 > function toLocation(location: IPosition | editorRange.IRange | undefined): types.Position | types.Range | undefined;
2068 > function toLocation(location: IPosition | editorRange.IRange | undefined): types.Position | types.Range | undefined {
2069 if (!location) { return undefined; }
2070 return 'endLineNumber' in location ? Range.to(location) : Position.to(location);
2071 }
2073 > export function to(serialized: CoverageDetails.Serialized): vscode.FileCoverageDetail {
2074 if (serialized.type === DetailType.Statement) {
2075 const branches: vscode.BranchCoverage[] = [];
2100 }
2101 }
2103 > export function fromDetails(coverage: vscode.FileCoverageDetail): CoverageDetails.Serialized {
2104 if (typeof coverage.executed === 'number' && coverage.executed < 0) {
2105 throw new Error(`Invalid coverage count ${coverage.executed}`);
2124 }
2125 }
2127 > export function fromFile(controllerId: string, id: string, coverage: vscode.FileCoverage): IFileCoverage.Serialized {
2128 types.validateTestCoverageCount(coverage.statementCoverage);
2129 types.validateTestCoverageCount(coverage.branchCoverage);
2140 };
2141 }
2143 >
2144 > export namespace CodeActionTriggerKind {
2145 >
2146 > export function to(value: languages.CodeActionTriggerType): types.CodeActionTriggerKind {
2147 switch (value) {
2148 case languages.CodeActionTriggerType.Invoke:
2153 }
2154 }
2156 >
2157 > export namespace TypeHierarchyItem {
2158 >
2159 > export function to(item: extHostProtocol.ITypeHierarchyItemDto): types.TypeHierarchyItem {
2160 const result = new types.TypeHierarchyItem(
2161 SymbolKind.to(item.kind),
2172 return result;
2173 }
2175 > export function from(item: vscode.TypeHierarchyItem, sessionId?: string, itemId?: string): extHostProtocol.ITypeHierarchyItemDto {
2176
2177 sessionId = sessionId ?? (<types.TypeHierarchyItem>item)._sessionId;
2194 };
2195 }
2197 >
2198 > export namespace ViewBadge {
2199 > export function from(badge: vscode.ViewBadge | undefined): IViewBadge | undefined {
2200 if (!badge) {
2201 return undefined;
2207 };
2208 }
2210 >
2211 > export namespace DataTransferItem {
2212 > export function to(mime: string, item: extHostProtocol.DataTransferItemDTO, resolveFileData: (id: string) => Promise<Uint8Array>): types.DataTransferItem {
2213 const file = item.fileData;
2214 if (file) {
2223 return new types.InternalDataTransferItem(item.asString);
2224 }
2226 > export async function from(mime: string, item: vscode.DataTransferItem | IDataTransferItem, id: string = generateUuid()): Promise<extHostProtocol.DataTransferItemDTO> {
2227 const stringValue = await item.asString();
2228
2247 };
2248 }
2250 > function serializeUriList(stringValue: string): ReadonlyArray<string | URI> {
2251 return UriList.split(stringValue).map(part => {
2252 if (part.startsWith('#')) {
2263 });
2264 }
2266 > function reviveUriList(parts: ReadonlyArray<string | UriComponents>): string {
2267 return UriList.create(parts.map(part => {
2268 return typeof part === 'string' ? part : URI.revive(part);
2269 }));
2270 }
2272 >
2273 > export namespace DataTransfer {
2274 > export function toDataTransfer(value: extHostProtocol.DataTransferDTO, resolveFileData: (itemId: string) => Promise<Uint8Array>): types.DataTransfer {
2275 const init = value.items.map(([type, item]) => {
2276 return [type, DataTransferItem.to(type, item, resolveFileData)] as const;
2278 return new types.DataTransfer(init);
2279 }
2281 > export async function from(dataTransfer: vscode.DataTransfer): Promise<extHostProtocol.DataTransferDTO> {
2282 const items = await Promise.all(Array.from(dataTransfer, async ([mime, value]) => {
2283 return [mime, await DataTransferItem.from(mime, value)] as const;
2286 return { items };
2287 }
2289 > export async function fromList(dataTransfer: Iterable<readonly [string, IDataTransferItem]>): Promise<extHostProtocol.DataTransferDTO> {
2290 const items = await Promise.all(Array.from(dataTransfer, async ([mime, value]) => {
2291 return [mime, await DataTransferItem.from(mime, value, value.id)] as const;
2294 return { items };
2295 }
2297 >
2298 > export namespace ChatFollowup {
2299 > export function from(followup: vscode.ChatFollowup, request: IChatAgentRequest | undefined): IChatFollowup {
2300 return {
2301 kind: 'reply',
2306 };
2307 }
2309 > export function to(followup: IChatFollowup): vscode.ChatFollowup {
2310 return {
2311 prompt: followup.message,
2315 };
2316 }
2318 >
2319 > export namespace LanguageModelChatMessageRole {
2320 > export function to(role: chatProvider.ChatMessageRole): vscode.LanguageModelChatMessageRole {
2321 switch (role) {
2322 case chatProvider.ChatMessageRole.System: return types.LanguageModelChatMessageRole.System;
2325 }
2326 }
2328 > export function from(role: vscode.LanguageModelChatMessageRole): chatProvider.ChatMessageRole {
2329 switch (role) {
2330 case types.LanguageModelChatMessageRole.System: return chatProvider.ChatMessageRole.System;
2334 return chatProvider.ChatMessageRole.User;
2335 }
2337 >
2338 > export namespace LanguageModelChatMessage {
2339 >
2340 > export function to(message: chatProvider.IChatMessage): vscode.LanguageModelChatMessage {
2341 const content = message.content.map(c => {
2342 if (c.type === 'text') {
2370 return result;
2371 }
2373 > export function from(message: vscode.LanguageModelChatMessage): chatProvider.IChatMessage {
2374
2375 const role = LanguageModelChatMessageRole.from(message.role);
2461 };
2462 }
2464 >
2465 > export namespace LanguageModelChatMessage2 {
2466 >
2467 > export function to(message: chatProvider.IChatMessage): vscode.LanguageModelChatMessage2 {
2468 const content = message.content.map(c => {
2469 if (c.type === 'text') {
2494 return result;
2495 }
2497 > export function from(message: vscode.LanguageModelChatMessage2): chatProvider.IChatMessage {
2498
2499 const role = LanguageModelChatMessageRole.from(message.role);
2593 };
2594 }
2596 >
2597 function isImageDataPart(part: types.LanguageModelDataPart): boolean {
2598 const mime = typeof part.mimeType === 'string' ? part.mimeType.toLowerCase() : '';
2609 }
2610 }
2612 > export namespace ChatResponseMarkdownPart {
2613 > export function from(part: vscode.ChatResponseMarkdownPart): Dto<IChatMarkdownContent> {
2614 return {
2615 kind: 'markdownContent',
2617 };
2618 }
2619 > export function to(part: Dto<IChatMarkdownContent>): vscode.ChatResponseMarkdownPart { extHostTypeConverters.ts
2620 return new types.ChatResponseMarkdownPart(MarkdownString.to(part.content));
2621 }
2623 >
2624 > export namespace ChatResponseCodeblockUriPart {
2625 > export function from(part: vscode.ChatResponseCodeblockUriPart): Dto<IChatResponseCodeblockUriPart> {
2626 return {
2627 kind: 'codeblockUri',
2631 };
2632 }
2633 > export function to(part: Dto<IChatResponseCodeblockUriPart>): vscode.ChatResponseCodeblockUriPart { extHostTypeConverters.ts
2634 return new types.ChatResponseCodeblockUriPart(URI.revive(part.uri), part.isEdit, part.undoStopId);
2635 }
2637 >
2638 > export namespace ChatResponseMarkdownWithVulnerabilitiesPart {
2639 > export function from(part: vscode.ChatResponseMarkdownWithVulnerabilitiesPart): Dto<IChatAgentMarkdownContentWithVulnerability> {
2640 return {
2641 kind: 'markdownVuln',
2644 };
2645 }
2646 > export function to(part: Dto<IChatAgentMarkdownContentWithVulnerability>): vscode.ChatResponseMarkdownWithVulnerabilitiesPart { extHostTypeConverters.ts
2647 return new types.ChatResponseMarkdownWithVulnerabilitiesPart(MarkdownString.to(part.content), part.vulnerabilities);
2648 }
2650 >
2651 > export namespace ChatResponseConfirmationPart {
2652 > export function from(part: vscode.ChatResponseConfirmationPart): Dto<IChatConfirmation> {
2653 return {
2654 kind: 'confirmation',
2659 };
2660 }
2662 >
2663 > export namespace ChatResponseQuestionCarouselPart {
2664 > function questionTypeToString(type: vscode.ChatQuestionType): 'text' | 'singleSelect' | 'multiSelect' {
2665 switch (type) {
2666 case types.ChatQuestionType.Text: return 'text';
2670 }
2671 }
2673 > function stringToQuestionType(type: 'text' | 'singleSelect' | 'multiSelect'): vscode.ChatQuestionType {
2674 switch (type) {
2675 case 'text': return types.ChatQuestionType.Text;
2679 }
2680 }
2682 > export function from(part: vscode.ChatResponseQuestionCarouselPart): Dto<IChatQuestionCarousel> {
2683 return {
2684 kind: 'questionCarousel',
2695 };
2696 }
2698 > export function to(part: Dto<IChatQuestionCarousel>): vscode.ChatResponseQuestionCarouselPart {
2699 const questions = part.questions.map(q => new types.ChatQuestion(
2700 q.id,
2714 return new types.ChatResponseQuestionCarouselPart(questions, part.allowSkip);
2715 }
2717 >
2718 > export namespace ChatResponseFilesPart {
2719 > export function from(part: vscode.ChatResponseFileTreePart): IChatTreeData {
2720 const { value, baseUri } = part;
2721 function convert(items: vscode.ChatResponseFileTree[], baseUri: URI): extHostProtocol.IChatResponseProgressFileTreeData[] {
2738 };
2739 }
2740 > export function to(part: Dto<IChatTreeData>): vscode.ChatResponseFileTreePart { extHostTypeConverters.ts
2741 const treeData = revive<extHostProtocol.IChatResponseProgressFileTreeData>(part.treeData);
2742 function convert(items: extHostProtocol.IChatResponseProgressFileTreeData[]): vscode.ChatResponseFileTree[] {
2753 return new types.ChatResponseFileTreePart(items, baseUri);
2754 }
2756 >
2757 > export namespace ChatResponseMultiDiffPart {
2758 > export function from(part: vscode.ChatResponseMultiDiffPart): IChatMultiDiffDataSerialized {
2759 return {
2760 kind: 'multiDiffData',
2772 };
2773 }
2774 > export function to(part: IChatMultiDiffDataSerialized): vscode.ChatResponseMultiDiffPart { extHostTypeConverters.ts
2775 const resources = part.multiDiffData.resources.map(resource => ({
2776 originalUri: resource.originalUri ? URI.revive(resource.originalUri) : undefined,
2782 return new types.ChatResponseMultiDiffPart(resources, part.multiDiffData.title, part.readOnly);
2783 }
2785 >
2786 > export namespace ChatResponseAnchorPart {
2787 > export function from(part: vscode.ChatResponseAnchorPart): Dto<IChatContentInlineReference> {
2788 // Work around type-narrowing confusion between vscode.Uri and URI
2789 const isUri = (thing: unknown): thing is vscode.Uri => URI.isUri(thing);
2800 };
2801 }
2803 > export function to(part: Dto<IChatContentInlineReference>): vscode.ChatResponseAnchorPart {
2804 const value = revive<IChatContentInlineReference>(part);
2805 return new types.ChatResponseAnchorPart(
2812 );
2813 }
2815 >
2816 > export namespace ChatResponseProgressPart {
2817 > export function from(part: vscode.ChatResponseProgressPart): Dto<IChatProgressMessage> {
2818 return {
2819 kind: 'progressMessage',
2821 };
2822 }
2823 > export function to(part: Dto<IChatProgressMessage>): vscode.ChatResponseProgressPart { extHostTypeConverters.ts
2824 return new types.ChatResponseProgressPart(part.content.value);
2825 }
2827 >
2828 > export namespace ChatResponseThinkingProgressPart {
2829 > export function from(part: vscode.ChatResponseThinkingProgressPart): Dto<IChatThinkingPart> {
2830 return {
2831 kind: 'thinking',
2835 };
2836 }
2837 > export function to(part: Dto<IChatThinkingPart>): vscode.ChatResponseThinkingProgressPart { extHostTypeConverters.ts
2838 return new types.ChatResponseThinkingProgressPart(part.value ?? '', part.id, part.metadata);
2839 }
2841 >
2842 > export namespace ChatResponseHookPart {
2843 > export function from(part: vscode.ChatResponseHookPart): Dto<IChatHookPart> {
2844 return {
2845 kind: 'hook',
2850 };
2851 }
2852 > export function to(part: Dto<IChatHookPart>): vscode.ChatResponseHookPart { extHostTypeConverters.ts
2853 return new types.ChatResponseHookPart(part.hookType, part.stopReason, part.systemMessage, part.metadata);
2854 }
2856 >
2857 > export namespace ChatResponseAutoModeResolutionPart {
2858 > const validLabels = new Set<IChatAutoModeResolutionPart['predictedLabel']>(['needs_reasoning', 'no_reasoning', 'fallback']);
2859 >
2860 > export function from(part: vscode.ChatResponseAutoModeResolutionPart): Dto<IChatAutoModeResolutionPart> {
2861 const label = validLabels.has(part.predictedLabel as IChatAutoModeResolutionPart['predictedLabel'])
2862 ? part.predictedLabel as IChatAutoModeResolutionPart['predictedLabel']
2870 };
2871 }
2872 > export function to(part: Dto<IChatAutoModeResolutionPart>): vscode.ChatResponseAutoModeResolutionPart { extHostTypeConverters.ts
2873 return new types.ChatResponseAutoModeResolutionPart(part.resolvedModel, part.resolvedModelName, part.predictedLabel, part.confidence);
2874 }
2876 >
2877 > export namespace ChatResponseWarningPart {
2878 > export function from(part: vscode.ChatResponseWarningPart): Dto<IChatWarningMessage> {
2879 return {
2880 kind: 'warning',
2882 };
2883 }
2884 > export function to(part: Dto<IChatWarningMessage>): vscode.ChatResponseWarningPart { extHostTypeConverters.ts
2885 return new types.ChatResponseWarningPart(part.content.value);
2886 }
2888 >
2889 > export namespace ChatResponseInfoPart {
2890 > export function from(part: vscode.ChatResponseInfoPart): Dto<IChatInfoMessage> {
2891 return {
2892 kind: 'info',
2894 };
2895 }
2896 > export function to(part: Dto<IChatInfoMessage>): vscode.ChatResponseInfoPart { extHostTypeConverters.ts
2897 return new types.ChatResponseInfoPart(part.content.value);
2898 }
2900 >
2901 > export namespace ChatResponseExtensionsPart {
2902 > export function from(part: vscode.ChatResponseExtensionsPart): Dto<IChatExtensionsContent> {
2903 return {
2904 kind: 'extensions',
2906 };
2907 }
2909 >
2910 > export namespace ChatResponsePullRequestPart {
2911 > export function from(part: Omit<vscode.ChatResponsePullRequestPart, 'command'> & { command?: vscode.Command }, commandsConverter: CommandsConverter, commandDisposables: DisposableStore): Dto<IChatPullRequestContent> {
2912 // If the command isn't in the converter, then this session may have been restored, and the command args don't exist anymore
2913 let command: extHostProtocol.ICommandDto;
2934 };
2935 }
2937 >
2938 > export namespace ChatResponseMovePart {
2939 > export function from(part: vscode.ChatResponseMovePart): Dto<IChatMoveMessage> {
2940 return {
2941 kind: 'move',
2944 };
2945 }
2946 > export function to(part: Dto<IChatMoveMessage>): vscode.ChatResponseMovePart { extHostTypeConverters.ts
2947 return new types.ChatResponseMovePart(URI.revive(part.uri), Range.to(part.range));
2948 }
2950 >
2951 > export namespace ChatToolInvocationPart {
2952 > export function from(part: vscode.ChatToolInvocationPart): IChatToolInvocationSerialized | IChatExternalToolInvocationUpdate {
2953 // Check if toolSpecificData is ChatMcpToolInvocationData (has input and output)
2954 // If so, convert to resultDetails for rendering via ChatInputOutputMarkdownProgressPart
3005 };
3006 }
3008 > function isChatMcpToolInvocationData(data: any): data is vscode.ChatMcpToolInvocationData {
3009 return data !== null && typeof data === 'object' &&
3010 'input' in data && typeof data.input === 'string' &&
3011 'output' in data && Array.isArray(data.output);
3012 }
3014 > function convertMcpToResultDetails(data: vscode.ChatMcpToolInvocationData, isError?: boolean): IToolResultInputOutputDetails {
3015 return {
3016 input: data.input,
3027 };
3028 }
3030 > function convertToolSpecificData(data: any): any {
3031 // Convert extension API terminal tool data to internal format
3032 if ('command' in data && 'language' in data) {
3098 return data;
3099 }
3101 > function todoStatusEnumToString(status: types.ChatTodoStatus | string): string {
3102 // Handle enum values
3103 switch (status) {
3112 }
3113 }
3115 > function todoStatusStringToEnum(status: string): types.ChatTodoStatus {
3116 switch (status) {
3117 case 'not-started':
3125 }
3126 }
3128 > export function to(part: any): vscode.ChatToolInvocationPart {
3129 const toolInvocation = new types.ChatToolInvocationPart(
3130 part.toolId || part.toolName,
3156 return toolInvocation;
3157 }
3159 > function convertFromInternalToolSpecificData(data: any): any {
3160 // Convert internal terminal tool data to extension API format
3161 if (data.kind === 'terminal') {
3213 return data;
3214 }
3216 >
3217 > export namespace ChatTask {
3218 > export function from(part: vscode.ChatResponseProgressPart2): IChatTaskDto {
3219 return {
3220 kind: 'progressTask',
3222 };
3223 }
3225 >
3226 > export namespace ChatTaskResult {
3227 > export function from(part: string | void): Dto<IChatTaskResult> {
3228 return {
3229 kind: 'progressTaskResult',
3231 };
3232 }
3234 >
3235 > export namespace ChatResponseCommandButtonPart {
3236 > export function from(part: vscode.ChatResponseCommandButtonPart, commandsConverter: CommandsConverter, commandDisposables: DisposableStore): Dto<IChatCommandButton> {
3237 // If the command isn't in the converter, then this session may have been restored, and the command args don't exist anymore
3238 const command = commandsConverter.toInternal(part.value, commandDisposables) ?? { command: part.value.command, title: part.value.title };
3242 };
3243 }
3244 > export function to(part: Dto<IChatCommandButton>, commandsConverter: CommandsConverter): vscode.ChatResponseCommandButtonPart { extHostTypeConverters.ts
3245 // If the command isn't in the converter, then this session may have been restored, and the command args don't exist anymore
3246 return new types.ChatResponseCommandButtonPart(commandsConverter.fromInternal(part.command) ?? { command: part.command.id, title: part.command.title });
3247 }
3249 >
3250 > export namespace ChatResponseTextEditPart {
3251 > export function from(part: vscode.ChatResponseTextEditPart): Dto<IChatTextEdit> {
3252 return {
3253 kind: 'textEdit',
3257 };
3258 }
3259 > export function to(part: Dto<IChatTextEdit>): vscode.ChatResponseTextEditPart { extHostTypeConverters.ts
3260 const result = new types.ChatResponseTextEditPart(URI.revive(part.uri), part.edits.map(e => TextEdit.to(e)));
3261 result.isDone = part.done;
3262 return result;
3263 }
3265 > }
3266 >
3267 > export namespace NotebookEdit {
3268 > export function from(edit: vscode.NotebookEdit): extHostProtocol.ICellEditOperationDto {
3269 if (edit.newCellMetadata) {
3270 return {
3287 }
3288 }
3290 >
3291 >
3292 > export namespace ChatResponseNotebookEditPart {
3293 > export function from(part: vscode.ChatResponseNotebookEditPart): extHostProtocol.IChatNotebookEditDto {
3294 return {
3295 kind: 'notebookEdit',
3299 };
3300 }
3302 >
3303 > export namespace ChatResponseWorkspaceEditPart {
3304 > export function from(part: vscode.ChatResponseWorkspaceEditPart): IChatWorkspaceEdit {
3305 return {
3306 kind: 'workspaceEdit',
3311 };
3312 }
3314 >
3315 > export namespace ChatResponseReferencePart {
3316 > export function from(part: types.ChatResponseReferencePart): Dto<IChatContentReference> {
3317 const iconPath = ThemeIcon.isThemeIcon(part.iconPath) ? part.iconPath
3318 : URI.isUri(part.iconPath) ? { light: URI.revive(part.iconPath) }
3343 };
3344 }
3345 > export function to(part: Dto<IChatContentReference>): vscode.ChatResponseReferencePart { extHostTypeConverters.ts
3346 const value = revive<IChatContentReference>(part);
3347
3358 ) as vscode.ChatResponseReferencePart; // 'value' is extended with variableName
3359 }
3361 >
3362 > export namespace ChatResponseCodeCitationPart {
3363 > export function from(part: vscode.ChatResponseCodeCitationPart): Dto<IChatCodeCitation> {
3364 return {
3365 kind: 'codeCitation',
3369 };
3370 }
3372 >
3373 > export namespace ChatResponsePart {
3374 >
3375 > export function from(part: vscode.ExtendedChatResponsePart, commandsConverter: CommandsConverter, commandDisposables: DisposableStore): extHostProtocol.IChatProgressDto {
3376 if (part instanceof types.ChatResponseMarkdownPart) {
3377 return ChatResponseMarkdownPart.from(part);
3429 };
3430 }
3432 > export function to(part: extHostProtocol.IChatProgressDto, commandsConverter: CommandsConverter): vscode.ChatResponsePart | undefined {
3433 switch (part.kind) {
3434 case 'reference': return ChatResponseReferencePart.to(part);
3442 return undefined;
3443 }
3445 > export function toContent(part: extHostProtocol.IChatContentProgressDto, commandsConverter: CommandsConverter): vscode.ChatResponseMarkdownPart | vscode.ChatResponseFileTreePart | vscode.ChatResponseAnchorPart | vscode.ChatResponseCommandButtonPart | undefined {
3446 switch (part.kind) {
3447 case 'markdownContent': return ChatResponseMarkdownPart.to(part);
3454 return undefined;
3455 }
3457 >
3458 > export namespace ChatAgentRequest {
3459 > export function to(request: IChatAgentRequest, location2: vscode.ChatRequestEditorData | vscode.ChatRequestNotebookData | undefined, model: vscode.LanguageModelChat, modelConfiguration: IStringDictionary<unknown> | undefined, diagnostics: readonly [vscode.Uri, readonly vscode.Diagnostic[]][], tools: Map<vscode.LanguageModelToolInformation, boolean>, extension: IRelaxedExtensionDescription, logService: ILogService): vscode.ChatRequest {
3460
3461 const toolReferences: IChatRequestVariableEntry[] = [];
3544 return requestWithAllProps;
3545 }
3547 >
3548 > export namespace ChatLocation {
3549 > export function to(loc: ChatAgentLocation): types.ChatLocation {
3550 switch (loc) {
3551 case ChatAgentLocation.Notebook: return types.ChatLocation.Notebook;
3555 }
3556 }
3558 > export function from(loc: types.ChatLocation): ChatAgentLocation {
3559 switch (loc) {
3560 case types.ChatLocation.Notebook: return ChatAgentLocation.Notebook;
3564 }
3565 }
3567 >
3568 > export namespace ChatSessionCustomizationType {
3569 > export function from(type: types.ChatSessionCustomizationType): string {
3570 return type.id;
3571 }
3573 > export function to(id: string): types.ChatSessionCustomizationType {
3574 switch (id) {
3575 case 'agent': return types.ChatSessionCustomizationType.Agent;
3582 }
3583 }
3585 >
3586 > export namespace ChatPromptReference {
3587 > export function to(variable: IChatRequestVariableEntry, diagnostics: readonly [vscode.Uri, readonly vscode.Diagnostic[]][], logService: ILogService): vscode.ChatPromptReference | undefined {
3588 let value: vscode.ChatPromptReference['value'] = variable.value;
3589 if (!value) {
3648 };
3649 }
3651 >
3652 > export namespace ChatLanguageModelToolReference {
3653 > export function to(variable: IChatRequestVariableEntry): vscode.ChatLanguageModelToolReference {
3654 const value = variable.value;
3655 if (value) {
3662 };
3663 }
3665 >
3666 > namespace ChatLanguageModelToolReferences {
3667 > export function to(variables: readonly ChatRequestToolReferenceEntry[]): vscode.ChatLanguageModelToolReference[] {
3668 const toolReferences = [];
3669 for (const v of variables) {
3678 return toolReferences;
3679 }
3681 >
3682 > export namespace ChatRequestModeInstructions {
3683 > export function to(mode: IChatRequestModeInstructions | Dto<IChatRequestModeInstructions> | undefined): vscode.ChatRequestModeInstructions | undefined {
3684 if (mode) {
3685 return {
3695 return undefined;
3696 }
3698 > export function from(mode: vscode.ChatRequestModeInstructions | undefined): IChatRequestModeInstructions | undefined {
3699 if (mode) {
3700 return {
3716 return undefined;
3717 }
3719 >
3720 > export namespace ChatAgentCompletionItem {
3721 > export function from(item: vscode.ChatCompletionItem, commandsConverter: CommandsConverter, disposables: DisposableStore): extHostProtocol.IChatAgentCompletionItem {
3722 return {
3723 id: item.id,
3732 };
3733 }
3735 >
3736 > export namespace ChatAgentResult {
3737 > export function to(result: IChatAgentResult): vscode.ChatResult {
3738 return {
3739 errorDetails: result.errorDetails,
3743 };
3744 }
3745 > export function from(result: vscode.ChatResult): Dto<IChatAgentResult> { extHostTypeConverters.ts
3746 return {
3747 errorDetails: result.errorDetails,
3751 };
3752 }
3754 > function reviveMetadata(metadata: IChatAgentResult['metadata']) {
3755 return cloneAndChange(metadata, value => {
3756 if (value.$mid === MarshalledId.LanguageModelToolResult) {
3783 });
3784 }
3786 >
3787 > export namespace ChatAgentUserActionEvent {
3788 > export function to(result: IChatAgentResult, event: IChatUserActionEvent, commandsConverter: CommandsConverter): vscode.ChatUserActionEvent | undefined {
3789 if (event.action.kind === 'vote') {
3790 // Is the "feedback" type
3842 }
3843 }
3845 >
3846 > export namespace TerminalQuickFix {
3847 > export function from(quickFix: vscode.TerminalQuickFixTerminalCommand | vscode.TerminalQuickFixOpener | vscode.Command, converter: Command.ICommandsConverter, disposables: DisposableStore): extHostProtocol.ITerminalQuickFixTerminalCommandDto | extHostProtocol.ITerminalQuickFixOpenerDto | extHostProtocol.ICommandDto | undefined {
3848 if ('terminalCommand' in quickFix) {
3849 return { terminalCommand: quickFix.terminalCommand, shouldExecute: quickFix.shouldExecute };
3854 return converter.toInternal(quickFix, disposables);
3855 }
3857 > export namespace TerminalCompletionItemDto {
3858 > export function from(item: vscode.TerminalCompletionItem): extHostProtocol.ITerminalCompletionItemDto {
3859 return {
3860 ...item,
3862 };
3863 }
3865 >
3866 > export namespace TerminalCompletionList {
3867 > export function from(completions: vscode.TerminalCompletionList | vscode.TerminalCompletionItem[], pathSeparator: string): extHostProtocol.TerminalCompletionListDto {
3868 if (Array.isArray(completions)) {
3869 return {
3876 };
3877 }
3879 >
3880 > export namespace TerminalCompletionResourceOptions {
3881 > export function from(resourceOptions: vscode.TerminalCompletionResourceOptions, pathSeparator: string): extHostProtocol.TerminalCompletionResourceOptionsDto {
3882 return {
3883 ...resourceOptions,
3887 };
3888 }
3890 >
3891 > export namespace PartialAcceptInfo {
3892 > export function to(info: languages.PartialAcceptInfo): types.PartialAcceptInfo {
3893 return {
3894 kind: PartialAcceptTriggerKind.to(info.kind),
3896 };
3897 }
3899 >
3900 > export namespace PartialAcceptTriggerKind {
3901 > export function to(kind: languages.PartialAcceptTriggerKind): types.PartialAcceptTriggerKind {
3902 switch (kind) {
3903 case languages.PartialAcceptTriggerKind.Word:
3911 }
3912 }
3914 >
3915 > export namespace InlineCompletionEndOfLifeReason {
3916 > export function to<T>(reason: languages.InlineCompletionEndOfLifeReason<T>, convertFn: (item: T) => vscode.InlineCompletionItem | undefined): vscode.InlineCompletionEndOfLifeReason {
3917 if (reason.kind === languages.InlineCompletionEndOfLifeReasonKind.Ignored) {
3918 const supersededBy = reason.supersededBy ? convertFn(reason.supersededBy) : undefined;
3931 };
3932 }
3934 >
3935 > export namespace InlineCompletionHintStyle {
3936 > export function from(value: vscode.InlineCompletionDisplayLocationKind): languages.InlineCompletionHintStyle {
3937 if (value === types.InlineCompletionDisplayLocationKind.Label) {
3938 return languages.InlineCompletionHintStyle.Label;
3941 }
3942 }
3944 > export function to(kind: languages.InlineCompletionHintStyle): types.InlineCompletionDisplayLocationKind {
3945 switch (kind) {
3946 case languages.InlineCompletionHintStyle.Label:
3950 }
3951 }
3953 >
3954 > export namespace DebugTreeItem {
3955 > export function from(item: vscode.DebugTreeItem, id: number): IDebugVisualizationTreeItem {
3956 return {
3957 id,
3963 };
3964 }
3966 >
3967 > export namespace LanguageModelToolSource {
3968 > export function to(source: Dto<ToolDataSource>): vscode.LanguageModelToolInformation['source'] {
3969 if (source.type === 'mcp') {
3970 return new types.LanguageModelToolMCPSource(source.label, source.serverLabel || source.label, source.instructions);
3975 }
3976 }
3978 >
3979 > export namespace LanguageModelToolResult {
3980 > export function to(result: IToolResult): vscode.ExtendedLanguageModelToolResult {
3981 const toolResult = new types.LanguageModelToolResult(result.content.map(item => {
3982 if (item.kind === 'text') {
3996 return toolResult;
3997 }
3999 > export function from(result: vscode.ExtendedLanguageModelToolResult2, extension: IExtensionDescription): Dto<IToolResult> | SerializableObjectWithBuffers<Dto<IToolResult>> {
4000 if (result.toolResultMessage) {
4001 checkProposedApiEnabled(extension, 'chatParticipantPrivate');
4064 return hasBuffers ? new SerializableObjectWithBuffers(dto) : dto;
4065 }
4067 >
4068 > export namespace IconPath {
4069 > export function fromThemeIcon(iconPath: vscode.ThemeIcon): languages.IconPath {
4070 return iconPath;
4071 }
4073 > /**
4074 > * Converts a {@link vscode.IconPath} to an {@link extHostProtocol.IconPathDto}.
4075 > * @note This function will tolerate strings specified instead of URIs in IconPath for historical reasons.
4076 > * Such strings are treated as file paths and converted using {@link URI.file} function, not {@link URI.from}.
4077 > * See https://github.com/microsoft/vscode/issues/110432#issuecomment-726144556 for context.
4078 > */
4079 > export function from(value: undefined): undefined;
4080 > export function from(value: vscode.IconPath): extHostProtocol.IconPathDto;
4081 > export function from(value: vscode.IconPath | undefined): extHostProtocol.IconPathDto | undefined;
4082 > export function from(value: vscode.IconPath | undefined): extHostProtocol.IconPathDto | undefined {
4083 if (!value) {
4084 return undefined;
4097 }
4098 }
4100 > /**
4101 > * Converts a {@link extHostProtocol.IconPathDto} to a {@link vscode.IconPath}.
4102 > * @note This is a strict conversion and we assume types are correct in this case.
4103 > */
4104 > export function to(value: undefined): undefined;
4105 > export function to(value: extHostProtocol.IconPathDto): vscode.IconPath;
4106 > export function to(value: extHostProtocol.IconPathDto | undefined): vscode.IconPath | undefined;
4107 > export function to(value: extHostProtocol.IconPathDto | undefined): vscode.IconPath | undefined {
4108 if (!value) {
4109 return undefined;
4120 }
4121 }
4123 >
4124 > export namespace AiSettingsSearch {
4125 > export function fromSettingsSearchResult(result: vscode.SettingsSearchResult): AiSettingsSearchResult {
4126 return {
4127 query: result.query,
4130 };
4131 }
4133 > function fromSettingsSearchResultKind(kind: number): AiSettingsSearchResultKind {
4134 switch (kind) {
4135 case AiSettingsSearchResultKind.EMBEDDED:
4143 }
4144 }
4146 >
4147 > export namespace McpServerDefinition {
4148 > function isHttpConfig(candidate: vscode.McpServerDefinition): candidate is vscode.McpHttpServerDefinition {
4149 return !!(candidate as vscode.McpHttpServerDefinition).uri;
4150 }
4152 > export function from(item: vscode.McpServerDefinition): McpServerLaunch.Serialized {
4153 return McpServerLaunch.toSerialized(
4154 isHttpConfig(item)
4173 );
4174 }
4176 > /** Converts from the IPC DTO to the API type. */
4177 > export function to(dto: McpServerDefinitionType.Serialized): vscode.McpServerDefinition {
4178 const launch = McpServerLaunch.fromSerialized(dto.launch);
4179 if (launch.type === McpServerTransportType.HTTP) {
4198 }
4199 }
4201 >
4202 > export namespace SourceControlInputBoxValidationType {
4203 > export function from(type: number): InputValidationType {
4204 switch (type) {
4205 case types.SourceControlInputBoxValidationType.Error:
4213 }
4214 }
4216 >
4217 > export namespace ChatRequestHooksConverter {
4218 > export function to(hooks: ChatRequestHooks): vscode.ChatRequestHooks {
4219 const result: Record<string, vscode.ChatHookCommand[]> = {};
4220 for (const [hookType, commands] of Object.entries(hooks)) {
4235 return result;
4236 }
4238 >
4239 > export namespace ChatHookCommand {
4240 > export function to(hook: IParsedHookCommand): vscode.ChatHookCommand | undefined {
4241 const command = resolveEffectiveCommand(hook, OS);
4242 if (!command) {
4250 };
4251 }
4253 >
4254 > export namespace ChatSessionItem {
4255 >
4256 > function convertStatus(status: vscode.ChatSessionStatus | undefined): ChatSessionStatus | undefined {
4257 if (status === undefined) {
4258 return undefined;
4272 }
4273 }
4275 > export function from(sessionContent: vscode.ChatSessionItem): Dto<IChatSessionItem> {
4276 // Support both new (created, lastRequestStarted, lastRequestEnded) and old (startTime, endTime) timing properties
4277 const timing = sessionContent.timing;
src/vs/workbench/services/editor/common/editorGroupsService.ts 1075 covered LOC · 4 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- editorGroupsService.ts
2 > * Copyright (c) Microsoft 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 { IInstantiationService, createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
8 > import { IEditorPane, GroupIdentifier, EditorInputWithOptions, CloseDirection, IEditorPartOptions, IEditorPartOptionsChangeEvent, EditorsOrder, IVisibleEditorPane, IEditorCloseEvent, IUntypedEditorInput, isEditorInput, IEditorWillMoveEvent, IMatchEditorOptions, IActiveEditorChangeEvent, IFindEditorOptions, IToolbarActions } from '../../../common/editor.js';
9 > import { EditorInput } from '../../../common/editor/editorInput.js';
10 > import { IEditorOptions, IModalEditorNavigation, IModalEditorPartOptions } from '../../../../platform/editor/common/editor.js';
11 > import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
12 > import { IDimension } from '../../../../editor/common/core/2d/dimension.js';
13 > import { DisposableStore, IDisposable } from '../../../../base/common/lifecycle.js';
14 > import { ContextKeyValue, IContextKeyService, RawContextKey } from '../../../../platform/contextkey/common/contextkey.js';
15 > import { URI } from '../../../../base/common/uri.js';
16 > import { IGroupModelChangeEvent } from '../../../common/editor/editorGroupModel.js';
17 > import { IRectangle } from '../../../../platform/window/common/window.js';
18 > import { IMenuChangeEvent, MenuId } from '../../../../platform/actions/common/actions.js';
19 > import { DeepPartial } from '../../../../base/common/types.js';
20 >
21 > export const IEditorGroupsService = createDecorator<IEditorGroupsService>('editorGroupsService');
22 >
23 > export const enum GroupActivationReason {
24 >
25 > /**
26 > * Group was activated explicitly by user or programmatic action.
27 > */
28 > DEFAULT = 0,
29 >
30 > /**
31 > * Group was activated because a modal or auxiliary editor part was closing.
32 > */
33 > PART_CLOSE = 1
34 > }
35 >
36 > export interface IEditorGroupActivationEvent {
37 > readonly group: IEditorGroup;
38 > readonly reason: GroupActivationReason;
39 > }
40 >
41 > export const enum GroupDirection {
42 > UP,
43 > DOWN,
44 > LEFT,
45 > RIGHT
46 > }
47 >
48 > export const enum GroupOrientation {
49 > HORIZONTAL,
50 > VERTICAL
51 > }
52 >
53 > export const enum GroupLocation {
54 > FIRST,
55 > LAST,
56 > NEXT,
57 > PREVIOUS
58 > }
59 >
60 > export interface IFindGroupScope {
61 > readonly direction?: GroupDirection;
62 > readonly location?: GroupLocation;
63 > }
64 >
65 > export const enum GroupsArrangement {
66 > /**
67 > * Make the current active group consume the entire
68 > * editor area.
69 > */
70 > MAXIMIZE,
71 >
72 > /**
73 > * Make the current active group consume the maximum
74 > * amount of space possible.
75 > */
76 > EXPAND,
77 >
78 > /**
79 > * Size all groups evenly.
80 > */
81 > EVEN
82 > }
83 >
84 > export interface GroupLayoutArgument {
85 >
86 > /**
87 > * Only applies when there are multiple groups
88 > * arranged next to each other in a row or column.
89 > * If provided, their sum must be 1 to be applied
90 > * per row or column.
91 > */
92 > readonly size?: number;
93 >
94 > /**
95 > * Editor groups will be laid out orthogonal to the
96 > * parent orientation.
97 > */
98 > readonly groups?: GroupLayoutArgument[];
99 > }
100 >
101 > export interface EditorGroupLayout {
102 >
103 > /**
104 > * The initial orientation of the editor groups at the root.
105 > */
106 > readonly orientation: GroupOrientation;
107 >
108 > /**
109 > * The editor groups at the root of the layout.
110 > */
111 > readonly groups: GroupLayoutArgument[];
112 > }
113 >
114 > export const enum MergeGroupMode {
115 > COPY_EDITORS,
116 > MOVE_EDITORS
117 > }
118 >
119 > export interface IMergeGroupOptions {
120 > mode?: MergeGroupMode;
121 > readonly index?: number;
122 >
123 > /**
124 > * Set this to prevent editors already present in the
125 > * target group from moving to a different index as
126 > * they are in the source group.
127 > */
128 > readonly preserveExistingIndex?: boolean;
129 > }
130 >
131 > export interface ICloseEditorOptions {
132 > readonly preserveFocus?: boolean;
133 > }
134 >
135 > export type ICloseEditorsFilter = {
136 > readonly except?: EditorInput;
137 > readonly direction?: CloseDirection;
138 > readonly savedOnly?: boolean;
139 > readonly excludeSticky?: boolean;
140 > };
141 >
142 > export interface ICloseAllEditorsOptions {
143 > readonly excludeSticky?: boolean;
144 > readonly excludeConfirming?: boolean;
145 > }
146 >
147 > export interface IEditorReplacement {
148 > readonly editor: EditorInput;
149 > readonly replacement: EditorInput;
150 > readonly options?: IEditorOptions;
151 >
152 > /**
153 > * Skips asking the user for confirmation and doesn't
154 > * save the document. Only use this if you really need to!
155 > */
156 > readonly forceReplaceDirty?: boolean;
157 > }
158 >
159 > export function isEditorReplacement(replacement: unknown): replacement is IEditorReplacement {
160 const candidate = replacement as IEditorReplacement | undefined;
161
162 return isEditorInput(candidate?.editor) && isEditorInput(candidate?.replacement);
163 }
165 > export const enum GroupsOrder {
166 >
167 > /**
168 > * Groups sorted by creation order (oldest one first)
169 > */
170 > CREATION_TIME,
171 >
172 > /**
173 > * Groups sorted by most recent activity (most recent active first)
174 > */
175 > MOST_RECENTLY_ACTIVE,
176 >
177 > /**
178 > * Groups sorted by grid widget order
179 > */
180 > GRID_APPEARANCE
181 > }
182 >
183 > export interface IEditorSideGroup {
184 >
185 > /**
186 > * Open an editor in this group.
187 > *
188 > * @returns a promise that resolves around an IEditor instance unless
189 > * the call failed, or the editor was not opened as active editor.
190 > */
191 > openEditor(editor: EditorInput, options?: IEditorOptions): Promise<IEditorPane | undefined>;
192 > }
193 >
194 > export interface IEditorDropTargetDelegate {
195 >
196 > /**
197 > * A helper to figure out if the drop target contains the provided group.
198 > */
199 > containsGroup?(groupView: IEditorGroup): boolean;
200 > }
201 >
202 > /**
203 > * The basic primitive to work with editor groups. This interface is both implemented
204 > * by editor part component as well as the editor groups service that operates across
205 > * all opened editor parts.
206 > */
207 > export interface IEditorGroupsContainer {
208 >
209 > /**
210 > * An event for when the active editor group changes. The active editor
211 > * group is the default location for new editors to open.
212 > */
213 > readonly onDidChangeActiveGroup: Event<IEditorGroup>;
214 >
215 > /**
216 > * An event for when a new group was added.
217 > */
218 > readonly onDidAddGroup: Event<IEditorGroup>;
219 >
220 > /**
221 > * An event for when a group was removed.
222 > */
223 > readonly onDidRemoveGroup: Event<IEditorGroup>;
224 >
225 > /**
226 > * An event for when a group was moved.
227 > */
228 > readonly onDidMoveGroup: Event<IEditorGroup>;
229 >
230 > /**
231 > * An event for when a group gets activated.
232 > */
233 > readonly onDidActivateGroup: Event<IEditorGroupActivationEvent>;
234 >
235 > /**
236 > * An event for when the index of a group changes.
237 > */
238 > readonly onDidChangeGroupIndex: Event<IEditorGroup>;
239 >
240 > /**
241 > * An event for when the locked state of a group changes.
242 > */
243 > readonly onDidChangeGroupLocked: Event<IEditorGroup>;
244 >
245 > /**
246 > * An event for when the maximized state of a group changes.
247 > */
248 > readonly onDidChangeGroupMaximized: Event<boolean>;
249 >
250 > /**
251 > * An event that notifies when container options change.
252 > */
253 > readonly onDidChangeEditorPartOptions: Event<IEditorPartOptionsChangeEvent>;
254 >
255 > /**
256 > * A property that indicates when groups have been created
257 > * and are ready to be used in the container.
258 > */
259 > readonly isReady: boolean;
260 >
261 > /**
262 > * A promise that resolves when groups have been created
263 > * and are ready to be used in the container.
264 > *
265 > * Await this promise to safely work on the editor groups model
266 > * (for example, install editor group listeners).
267 > *
268 > * Use the `whenRestored` property to await visible editors
269 > * having fully resolved.
270 > */
271 > readonly whenReady: Promise<void>;
272 >
273 > /**
274 > * A promise that resolves when groups have been restored in
275 > * the container.
276 > *
277 > * For groups with active editor, the promise will resolve
278 > * when the visible editor has finished to resolve.
279 > *
280 > * Use the `whenReady` property to not await editors to
281 > * resolve.
282 > */
283 > readonly whenRestored: Promise<void>;
284 >
285 > /**
286 > * Find out if the container has UI state to restore
287 > * from a previous session.
288 > */
289 > readonly hasRestorableState: boolean;
290 >
291 > /**
292 > * An active group is the default location for new editors to open.
293 > */
294 > readonly activeGroup: IEditorGroup;
295 >
296 > /**
297 > * A side group allows a subset of methods on a group that is either
298 > * created to the side or picked if already there.
299 > */
300 > readonly sideGroup: IEditorSideGroup;
301 >
302 > /**
303 > * All groups that are currently visible in the container in the order
304 > * of their creation (oldest first).
305 > */
306 > readonly groups: readonly IEditorGroup[];
307 >
308 > /**
309 > * The number of editor groups that are currently opened in the
310 > * container.
311 > */
312 > readonly count: number;
313 >
314 > /**
315 > * The current layout orientation of the root group.
316 > */
317 > readonly orientation: GroupOrientation;
318 >
319 > /**
320 > * Access the options of the container.
321 > */
322 > readonly partOptions: IEditorPartOptions;
323 >
324 > /**
325 > * Enforce container options temporarily.
326 > */
327 > enforcePartOptions(options: DeepPartial<IEditorPartOptions>): IDisposable;
328 >
329 > /**
330 > * Get all groups that are currently visible in the container.
331 > *
332 > * @param order the order of the editors to use
333 > */
334 > getGroups(order: GroupsOrder): readonly IEditorGroup[];
335 >
336 > /**
337 > * Allows to convert a group identifier to a group.
338 > */
339 > getGroup(identifier: GroupIdentifier): IEditorGroup | undefined;
340 >
341 > /**
342 > * Set a group as active. An active group is the default location for new editors to open.
343 > */
344 > activateGroup(group: IEditorGroup | GroupIdentifier): IEditorGroup;
345 >
346 > /**
347 > * Returns the size of a group.
348 > */
349 > getSize(group: IEditorGroup | GroupIdentifier): { width: number; height: number };
350 >
351 > /**
352 > * Sets the size of a group.
353 > */
354 > setSize(group: IEditorGroup | GroupIdentifier, size: { width: number; height: number }): void;
355 >
356 > /**
357 > * Arrange all groups in the container according to the provided arrangement.
358 > */
359 > arrangeGroups(arrangement: GroupsArrangement, target?: IEditorGroup | GroupIdentifier): void;
360 >
361 > /**
362 > * Toggles the target goup size to maximize/unmaximize.
363 > */
364 > toggleMaximizeGroup(group?: IEditorGroup | GroupIdentifier): void;
365 >
366 > /**
367 > * Toggles the target goup size to expand/distribute even.
368 > */
369 > toggleExpandGroup(group?: IEditorGroup | GroupIdentifier): void;
370 >
371 > /**
372 > * Applies the provided layout by either moving existing groups or creating new groups.
373 > */
374 > applyLayout(layout: EditorGroupLayout): void;
375 >
376 > /**
377 > * Returns an editor layout of the container.
378 > */
379 > getLayout(): EditorGroupLayout;
380 >
381 > /**
382 > * Sets the orientation of the root group to be either vertical or horizontal.
383 > */
384 > setGroupOrientation(orientation: GroupOrientation): void;
385 >
386 > /**
387 > * Find a group in a specific scope:
388 > * * `GroupLocation.FIRST`: the first group
389 > * * `GroupLocation.LAST`: the last group
390 > * * `GroupLocation.NEXT`: the next group from either the active one or `source`
391 > * * `GroupLocation.PREVIOUS`: the previous group from either the active one or `source`
392 > * * `GroupDirection.UP`: the next group above the active one or `source`
393 > * * `GroupDirection.DOWN`: the next group below the active one or `source`
394 > * * `GroupDirection.LEFT`: the next group to the left of the active one or `source`
395 > * * `GroupDirection.RIGHT`: the next group to the right of the active one or `source`
396 > *
397 > * @param scope the scope of the group to search in
398 > * @param source optional source to search from
399 > * @param wrap optionally wrap around if reaching the edge of groups
400 > */
401 > findGroup(scope: IFindGroupScope, source?: IEditorGroup | GroupIdentifier, wrap?: boolean): IEditorGroup | undefined;
402 >
403 > /**
404 > * Add a new group to the container. A new group is added by splitting a provided one in
405 > * one of the four directions.
406 > *
407 > * @param location the group from which to split to add a new group
408 > * @param direction the direction of where to split to
409 > */
410 > addGroup(location: IEditorGroup | GroupIdentifier, direction: GroupDirection): IEditorGroup;
411 >
412 > /**
413 > * Remove a group from the container.
414 > */
415 > removeGroup(group: IEditorGroup | GroupIdentifier): void;
416 >
417 > /**
418 > * Move a group to a new group in the container.
419 > *
420 > * @param group the group to move
421 > * @param location the group from which to split to add the moved group
422 > * @param direction the direction of where to split to
423 > */
424 > moveGroup(group: IEditorGroup | GroupIdentifier, location: IEditorGroup | GroupIdentifier, direction: GroupDirection): IEditorGroup;
425 >
426 > /**
427 > * Merge the editors of a group into a target group. By default, all editors will
428 > * move and the source group will close. This behaviour can be configured via the
429 > * `IMergeGroupOptions` options.
430 > *
431 > * @param group the group to merge
432 > * @param target the target group to merge into
433 > * @param options controls how the merge should be performed. by default all editors
434 > * will be moved over to the target and the source group will close. Configure to
435 > * `MOVE_EDITORS_KEEP_GROUP` to prevent the source group from closing. Set to
436 > * `COPY_EDITORS` to copy the editors into the target instead of moding them.
437 > *
438 > * @returns if merging was successful
439 > */
440 > mergeGroup(group: IEditorGroup | GroupIdentifier, target: IEditorGroup | GroupIdentifier, options?: IMergeGroupOptions): boolean;
441 >
442 > /**
443 > * Merge all editor groups into the target one.
444 > *
445 > * @returns if merging was successful
446 > */
447 > mergeAllGroups(target: IEditorGroup | GroupIdentifier): boolean;
448 >
449 > /**
450 > * Copy a group to a new group in the container.
451 > *
452 > * @param group the group to copy
453 > * @param location the group from which to split to add the copied group
454 > * @param direction the direction of where to split to
455 > */
456 > copyGroup(group: IEditorGroup | GroupIdentifier, location: IEditorGroup | GroupIdentifier, direction: GroupDirection): IEditorGroup;
457 >
458 > /**
459 > * Allows to register a drag and drop target for editors
460 > * on the provided `container`.
461 > */
462 > createEditorDropTarget(container: unknown /* HTMLElement */, delegate: IEditorDropTargetDelegate): IDisposable;
463 > }
464 >
465 > /**
466 > * An editor part is a viewer of editor groups. There can be multiple editor
467 > * parts opened in multiple windows.
468 > */
469 > export interface IEditorPart extends IEditorGroupsContainer {
470 >
471 > /**
472 > * An event for when the editor part is layed out.
473 > */
474 > readonly onDidLayout: Event<IDimension>;
475 >
476 > /**
477 > * An event for when the editor part is scrolled.
478 > */
479 > readonly onDidScroll: Event<void>;
480 >
481 > /**
482 > * An event for when the editor part is disposed.
483 > */
484 > readonly onWillDispose: Event<void>;
485 >
486 > /**
487 > * The identifier of the window the editor part is contained in.
488 > */
489 > readonly windowId: number;
490 >
491 > /**
492 > * The size of the editor part.
493 > */
494 > readonly contentDimension: IDimension;
495 >
496 > /**
497 > * Find out if an editor group is currently maximized.
498 > */
499 > hasMaximizedGroup(): boolean;
500 >
501 > /**
502 > * Enable or disable centered editor layout.
503 > */
504 > centerLayout(active: boolean): void;
505 >
506 > /**
507 > * Find out if the editor layout is currently centered.
508 > */
509 > isLayoutCentered(): boolean;
510 > }
511 >
512 > export interface IAuxiliaryEditorPart extends IEditorPart {
513 >
514 > /**
515 > * Close this auxiliary editor part after moving all
516 > * dirty editors of all groups back to the main editor
517 > * part.
518 > *
519 > * @returns `false` if an editor could not be moved back.
520 > */
521 > close(): boolean;
522 > }
523 >
524 > export interface IModalEditorPart extends IEditorPart {
525 >
526 > /**
527 > * Modal container of the editor part.
528 > */
529 > readonly modalElement: unknown /* HTMLElement */;
530 >
531 > /**
532 > * Whether the modal editor part is currently maximized.
533 > */
534 > readonly maximized: boolean;
535 >
536 > /**
537 > * Fired when the maximized state changes.
538 > */
539 > readonly onDidChangeMaximized: Event<boolean>;
540 >
541 > /**
542 > * Toggle between default and maximized size.
543 > */
544 > toggleMaximized(): void;
545 >
546 > /**
547 > * Size set by the user via resizing, if any.
548 > */
549 > readonly size: IDimension | undefined;
550 >
551 > /**
552 > * Position set by the user via dragging, if any.
553 > */
554 > readonly position: { left: number; top: number } | undefined;
555 >
556 > /**
557 > * Whether the modal editor part has a sidebar.
558 > */
559 > readonly hasSidebar: boolean;
560 >
561 > /**
562 > * Sidebar width set by the user via resizing, if any.
563 > */
564 > readonly sidebarWidth: number | undefined;
565 >
566 > /**
567 > * Whether the sidebar is hidden.
568 > */
569 > readonly sidebarHidden: boolean;
570 >
571 > /**
572 > * Toggle sidebar visibility.
573 > */
574 > toggleSidebar(): void;
575 >
576 > /**
577 > * The current navigation context, if any.
578 > */
579 > readonly navigation: IModalEditorNavigation | undefined;
580 >
581 > /**
582 > * Update options for the modal editor part.
583 > */
584 > updateOptions(options?: IModalEditorPartOptions): void;
585 >
586 > /**
587 > * Fired when this modal editor part is about to close.
588 > */
589 > readonly onWillClose: Event<void>;
590 >
591 > /**
592 > * Close this modal editor part after closing all
593 > * editors of all groups. Dirty editors will trigger
594 > * a confirmation dialog asking the user to save.
595 > *
596 > * The option `mergeAllEditorsToMainPart` can be used
597 > * to first move all editors from this modal editor part
598 > * back to the main editor part, where they remain open.
599 > * This avoids the confirmation dialog because the editors
600 > * are not closed as part of this operation.
601 > *
602 > * @returns `false` if the close was cancelled.
603 > */
604 > close(options?: { mergeAllEditorsToMainPart?: boolean }): Promise<boolean>;
605 > }
606 >
607 > export interface IEditorWorkingSet {
608 > readonly id: string;
609 > readonly name: string;
610 > }
611 >
612 > export interface IEditorWorkingSetOptions {
613 > readonly preserveFocus?: boolean;
614 > }
615 >
616 > export interface IEditorGroupContextKeyProvider<T extends ContextKeyValue> {
617 >
618 > /**
619 > * The context key that needs to be set for each editor group context and the global context.
620 > */
621 > readonly contextKey: RawContextKey<T>;
622 >
623 > /**
624 > * Retrieves the context key value for the given editor group.
625 > */
626 > readonly getGroupContextKeyValue: (group: IEditorGroup) => T;
627 >
628 > /**
629 > * An event that is fired when there was a change leading to the context key value to be re-evaluated.
630 > */
631 > readonly onDidChange?: Event<void>;
632 > }
633 >
634 > /**
635 > * The main service to interact with editor groups across all opened editor parts.
636 > */
637 > export interface IEditorGroupsService extends IEditorGroupsContainer {
638 >
639 > readonly _serviceBrand: undefined;
640 >
641 > /**
642 > * An event for when a new auxiliary editor part is created.
643 > */
644 > readonly onDidCreateAuxiliaryEditorPart: Event<IAuxiliaryEditorPart>;
645 >
646 > /**
647 > * Provides access to the main window editor part.
648 > */
649 > readonly mainPart: IEditorPart;
650 >
651 > /**
652 > * Provides access to all editor parts.
653 > */
654 > readonly parts: ReadonlyArray<IEditorPart>;
655 >
656 > /**
657 > * Get the editor part that contains the group with the provided identifier.
658 > */
659 > getPart(group: IEditorGroup | GroupIdentifier): IEditorPart;
660 >
661 > /**
662 > * Get the editor part that is rooted in the provided container.
663 > */
664 > getPart(container: unknown /* HTMLElement */): IEditorPart;
665 >
666 > /**
667 > * Opens a new window with a full editor part instantiated
668 > * in there at the optional position and size on screen.
669 > */
670 > createAuxiliaryEditorPart(options?: { bounds?: Partial<IRectangle>; compact?: boolean; alwaysOnTop?: boolean }): Promise<IAuxiliaryEditorPart>;
671 >
672 > /**
673 > * Creates a modal editor part that shows in a modal overlay
674 > * on top of the main workbench window.
675 > *
676 > * If a modal part already exists, it will be returned
677 > * instead of creating a new one.
678 > */
679 > createModalEditorPart(options?: IModalEditorPartOptions): Promise<IModalEditorPart>;
680 >
681 > /**
682 > * The currently active modal editor part, if any.
683 > */
684 > readonly activeModalEditorPart: IModalEditorPart | undefined;
685 >
686 > /**
687 > * Returns the instantiation service that is scoped to the
688 > * provided editor part. Use this method when building UI
689 > * that contributes to auxiliary editor parts to ensure the
690 > * UI is scoped to that part.
691 > */
692 > getScopedInstantiationService(part: IEditorPart): IInstantiationService;
693 >
694 > /**
695 > * Save a new editor working set from the currently opened
696 > * editors and group layout.
697 > */
698 > saveWorkingSet(name: string): IEditorWorkingSet;
699 >
700 > /**
701 > * Returns all known editor working sets.
702 > */
703 > getWorkingSets(): IEditorWorkingSet[];
704 >
705 > /**
706 > * Applies the working set. Use `empty` to apply an empty working set.
707 > *
708 > * @returns `true` when the working set as applied.
709 > */
710 > applyWorkingSet(workingSet: IEditorWorkingSet | 'empty', options?: IEditorWorkingSetOptions): Promise<boolean>;
711 >
712 > /**
713 > * Deletes a working set.
714 > */
715 > deleteWorkingSet(workingSet: IEditorWorkingSet): void;
716 >
717 > /**
718 > * Registers a context key provider. This provider sets a context key for each scoped editor group context and the global context.
719 > *
720 > * @param provider - The context key provider to be registered.
721 > * @returns - A disposable object to unregister the provider.
722 > */
723 > registerContextKeyProvider<T extends ContextKeyValue>(provider: IEditorGroupContextKeyProvider<T>): IDisposable;
724 > }
725 >
726 > export const enum OpenEditorContext {
727 > NEW_EDITOR = 1,
728 > MOVE_EDITOR = 2,
729 > COPY_EDITOR = 3
730 > }
731 >
732 > export interface IActiveEditorActions {
733 > readonly actions: IToolbarActions;
734 > readonly onDidChange: Event<IMenuChangeEvent | void>;
735 > }
736 >
737 > export interface IEditorGroup {
738 >
739 > /**
740 > * An event which fires whenever the underlying group model changes.
741 > */
742 > readonly onDidModelChange: Event<IGroupModelChangeEvent>;
743 >
744 > /**
745 > * An event that is fired when the group gets disposed.
746 > */
747 > readonly onWillDispose: Event<void>;
748 >
749 > /**
750 > * An event that is fired when the active editor in the group changed.
751 > */
752 > readonly onDidActiveEditorChange: Event<IActiveEditorChangeEvent>;
753 >
754 > /**
755 > * An event that is fired when an editor is about to close.
756 > */
757 > readonly onWillCloseEditor: Event<IEditorCloseEvent>;
758 >
759 > /**
760 > * An event that is fired when an editor is closed.
761 > */
762 > readonly onDidCloseEditor: Event<IEditorCloseEvent>;
763 >
764 > /**
765 > * An event that is fired when an editor is about to move to
766 > * a different group.
767 > */
768 > readonly onWillMoveEditor: Event<IEditorWillMoveEvent>;
769 >
770 > /**
771 > * A unique identifier of this group that remains identical even if the
772 > * group is moved to different locations.
773 > */
774 > readonly id: GroupIdentifier;
775 >
776 > /**
777 > * The identifier of the window this editor group is part of.
778 > */
779 > readonly windowId: number;
780 >
781 > /**
782 > * A number that indicates the position of this group in the visual
783 > * order of groups from left to right and top to bottom. The lowest
784 > * index will likely be top-left while the largest index in most
785 > * cases should be bottom-right, but that depends on the grid.
786 > */
787 > readonly index: number;
788 >
789 > /**
790 > * A human readable label for the group. This label can change depending
791 > * on the layout of all editor groups. Clients should listen on the
792 > * `onDidGroupModelChange` event to react to that.
793 > */
794 > readonly label: string;
795 >
796 > /**
797 > * A human readable label for the group to be used by screen readers.
798 > */
799 > readonly ariaLabel: string;
800 >
801 > /**
802 > * The active editor pane is the currently visible editor pane of the group.
803 > */
804 > readonly activeEditorPane: IVisibleEditorPane | undefined;
805 >
806 > /**
807 > * The active editor is the currently visible editor of the group
808 > * within the current active editor pane.
809 > */
810 > readonly activeEditor: EditorInput | null;
811 >
812 > /**
813 > * All selected editor in this group in sequential order.
814 > * The active editor is always part of the selection.
815 > */
816 > readonly selectedEditors: EditorInput[];
817 >
818 > /**
819 > * The editor in the group that is in preview mode if any. There can
820 > * only ever be one editor in preview mode.
821 > */
822 > readonly previewEditor: EditorInput | null;
823 >
824 > /**
825 > * The number of opened editors in this group.
826 > */
827 > readonly count: number;
828 >
829 > /**
830 > * Whether the group has editors or not.
831 > */
832 > readonly isEmpty: boolean;
833 >
834 > /**
835 > * Whether this editor group is locked or not. Locked editor groups
836 > * will only be considered for editors to open in when the group is
837 > * explicitly provided for the editor.
838 > *
839 > * Note: editor group locking only applies when more than one group
840 > * is opened.
841 > */
842 > readonly isLocked: boolean;
843 >
844 > /**
845 > * The number of sticky editors in this group.
846 > */
847 > readonly stickyCount: number;
848 >
849 > /**
850 > * All opened editors in the group in sequential order of their appearance.
851 > */
852 > readonly editors: readonly EditorInput[];
853 >
854 > /**
855 > * The scoped context key service for this group.
856 > */
857 > readonly scopedContextKeyService: IContextKeyService;
858 >
859 > /**
860 > * Get all editors that are currently opened in the group.
861 > *
862 > * @param order the order of the editors to use
863 > * @param options options to select only specific editors as instructed
864 > */
865 > getEditors(order: EditorsOrder, options?: { excludeSticky?: boolean }): readonly EditorInput[];
866 >
867 > /**
868 > * Finds all editors for the given resource that are currently
869 > * opened in the group. This method will return an entry for
870 > * each editor that reports a `resource` that matches the
871 > * provided one.
872 > *
873 > * @param resource the resource of the editor to find
874 > * @param options whether to support side by side editors or not
875 > */
876 > findEditors(resource: URI, options?: IFindEditorOptions): readonly EditorInput[];
877 >
878 > /**
879 > * Returns the editor at a specific index of the group.
880 > */
881 > getEditorByIndex(index: number): EditorInput | undefined;
882 >
883 > /**
884 > * Returns the index of the editor in the group or -1 if not opened.
885 > */
886 > getIndexOfEditor(editor: EditorInput): number;
887 >
888 > /**
889 > * Whether the editor is the first in the group.
890 > */
891 > isFirst(editor: EditorInput): boolean;
892 >
893 > /**
894 > * Whether the editor is the last in the group.
895 > */
896 > isLast(editor: EditorInput): boolean;
897 >
898 > /**
899 > * Open an editor in this group.
900 > *
901 > * @returns a promise that resolves around an IEditor instance unless
902 > * the call failed, or the editor was not opened as active editor.
903 > */
904 > openEditor(editor: EditorInput, options?: IEditorOptions): Promise<IEditorPane | undefined>;
905 >
906 > /**
907 > * Opens editors in this group.
908 > *
909 > * @returns a promise that resolves around an IEditor instance unless
910 > * the call failed, or the editor was not opened as active editor. Since
911 > * a group can only ever have one active editor, even if many editors are
912 > * opened, the result will only be one editor.
913 > */
914 > openEditors(editors: EditorInputWithOptions[]): Promise<IEditorPane | undefined>;
915 >
916 > /**
917 > * Find out if the provided editor is pinned in the group.
918 > */
919 > isPinned(editorOrIndex: EditorInput | number): boolean;
920 >
921 > /**
922 > * Find out if the provided editor or index of editor is sticky in the group.
923 > */
924 > isSticky(editorOrIndex: EditorInput | number): boolean;
925 >
926 > /**
927 > * Find out if the provided editor or index of editor is transient in the group.
928 > */
929 > isTransient(editorOrIndex: EditorInput | number): boolean;
930 >
931 > /**
932 > * Find out if the provided editor is active in the group.
933 > */
934 > isActive(editor: EditorInput | IUntypedEditorInput): boolean;
935 >
936 > /**
937 > * Whether the editor is selected in the group.
938 > */
939 > isSelected(editor: EditorInput): boolean;
940 >
941 > /**
942 > * Set a new selection for this group. This will replace the current
943 > * selection with the new selection.
944 > *
945 > * @param activeSelectedEditor the editor to set as active selected editor
946 > * @param inactiveSelectedEditors the inactive editors to set as selected
947 > */
948 > setSelection(activeSelectedEditor: EditorInput, inactiveSelectedEditors: EditorInput[]): Promise<void>;
949 >
950 > /**
951 > * Find out if a certain editor is included in the group.
952 > *
953 > * @param candidate the editor to find
954 > * @param options fine tune how to match editors
955 > */
956 > contains(candidate: EditorInput | IUntypedEditorInput, options?: IMatchEditorOptions): boolean;
957 >
958 > /**
959 > * Move an editor from this group either within this group or to another group.
960 > *
961 > * @returns whether the editor was moved or not.
962 > */
963 > moveEditor(editor: EditorInput, target: IEditorGroup, options?: IEditorOptions): boolean;
964 >
965 > /**
966 > * Move editors from this group either within this group or to another group.
967 > *
968 > * @returns whether all editors were moved or not.
969 > */
970 > moveEditors(editors: EditorInputWithOptions[], target: IEditorGroup): boolean;
971 >
972 > /**
973 > * Copy an editor from this group to another group.
974 > *
975 > * Note: It is currently not supported to show the same editor more than once in the same group.
976 > */
977 > copyEditor(editor: EditorInput, target: IEditorGroup, options?: IEditorOptions): void;
978 >
979 > /**
980 > * Copy editors from this group to another group.
981 > *
982 > * Note: It is currently not supported to show the same editor more than once in the same group.
983 > */
984 > copyEditors(editors: EditorInputWithOptions[], target: IEditorGroup): void;
985 >
986 > /**
987 > * Close an editor from the group. This may trigger a confirmation dialog if
988 > * the editor is dirty and thus returns a promise as value.
989 > *
990 > * @param editor the editor to close, or the currently active editor
991 > * if unspecified.
992 > *
993 > * @returns a promise when the editor is closed or not. If `true`, the editor
994 > * is closed and if `false` there was a veto closing the editor, e.g. when it
995 > * is dirty.
996 > */
997 > closeEditor(editor?: EditorInput, options?: ICloseEditorOptions): Promise<boolean>;
998 >
999 > /**
1000 > * Closes specific editors in this group. This may trigger a confirmation dialog if
1001 > * there are dirty editors and thus returns a promise as value.
1002 > *
1003 > * @returns a promise whether the editors were closed or not. If `true`, the editors
1004 > * were closed and if `false` there was a veto closing the editors, e.g. when one
1005 > * is dirty.
1006 > */
1007 > closeEditors(editors: EditorInput[] | ICloseEditorsFilter, options?: ICloseEditorOptions): Promise<boolean>;
1008 >
1009 > /**
1010 > * Closes all editors from the group. This may trigger a confirmation dialog if
1011 > * there are dirty editors and thus returns a promise as value.
1012 > *
1013 > * @returns a promise if confirmation is needed when all editors are closed.
1014 > */
1015 > closeAllEditors(options: { excludeConfirming: true }): boolean;
1016 > closeAllEditors(options?: ICloseAllEditorsOptions): Promise<boolean>;
1017 >
1018 > /**
1019 > * Replaces editors in this group with the provided replacement.
1020 > *
1021 > * @param editors the editors to replace
1022 > *
1023 > * @returns a promise that is resolved when the replaced active
1024 > * editor (if any) has finished loading.
1025 > */
1026 > replaceEditors(editors: IEditorReplacement[]): Promise<void>;
1027 >
1028 > /**
1029 > * Set an editor to be pinned. A pinned editor is not replaced
1030 > * when another editor opens at the same location.
1031 > *
1032 > * @param editor the editor to pin, or the currently active editor
1033 > * if unspecified.
1034 > */
1035 > pinEditor(editor?: EditorInput): void;
1036 >
1037 > /**
1038 > * Set an editor to be sticky. A sticky editor is showing in the beginning
1039 > * of the tab stripe and will not be impacted by close operations.
1040 > *
1041 > * @param editor the editor to make sticky, or the currently active editor
1042 > * if unspecified.
1043 > */
1044 > stickEditor(editor?: EditorInput): void;
1045 >
1046 > /**
1047 > * Set an editor to be non-sticky and thus moves back to a location after
1048 > * sticky editors and can be closed normally.
1049 > *
1050 > * @param editor the editor to make unsticky, or the currently active editor
1051 > * if unspecified.
1052 > */
1053 > unstickEditor(editor?: EditorInput): void;
1054 >
1055 > /**
1056 > * Whether this editor group should be locked or not.
1057 > *
1058 > * See {@linkcode IEditorGroup.isLocked `isLocked`}
1059 > */
1060 > lock(locked: boolean): void;
1061 >
1062 > /**
1063 > * Move keyboard focus into the group.
1064 > */
1065 > focus(): void;
1066 >
1067 > /**
1068 > * Create the editor actions for the current active editor.
1069 > */
1070 > createEditorActions(disposables: DisposableStore, menuId?: MenuId): IActiveEditorActions;
1071 > }
1072 >
1073 > export function isEditorGroup(obj: unknown): obj is IEditorGroup {
1074 const group = obj as IEditorGroup | undefined;
1075
1076 return !!group && typeof group.id === 'number' && Array.isArray(group.editors);
1077 }
1079 > //#region Editor Group Helpers
1080 >
1081 > export function preferredSideBySideGroupDirection(configurationService: IConfigurationService): GroupDirection.DOWN | GroupDirection.RIGHT {
1082 const openSideBySideDirection = configurationService.getValue('workbench.editor.openSideBySideDirection');
1083
src/vs/platform/agentHost/common/state/protocol/common/commands.ts 1071 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- commands.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > // allow-any-unicode-comment-file
7 > // DO NOT EDIT -- auto-generated by scripts/sync-agent-host-protocol.ts
8 >
9 > import type { URI, Snapshot } from './state.js';
10 > import type { ActionEnvelope, StateAction } from './actions.js';
11 > import type { TelemetryCapabilities } from '../channels-otlp/state.js';
12 >
13 > // ─── BaseParams ──────────────────────────────────────────────────────────────
14 >
15 > /**
16 > * Base shape every command's params extends.
17 > *
18 > * `channel` identifies the channel the command targets, mirroring the
19 > * `channel` field on every protocol notification. For commands that operate
20 > * on a specific channel (a session, terminal, or changeset), `channel` is
21 > * that channel's URI. For commands that are connection-level rather than
22 > * channel-scoped (e.g. {@link InitializeParams | `initialize`},
23 > * {@link PingParams | `ping`}, {@link ListSessionsParams | `listSessions`},
24 > * the `resource*` filesystem commands, and {@link AuthenticateParams |
25 > * `authenticate`}), the params type narrows `channel` to the literal
26 > * root URI `'ahp-root://'`.
27 > *
28 > * This invariant lets implementations route every incoming message —
29 > * request, response, or notification — by inspecting `params.channel`
30 > * without needing to know the per-method param shape.
31 > *
32 > * @category Commands
33 > */
34 > export interface BaseParams {
35 > /** Channel URI this command targets. */
36 > channel: URI;
37 > }
38 >
39 > // ─── Pagination ──────────────────────────────────────────────────────────────
40 >
41 > /**
42 > * Cursor-based pagination inputs, mixed into the params of any list command
43 > * that can page a large result set (e.g. {@link ListSessionsParams |
44 > * `listSessions`}). The paired output is {@link PaginatedResult}.
45 > *
46 > * Pagination is **opaque and cursor-based**, mirroring the shape `fetchTurns`
47 > * already uses for chat history: the server owns the ordering and keyset, and
48 > * the client walks pages by echoing the cursor from the previous
49 > * {@link PaginatedResult.nextCursor} back on the next request.
50 > *
51 > * The contract every paginated command shares:
52 > *
53 > * - To fetch the first page, omit `cursor`. Supply `limit` to bound the page.
54 > * - If the result carries a {@link PaginatedResult.nextCursor}, more entries
55 > * exist — pass it back as `cursor` to fetch the following page. A missing
56 > * `nextCursor` signals the end of the collection.
57 > * - Cursors are **server-defined and opaque**: clients MUST NOT parse, modify,
58 > * or persist them across connections. An unrecognised cursor SHOULD be
59 > * rejected with an `InvalidParams` error.
60 > * - Pagination is **fully additive**: a client that omits `limit`/`cursor` and
61 > * ignores `nextCursor` sees the pre-pagination behaviour (subject to any
62 > * server-imposed cap), and a server that does not paginate ignores the inputs
63 > * and returns everything in a single page.
64 > *
65 > * @category Commands
66 > */
67 > export interface PaginatedParams {
68 > /**
69 > * Maximum number of entries to return in this page. The server SHOULD respect
70 > * this bound but MAY return fewer entries and MAY impose its own upper cap.
71 > * Omit to let the server choose the page size.
72 > */
73 > limit?: number;
74 > /**
75 > * Opaque pagination cursor from a previous {@link PaginatedResult.nextCursor}.
76 > * Omit to fetch the first page. Cursors are server-defined and MUST be treated
77 > * as opaque — do not parse, modify, or persist them across connections. An
78 > * unrecognised cursor SHOULD be rejected with an `InvalidParams` error.
79 > */
80 > cursor?: string;
81 > }
82 >
83 > /**
84 > * Cursor-based pagination output, extended by the result of any list command
85 > * that can page a large result set (e.g. {@link ListSessionsResult |
86 > * `listSessions`}). See {@link PaginatedParams} for the full pagination
87 > * contract shared by every paginated command.
88 > *
89 > * @category Commands
90 > */
91 > export interface PaginatedResult {
92 > /**
93 > * Opaque cursor for the next page. Present when more entries exist beyond the
94 > * returned page; absent signals the end of the collection. Pass it back as
95 > * {@link PaginatedParams.cursor} to fetch the following page.
96 > */
97 > nextCursor?: string;
98 > }
99 >
100 > // ─── initialize ──────────────────────────────────────────────────────────────
101 >
102 > /**
103 > * Identifies a protocol implementation — the software (and build) on one end
104 > * of the connection, as distinct from the {@link AgentInfo | agent persona} it
105 > * hosts. Carried as {@link InitializeParams.clientInfo | `clientInfo`} on the
106 > * client side and {@link InitializeResult.serverInfo | `serverInfo`} on the
107 > * server side, mirroring LSP's `clientInfo`/`serverInfo` and MCP's
108 > * `Implementation`.
109 > *
110 > * This is **informational only**: it exists for logging, telemetry, an
111 > * about/status affordance, and — as a last resort — a known-issue workaround
112 > * for a specific buggy build. It is **not** a feature-detection mechanism.
113 > * Feature availability stays with the capability model
114 > * ({@link ClientCapabilities} and the various `*.capabilities` declarations);
115 > * implementations SHOULD NOT gate protocol behaviour on parsing
116 > * {@link Implementation.version | `version`}.
117 > *
118 > * @category Commands
119 > */
120 > export interface Implementation {
121 > /** Implementation name, e.g. a product or package identifier. */
122 > name: string;
123 > /**
124 > * Implementation version. A [SemVer](https://semver.org) string is
125 > * recommended but not required.
126 > */
127 > version?: string;
128 > /** Optional human-readable display name. */
129 > title?: string;
130 > }
131 >
132 > /**
133 > * Establishes a new connection and negotiates the protocol version.
134 > * This MUST be the first message sent by the client.
135 > *
136 > * @category Commands
137 > * @method initialize
138 > * @direction Client → Server
139 > * @messageType Request
140 > * @version 1
141 > * @see {@link /specification/lifecycle | Lifecycle} for the full handshake flow.
142 > */
143 > export interface InitializeParams extends BaseParams {
144 > channel: 'ahp-root://';
145 > /**
146 > * Protocol versions the client is willing to speak, ordered from most
147 > * preferred to least preferred. Each entry is a [SemVer](https://semver.org)
148 > * `MAJOR.MINOR.PATCH` string (e.g. `"0.1.0"`).
149 > *
150 > * The server selects one entry and returns it as `InitializeResult.protocolVersion`.
151 > * If the server cannot speak any of the offered versions, it MUST return
152 > * error code `-32005` (`UnsupportedProtocolVersion`).
153 > */
154 > protocolVersions: string[];
155 > /** Unique client identifier */
156 > clientId: string;
157 > /**
158 > * Optional identity of the client implementation (name and version).
159 > * Informational only — see {@link Implementation} for how it may and may not
160 > * be used. Distinct from {@link InitializeParams.clientId | `clientId`},
161 > * which is an opaque per-connection identifier used for reconnection, not a
162 > * human-readable implementation name.
163 > */
164 > clientInfo?: Implementation;
165 > /** URIs to subscribe to during handshake */
166 > initialSubscriptions?: URI[];
167 > /**
168 > * IETF BCP 47 language tag indicating the client's preferred locale
169 > * (e.g. `"en-US"`, `"ja"`). The server SHOULD use this to localise
170 > * user-facing strings such as confirmation option labels.
171 > */
172 > locale?: string;
173 > /**
174 > * Optional client capability declarations.
175 > *
176 > * Servers SHOULD only advertise features whose corresponding client
177 > * capability is set here. Absent means "not declared" — the server
178 > * MUST assume the client does not support the feature.
179 > */
180 > capabilities?: ClientCapabilities;
181 > }
182 >
183 > /**
184 > * Optional capabilities a client declares during `initialize`.
185 > *
186 > * Each field is a presence flag: an empty object `{}` means "supported",
187 > * absence means "not supported". Sub-fields on individual capabilities
188 > * are reserved for future per-capability options.
189 > *
190 > * @category Commands
191 > */
192 > export interface ClientCapabilities {
193 > /**
194 > * Client can render
195 > * [MCP Apps](https://github.com/modelcontextprotocol/ext-apps) — i.e.
196 > * it can host the View sandbox, run the `ui/*` protocol against it,
197 > * and forward `mcp://`-channel traffic on the App's behalf.
198 > *
199 > * Hosts SHOULD only populate
200 > * {@link McpServerCustomization.mcpApp | `McpServerCustomization.mcpApp`}
201 > * (and expose the corresponding
202 > * {@link McpServerCustomization.channel | `mcp://` channel}) when this
203 > * capability is declared. Clients that omit it MUST treat
204 > * App-bearing tool calls as ordinary MCP tool calls.
205 > */
206 > mcpApps?: Record<string, never>;
207 > }
208 >
209 > /**
210 > * Result of the `initialize` command.
211 > *
212 > * `protocolVersion` is the version the server has selected from the client's
213 > * `protocolVersions` list. The client and server MUST use this version for
214 > * the rest of the connection. If the server cannot speak any of the offered
215 > * versions it MUST return error code `-32005` (`UnsupportedProtocolVersion`)
216 > * instead of a result.
217 > */
218 > export interface InitializeResult {
219 > /**
220 > * Protocol version selected by the server. MUST be one of the entries in
221 > * `InitializeParams.protocolVersions`. Formatted as a [SemVer](https://semver.org)
222 > * `MAJOR.MINOR.PATCH` string (e.g. `"0.1.0"`).
223 > */
224 > protocolVersion: string;
225 > /** Current server sequence number */
226 > serverSeq: number;
227 > /**
228 > * Optional identity of the server implementation (name and version).
229 > * Informational only — see {@link Implementation} for how it may and may not
230 > * be used. Whereas {@link InitializeResult.protocolVersion | `protocolVersion`}
231 > * identifies the negotiated protocol, `serverInfo` identifies the host
232 > * software behind it.
233 > */
234 > serverInfo?: Implementation;
235 > /** Snapshots for each `initialSubscriptions` URI */
236 > snapshots: Snapshot[];
237 > /** Suggested default directory for remote filesystem browsing */
238 > defaultDirectory?: URI;
239 > /**
240 > * Characters that, when typed in a {@link Message} input, SHOULD cause
241 > * the client to issue a `completions` request with
242 > * {@link CompletionItemKind.UserMessage}. Typically includes characters like
243 > * `'@'` or `'/'`.
244 > */
245 > completionTriggerCharacters?: string[];
246 > /**
247 > * Prefix that the host recognizes at the start of a user {@link Message.text}
248 > * as a shorthand for executing the remainder as a terminal command. Currently
249 > * the standardized convention is `"!"`; absence means the host does not
250 > * support command prefixes.
251 > */
252 > terminalCommandPrefix?: string;
253 > /**
254 > * OTLP telemetry channels the host emits, if any. Each populated field is
255 > * either a literal `ahp-otlp:` channel URI or an RFC 6570 URI template a
256 > * client expands before subscribing (currently only the `logs` channel
257 > * defines a template variable, `{level}`, for subscriber-side severity
258 > * filtering). Clients MAY ignore signals they cannot process.
259 > *
260 > * @see {@link /specification/telemetry-channel | Telemetry Channel}
261 > */
262 > telemetry?: TelemetryCapabilities;
263 > }
264 >
265 > // ─── ping ────────────────────────────────────────────────────────────────────
266 >
267 > /**
268 > * Verifies that the AHP connection is still alive and keeps it from being
269 > * closed by idle-timeout intermediaries (proxies, load balancers, etc.).
270 > *
271 > * The server MUST respond regardless of whether the client has completed
272 > * `initialize` or holds any subscriptions. Ping carries no payload in either
273 > * direction; the response itself is the signal.
274 > *
275 > * @category Commands
276 > * @method ping
277 > * @direction Client → Server
278 > * @messageType Request
279 > * @version 1
280 > */
281 > export interface PingParams extends BaseParams {
282 > channel: 'ahp-root://';
283 > }
284 >
285 > // ─── reconnect ───────────────────────────────────────────────────────────────
286 >
287 > /**
288 > * Discriminant for reconnect result types.
289 > *
290 > * @category Commands
291 > */
292 > export const enum ReconnectResultType {
293 > Replay = 'replay',
294 > Snapshot = 'snapshot',
295 > }
296 >
297 > /**
298 > * Re-establishes a dropped connection. The server replays missed actions or
299 > * provides fresh snapshots.
300 > *
301 > * @category Commands
302 > * @method reconnect
303 > * @direction Client → Server
304 > * @messageType Request
305 > * @version 1
306 > * @see {@link /specification/lifecycle | Lifecycle} for details.
307 > */
308 > export interface ReconnectParams extends BaseParams {
309 > channel: 'ahp-root://';
310 > /** Client identifier from the original connection */
311 > clientId: string;
312 > /** Last `serverSeq` the client received */
313 > lastSeenServerSeq: number;
314 > /** URIs the client was subscribed to */
315 > subscriptions: URI[];
316 > }
317 >
318 > /**
319 > * Reconnect result when the server can replay from the requested sequence.
320 > *
321 > * The server MUST include all replayed data in the response.
322 > */
323 > export interface ReconnectReplayResult {
324 > /** Discriminant */
325 > type: ReconnectResultType.Replay;
326 > /** Missed action envelopes since `lastSeenServerSeq` */
327 > actions: ActionEnvelope[];
328 > /**
329 > * URIs from `ReconnectParams.subscriptions` that the server cannot resume.
330 > * This includes resources that no longer exist (e.g. disposed sessions or
331 > * terminals) as well as resources the client is no longer permitted to
332 > * observe. Clients SHOULD drop these from their local subscription set.
333 > */
334 > missing: URI[];
335 > }
336 >
337 > /**
338 > * Reconnect result when the gap exceeds the replay buffer.
339 > */
340 > export interface ReconnectSnapshotResult {
341 > /** Discriminant */
342 > type: ReconnectResultType.Snapshot;
343 > /** Fresh snapshots for each subscription */
344 > snapshots: Snapshot[];
345 > }
346 >
347 > /** Result of the `reconnect` command. */
348 > export type ReconnectResult = ReconnectReplayResult | ReconnectSnapshotResult;
349 >
350 > // ─── subscribe ───────────────────────────────────────────────────────────────
351 >
352 > /**
353 > * Subscribe to a URI-identified channel.
354 > *
355 > * A channel MAY have state associated with it (e.g. root, sessions,
356 > * terminals) or be stateless (pure pub/sub for streaming data). For
357 > * state-bearing channels the result includes a snapshot; for stateless
358 > * channels `snapshot` is omitted.
359 > *
360 > * @category Commands
361 > * @method subscribe
362 > * @direction Client → Server
363 > * @messageType Request
364 > * @version 1
365 > * @see {@link /specification/subscriptions | Subscriptions}
366 > */
367 > export interface SubscribeParams extends BaseParams {
368 > /**
369 > * Optional delivery preferences for this subscription.
370 > *
371 > * Servers MAY use these preferences to buffer and coalesce high-frequency
372 > * updates while preserving the same reduced state. Omit this field for the
373 > * server's default delivery behavior.
374 > */
375 > delivery?: SubscriptionDeliveryOptions;
376 > /**
377 > * Optional client-requested shape for the returned snapshot.
378 > *
379 > * Servers that do not understand a requested view ignore it and return their
380 > * default snapshot. Clients MUST tolerate receiving more state than requested.
381 > */
382 > view?: SubscribeView;
383 > }
384 >
385 > /**
386 > * Optional client-requested shape for a subscription snapshot.
387 > *
388 > * @category Commands
389 > */
390 > export interface SubscribeView {
391 > /**
392 > * Advisory number of most-recent completed turns to expose in a chat
393 > * snapshot.
394 > *
395 > * Servers MAY return more or fewer turns than requested. When omitted, the
396 > * host MUST return all retained turns. When older turns remain available, the
397 > * returned {@link ChatState} carries `turnsNextCursor`; clients pass that
398 > * cursor to `fetchTurns` to ask the host to page more turns into the chat
399 > * state.
400 > */
401 > turns?: number;
402 > }
403 >
404 > /**
405 > * Advisory delivery preferences for a single subscription.
406 > *
407 > * @category Commands
408 > */
409 > export interface SubscriptionDeliveryOptions {
410 > /**
411 > * Maximum time, in milliseconds, that the server may intentionally delay
412 > * delivery while buffering/coalescing updates for this subscription.
413 > *
414 > * A value of `0` requests immediate delivery with no intentional coalescing.
415 > */
416 > maxLatencyMs?: number;
417 > }
418 >
419 > /**
420 > * Result of the `subscribe` command.
421 > *
422 > * `snapshot` is present when the subscribed channel has associated state, and
423 > * absent for stateless channels.
424 > */
425 > export interface SubscribeResult {
426 > /** Snapshot of the subscribed channel's state (omitted for stateless channels) */
427 > snapshot?: Snapshot;
428 > }
429 >
430 > // ─── unsubscribe ─────────────────────────────────────────────────────────────
431 >
432 > /**
433 > * Stop receiving updates for a channel.
434 > *
435 > * @category Commands
436 > * @method unsubscribe
437 > * @direction Client → Server
438 > * @messageType Notification
439 > * @version 1
440 > * @see {@link /specification/subscriptions | Subscriptions}
441 > */
442 > export interface UnsubscribeParams {
443 > /** Channel URI to unsubscribe from */
444 > channel: URI;
445 > }
446 >
447 > // ─── dispatchAction ──────────────────────────────────────────────────────────
448 >
449 > /**
450 > * Fire-and-forget action dispatch (write-ahead). The client applies actions
451 > * optimistically to local state and the server echoes them back as an
452 > * {@link ActionEnvelope} once accepted.
453 > *
454 > * The client → server method is named `dispatchAction`; the server's reply
455 > * arrives on the server → client `action` notification (params:
456 > * {@link ActionEnvelope}).
457 > *
458 > * @category Commands
459 > * @method dispatchAction
460 > * @direction Client → Server
461 > * @messageType Notification
462 > * @version 1
463 > * @see {@link /guide/actions | Actions} for the full list of client-dispatchable actions.
464 > */
465 > export interface DispatchActionParams {
466 > /** Channel URI this action targets */
467 > channel: URI;
468 > /** Client sequence number */
469 > clientSeq: number;
470 > /** The action to dispatch */
471 > action: StateAction;
472 > }
473 >
474 > // ─── resourceRead ────────────────────────────────────────────────────────
475 >
476 > /**
477 > * Encoding of fetched content data.
478 > *
479 > * @category Commands
480 > */
481 > export const enum ContentEncoding {
482 > Base64 = 'base64',
483 > Utf8 = 'utf-8',
484 > }
485 >
486 > /**
487 > * Reads the content of a resource by URI.
488 > *
489 > * Content references keep the state tree small by storing large data (images,
490 > * long tool outputs) by reference rather than inline.
491 > *
492 > * Binary content (images, etc.) MUST use `base64` encoding. Text content MAY
493 > * use `utf-8` encoding.
494 > *
495 > * Like all `resource*` methods, `resourceRead` is symmetrical and MAY be
496 > * sent in either direction. Hosts use it to fetch content from a
497 > * client-published URI (e.g. `virtual://my-client/...` plugins); clients
498 > * use it to read host-side files. The receiver enforces access via the
499 > * same permission/`resourceRequest` flow regardless of which peer initiated.
500 > *
501 > * @category Commands
502 > * @method resourceRead
503 > * @direction Client ↔ Server
504 > * @messageType Request
505 > * @version 1
506 > * @throws `NotFound` (`-32008`) if the URI does not exist.
507 > * @throws `PermissionDenied` (`-32009`) if the client is not permitted to read the URI.
508 > * @example
509 > * ```jsonc
510 > * // Client → Server
511 > * { "jsonrpc": "2.0", "id": 10, "method": "resourceRead",
512 > * "params": { "uri": "ahp-session:/<uuid>/content/img-1" } }
513 > *
514 > * // Server → Client
515 > * { "jsonrpc": "2.0", "id": 10, "result": {
516 > * "data": "iVBORw0KGgo...",
517 > * "encoding": "base64",
518 > * "contentType": "image/png"
519 > * }}
520 > * ```
521 > */
522 > export interface ResourceReadParams extends BaseParams {
523 > channel: 'ahp-root://';
524 > /** Content URI from a `ContentRef` */
525 > uri: string;
526 > /** Preferred encoding for the returned data (default: server-chosen) */
527 > encoding?: ContentEncoding;
528 > }
529 >
530 > /**
531 > * Result of the `resourceRead` command.
532 > *
533 > * The server SHOULD honor the `encoding` requested in the params. If the
534 > * server cannot provide the requested encoding, it MUST fall back to either
535 > * `base64` or `utf-8`.
536 > */
537 > export interface ResourceReadResult {
538 > /** Content encoded as a string */
539 > data: string;
540 > /** How `data` is encoded */
541 > encoding: ContentEncoding;
542 > /** Content type (e.g. `"image/png"`, `"text/plain"`) */
543 > contentType?: string;
544 > }
545 >
546 > // ─── resourceWrite ───────────────────────────────────────────────────────────
547 >
548 > /**
549 > * How {@link ResourceWriteParams.data} is placed within the target file.
550 > *
551 > * Each mode interprets {@link ResourceWriteParams.position} differently:
552 > *
553 > * - `truncate` (default): rooted at the **start** of the file. The file is
554 > * truncated at `position` (0 by default) and `data` is written from that
555 > * offset, so the resulting file is `existing[0..position] + data`. With
556 > * `position` omitted this is a full overwrite.
557 > * - `append`: rooted at the **end** of the file. `position` counts bytes
558 > * backwards from EOF, so `position: 0` (the default) writes at EOF —
559 > * POSIX append — and `position: 5` inserts `data` 5 bytes before the
560 > * current EOF, shifting those trailing 5 bytes after the inserted region.
561 > * The server MUST evaluate the effective EOF and write atomically with
562 > * respect to other appenders so concurrent `append` writes do not
563 > * clobber each other.
564 > * - `insert`: rooted at the **start** of the file. `position` (0 by default)
565 > * is the byte offset at which `data` is spliced in; bytes at or after
566 > * `position` are shifted right by `data.length`. `insert` always grows
567 > * the file — use `truncate` to overwrite bytes in place.
568 > *
569 > * @category Commands
570 > */
571 > export const enum ResourceWriteMode {
572 > Truncate = 'truncate',
573 > Append = 'append',
574 > Insert = 'insert',
575 > }
576 >
577 > /**
578 > * Writes content to a file on the server's filesystem.
579 > *
580 > * Binary content (images, etc.) MUST use `base64` encoding. Text content MAY
581 > * use `utf-8` encoding.
582 > *
583 > * If the file does not exist, it is created. If the file already exists, the
584 > * effect on existing bytes depends on {@link ResourceWriteParams.mode}:
585 > * `truncate` (default) overwrites from the chosen offset onward, `append`
586 > * preserves all existing bytes and adds `data` at a position rooted at EOF,
587 > * and `insert` preserves all existing bytes and splices `data` in at an
588 > * offset rooted at the start of the file.
589 > *
590 > * Like all `resource*` methods, `resourceWrite` is symmetrical and MAY be
591 > * sent in either direction.
592 > *
593 > * @category Commands
594 > * @method resourceWrite
595 > * @direction Client ↔ Server
596 > * @messageType Request
597 > * @version 1
598 > * @throws `NotFound` (`-32008`) if the parent directory does not exist.
599 > * @throws `PermissionDenied` (`-32009`) if the client is not permitted to write to the path.
600 > * @throws `AlreadyExists` (`-32010`) if `createOnly` is set and the file already exists.
601 > * @throws `Conflict` (`-32011`) if `ifMatch` is set and the current `etag` does not match.
602 > * @example
603 > * ```jsonc
604 > * // Client → Server
605 > * { "jsonrpc": "2.0", "id": 11, "method": "resourceWrite",
606 > * "params": { "uri": "file:///workspace/hello.txt", "data": "SGVsbG8=",
607 > * "encoding": "base64", "contentType": "text/plain" } }
608 > *
609 > * // Server → Client
610 > * { "jsonrpc": "2.0", "id": 11, "result": {} }
611 > * ```
612 > */
613 > export interface ResourceWriteParams extends BaseParams {
614 > channel: 'ahp-root://';
615 > /** Target file URI on the server filesystem */
616 > uri: URI;
617 > /** Content encoded as a string */
618 > data: string;
619 > /** How `data` is encoded */
620 > encoding: ContentEncoding;
621 > /** Content type (e.g. `"text/plain"`, `"image/png"`) */
622 > contentType?: string;
623 > /**
624 > * If `true`, the server MUST fail if the file already exists instead of
625 > * overwriting it. Useful for safe creation of new files.
626 > */
627 > createOnly?: boolean;
628 > /**
629 > * How `data` is placed within the target file. Defaults to `'truncate'`
630 > * (full overwrite) when omitted. See {@link ResourceWriteMode} for the
631 > * meaning of each mode and how it interprets {@link position}.
632 > */
633 > mode?: ResourceWriteMode;
634 > /**
635 > * Byte offset interpreted according to {@link mode}. Defaults to `0`.
636 > * - `truncate`: offset from the start of the file at which to truncate
637 > * before writing.
638 > * - `append`: bytes back from EOF at which to insert `data`.
639 > * - `insert`: offset from the start of the file at which to splice in
640 > * `data`.
641 > */
642 > position?: number;
643 > /**
644 > * Optimistic-concurrency token previously returned by
645 > * {@link ResourceResolveResult.etag}. When set, the server MUST fail with
646 > * `Conflict` if the current `etag` does not match — preventing lost
647 > * updates between a `resourceResolve` and a subsequent `resourceWrite`.
648 > */
649 > ifMatch?: string;
650 > }
651 >
652 > /**
653 > * Result of the `resourceWrite` command.
654 > *
655 > * An empty object on success.
656 > */
657 > export interface ResourceWriteResult {
658 > }
659 >
660 > // ─── resourceList ────────────────────────────────────────────────────────
661 >
662 > /**
663 > * Lists directory entries at a file URI on the server's filesystem.
664 > *
665 > * This is intended for remote folder pickers and similar UI that needs to let
666 > * users navigate the server's local filesystem.
667 > *
668 > * The server MUST return success only if the target exists and is a directory.
669 > * If the target does not exist, is not a directory, or cannot be accessed, the
670 > * server MUST return a JSON-RPC error.
671 > *
672 > * Like all `resource*` methods, `resourceList` is symmetrical and MAY be
673 > * sent in either direction.
674 > *
675 > * @category Commands
676 > * @method resourceList
677 > * @direction Client ↔ Server
678 > * @messageType Request
679 > * @version 1
680 > * @throws `NotFound` (`-32008`) if the directory does not exist.
681 > * @throws `PermissionDenied` (`-32009`) if the client is not permitted to browse the directory.
682 > */
683 > export interface ResourceListParams extends BaseParams {
684 > channel: 'ahp-root://';
685 > /** Directory URI on the server filesystem */
686 > uri: URI;
687 > }
688 >
689 > /**
690 > * Directory entry returned by `resourceList`.
691 > */
692 > export interface DirectoryEntry {
693 > /** Base name of the entry */
694 > name: string;
695 > /** Whether the entry is a file or directory */
696 > type: 'file' | 'directory';
697 > }
698 >
699 > /**
700 > * Result of the `resourceList` command.
701 > */
702 > export interface ResourceListResult {
703 > /** Entries directly contained in the requested directory */
704 > entries: DirectoryEntry[];
705 > }
706 >
707 > // ─── resourceCopy ────────────────────────────────────────────────────────────
708 >
709 > /**
710 > * Copies a resource from one URI to another on the server's filesystem.
711 > *
712 > * If the destination already exists, it is overwritten unless `failIfExists`
713 > * is set.
714 > *
715 > * Like all `resource*` methods, `resourceCopy` is symmetrical and MAY be
716 > * sent in either direction.
717 > *
718 > * @category Commands
719 > * @method resourceCopy
720 > * @direction Client ↔ Server
721 > * @messageType Request
722 > * @version 1
723 > * @throws `NotFound` (`-32008`) if the source does not exist.
724 > * @throws `PermissionDenied` (`-32009`) if the client is not permitted to read the source or write to the destination.
725 > * @throws `AlreadyExists` (`-32010`) if `failIfExists` is set and the destination already exists.
726 > */
727 > export interface ResourceCopyParams extends BaseParams {
728 > channel: 'ahp-root://';
729 > /** Source URI to copy from */
730 > source: URI;
731 > /** Destination URI to copy to */
732 > destination: URI;
733 > /**
734 > * If `true`, the server MUST fail if the destination already exists instead
735 > * of overwriting it.
736 > */
737 > failIfExists?: boolean;
738 > }
739 >
740 > /**
741 > * Result of the `resourceCopy` command.
742 > *
743 > * An empty object on success.
744 > */
745 > export interface ResourceCopyResult {
746 > }
747 >
748 > // ─── resourceDelete ──────────────────────────────────────────────────────────
749 >
750 > /**
751 > * Deletes a resource at a URI on the server's filesystem.
752 > *
753 > * Like all `resource*` methods, `resourceDelete` is symmetrical and MAY be
754 > * sent in either direction.
755 > *
756 > * @category Commands
757 > * @method resourceDelete
758 > * @direction Client ↔ Server
759 > * @messageType Request
760 > * @version 1
761 > * @throws `NotFound` (`-32008`) if the resource does not exist.
762 > * @throws `PermissionDenied` (`-32009`) if the client is not permitted to delete the resource.
763 > */
764 > export interface ResourceDeleteParams extends BaseParams {
765 > channel: 'ahp-root://';
766 > /** URI of the resource to delete */
767 > uri: URI;
768 > /**
769 > * If `true` and the target is a directory, delete it and all its contents
770 > * recursively. If `false` (default), deleting a non-empty directory MUST fail.
771 > */
772 > recursive?: boolean;
773 > }
774 >
775 > /**
776 > * Result of the `resourceDelete` command.
777 > *
778 > * An empty object on success.
779 > */
780 > export interface ResourceDeleteResult {
781 > }
782 >
783 > // ─── resourceRequest ─────────────────────────────────────────────────────────
784 >
785 > /**
786 > * Requests permission to access a resource on the receiver's filesystem.
787 > *
788 > * `resourceRequest` is symmetrical and MAY be sent in either direction: a
789 > * client asks the server to grant access to a server-side resource, or a
790 > * server asks the client to grant access to a client-side resource. The
791 > * receiver decides whether to allow, deny, or prompt the user for the
792 > * requested access.
793 > *
794 > * If the receiver denies access, it MUST respond with `PermissionDenied`
795 > * (-32009). The error data MAY include a `ResourceRequestParams` value
796 > * describing the access the caller would need to be granted for the
797 > * operation to succeed; see `PermissionDeniedErrorData` in
798 > * `types/errors.ts`.
799 > *
800 > * After a successful `resourceRequest`, the caller MAY use the corresponding
801 > * `resource*` commands (e.g. `resourceRead`, `resourceWrite`) to perform the
802 > * operation. Receivers MAY rescind access at any time by returning
803 > * `PermissionDenied` on subsequent operations.
804 > *
805 > * Either `read`, `write`, or both SHOULD be set to `true`. A request with
806 > * neither flag set is treated as `read: true` by receivers.
807 > *
808 > * @category Commands
809 > * @method resourceRequest
810 > * @direction Client ↔ Server
811 > * @messageType Request
812 > * @version 1
813 > * @throws `PermissionDenied` (`-32009`) if access is denied.
814 > */
815 > export interface ResourceRequestParams extends BaseParams {
816 > channel: 'ahp-root://';
817 > /**
818 > * Resource URI being requested. Typically a `file:` URI on the receiver's
819 > * filesystem, but any URI scheme that the receiver mediates access to is
820 > * allowed.
821 > */
822 > uri: URI;
823 > /** Whether the caller needs read access to the resource. */
824 > read?: boolean;
825 > /** Whether the caller needs write access to the resource. */
826 > write?: boolean;
827 > }
828 >
829 > /**
830 > * Result of the `resourceRequest` command.
831 > *
832 > * An empty object on success.
833 > */
834 > export interface ResourceRequestResult {
835 > }
836 >
837 > // ─── resourceMove ────────────────────────────────────────────────────────────
838 >
839 > /**
840 > * Moves (renames) a resource from one URI to another on the server's filesystem.
841 > *
842 > * If the destination already exists, it is overwritten unless `failIfExists`
843 > * is set.
844 > *
845 > * Like all `resource*` methods, `resourceMove` is symmetrical and MAY be
846 > * sent in either direction.
847 > *
848 > * @category Commands
849 > * @method resourceMove
850 > * @direction Client ↔ Server
851 > * @messageType Request
852 > * @version 1
853 > * @throws `NotFound` (`-32008`) if the source does not exist.
854 > * @throws `PermissionDenied` (`-32009`) if the client is not permitted to move the resource.
855 > * @throws `AlreadyExists` (`-32010`) if `failIfExists` is set and the destination already exists.
856 > */
857 > export interface ResourceMoveParams extends BaseParams {
858 > channel: 'ahp-root://';
859 > /** Source URI to move from */
860 > source: URI;
861 > /** Destination URI to move to */
862 > destination: URI;
863 > /**
864 > * If `true`, the server MUST fail if the destination already exists instead
865 > * of overwriting it.
866 > */
867 > failIfExists?: boolean;
868 > }
869 >
870 > /**
871 > * Result of the `resourceMove` command.
872 > *
873 > * An empty object on success.
874 > */
875 > export interface ResourceMoveResult {
876 > }
877 >
878 > // ─── resourceResolve ─────────────────────────────────────────────────────────
879 >
880 > /**
881 > * Discriminant for {@link ResourceResolveResult.type}.
882 > *
883 > * @category Commands
884 > */
885 > export const enum ResourceType {
886 > File = 'file',
887 > Directory = 'directory',
888 > Symlink = 'symlink',
889 > }
890 >
891 > /**
892 > * Resolves a resource — the combination of POSIX `stat` and `realpath`.
893 > *
894 > * `resourceResolve` returns metadata about the resource together with its
895 > * canonical URI after symlink resolution. Use this in place of any
896 > * `resourceExists` shim: a missing resource MUST surface as a `NotFound`
897 > * JSON-RPC error rather than a success with a sentinel value. Callers that
898 > * truly need a boolean check should attempt `resourceResolve` and treat
899 > * `NotFound` as "does not exist".
900 > *
901 > * Like all `resource*` methods, `resourceResolve` is symmetrical and MAY be
902 > * sent in either direction.
903 > *
904 > * @category Commands
905 > * @method resourceResolve
906 > * @direction Client ↔ Server
907 > * @messageType Request
908 > * @version 1
909 > * @throws `NotFound` (`-32008`) if the resource does not exist.
910 > * @throws `PermissionDenied` (`-32009`) if the caller is not permitted to stat the URI.
911 > * @example
912 > * ```jsonc
913 > * // Client → Server
914 > * { "jsonrpc": "2.0", "id": 20, "method": "resourceResolve",
915 > * "params": { "channel": "ahp-root://", "uri": "file:///workspace/hello.txt" } }
916 > *
917 > * // Server → Client
918 > * { "jsonrpc": "2.0", "id": 20, "result": {
919 > * "uri": "file:///workspace/hello.txt",
920 > * "type": "file",
921 > * "size": 5,
922 > * "mtime": "2026-01-15T12:34:56.789Z",
923 > * "etag": "W/\"5-abc123\""
924 > * }}
925 > * ```
926 > */
927 > export interface ResourceResolveParams extends BaseParams {
928 > channel: 'ahp-root://';
929 > /** URI to resolve */
930 > uri: URI;
931 > /**
932 > * When `true` (default), follow symlinks and report the metadata of the
933 > * link target — and set `uri` in the result to the canonical (realpath)
934 > * URI. When `false`, stat the link itself (lstat semantics) and report
935 > * `type: 'symlink'`.
936 > */
937 > followSymlinks?: boolean;
938 > }
939 >
940 > /**
941 > * Result of the `resourceResolve` command.
942 > */
943 > export interface ResourceResolveResult {
944 > /**
945 > * Canonical URI after symlink resolution. Equal to the requested URI when
946 > * `followSymlinks` is `false` or the URI does not traverse a symlink.
947 > */
948 > uri: URI;
949 > /** Resource kind. */
950 > type: ResourceType;
951 > /**
952 > * Size in bytes. Omitted for directories when the provider cannot
953 > * cheaply compute it.
954 > */
955 > size?: number;
956 > /** Last-modified time in ISO 8601 format, when known. */
957 > mtime?: string;
958 > /** Creation time in ISO 8601 format, when known. */
959 > ctime?: string;
960 > /** Sniffed MIME type, when known (e.g. `"text/plain"`, `"image/png"`). */
961 > contentType?: string;
962 > /**
963 > * Opaque per-provider version token. When present, pass it as
964 > * {@link ResourceWriteParams.ifMatch} on a subsequent `resourceWrite` to
965 > * detect concurrent modifications.
966 > */
967 > etag?: string;
968 > }
969 >
970 > // ─── resourceMkdir ───────────────────────────────────────────────────────────
971 >
972 > /**
973 > * Creates a directory on the server's filesystem with `mkdir -p` semantics.
974 > *
975 > * The server MUST create any missing parent directories. Creating a
976 > * directory that already exists is a no-op success. If `uri` already
977 > * exists but is **not** a directory, the server MUST fail with
978 > * `AlreadyExists`.
979 > *
980 > * Like all `resource*` methods, `resourceMkdir` is symmetrical and MAY be
981 > * sent in either direction.
982 > *
983 > * @category Commands
984 > * @method resourceMkdir
985 > * @direction Client ↔ Server
986 > * @messageType Request
987 > * @version 1
988 > * @throws `PermissionDenied` (`-32009`) if the caller is not permitted to create the directory.
989 > * @throws `AlreadyExists` (`-32010`) if `uri` already exists as a non-directory.
990 > */
991 > export interface ResourceMkdirParams extends BaseParams {
992 > channel: 'ahp-root://';
993 > /** Directory URI to create (parents created as needed). */
994 > uri: URI;
995 > }
996 >
997 > /**
998 > * Result of the `resourceMkdir` command.
999 > *
1000 > * An empty object on success.
1001 > */
1002 > export interface ResourceMkdirResult {
1003 > }
1004 >
1005 > // ─── authenticate ────────────────────────────────────────────────────────────
1006 >
1007 > /**
1008 > * Pushes a ****** for a protected resource. The `resource` field MUST
1009 > * match a protected-resource identifier the client has discovered from the
1010 > * server — whether declared statically in `AgentInfo.protectedResources`,
1011 > * or discovered dynamically from a live `McpServerAuthRequiredState.resource`
1012 > * or `ToolCallAuthRequiredState.auth.resource` (both surfaced only once the
1013 > * corresponding MCP server or tool call actually challenges for auth).
1014 > * Servers MUST accept any `resource` value they have themselves advertised
1015 > * through one of these three mechanisms.
1016 > *
1017 > * Tokens are delivered using [RFC 6750](https://datatracker.ietf.org/doc/html/rfc6750)
1018 > * (****** Usage) semantics. The client obtains the token from the
1019 > * authorization server(s) listed in the resource's metadata and pushes it
1020 > * to the server via this command.
1021 > *
1022 > * @category Commands
1023 > * @method authenticate
1024 > * @direction Client → Server
1025 > * @messageType Request
1026 > * @version 1
1027 > * @see {@link /specification/authentication | Authentication}
1028 > * @example
1029 > * ```jsonc
1030 > * // Client → Server
1031 > * { "jsonrpc": "2.0", "id": 3, "method": "authenticate",
1032 > * "params": { "channel": "ahp-root://", "resource": "https://api.github.com", "token": "gho_xxxx" } }
1033 > *
1034 > * // Server → Client (success)
1035 > * { "jsonrpc": "2.0", "id": 3, "result": {} }
1036 > *
1037 > * // Server → Client (failure — invalid token)
1038 > * { "jsonrpc": "2.0", "id": 3, "error": { "code": -32007, "message": "Invalid token" } }
1039 > * ```
1040 > */
1041 > export interface AuthenticateParams extends BaseParams {
1042 > channel: 'ahp-root://';
1043 > /**
1044 > * The protected resource identifier. MUST match a `resource` value the
1045 > * server has advertised — via `ProtectedResourceMetadata` in
1046 > * `AgentInfo.protectedResources`, or via a live
1047 > * `McpServerAuthRequiredState.resource` / `ToolCallAuthRequiredState.auth.resource`.
1048 > */
1049 > resource: string;
1050 > /** ****** obtained from the resource's authorization server */
1051 > token: string;
1052 > /**
1053 > * OAuth scopes the token grants, when known. Lets the server determine
1054 > * whether a specific challenge — e.g. the `requiredScopes` on a live
1055 > * `McpServerAuthRequiredState` or `ToolCallAuthRequiredState.auth` — is
1056 > * satisfied without decoding the (opaque, server-specific) token itself.
1057 > * Omit when the client doesn't track granted scopes separately from the
1058 > * token.
1059 > */
1060 > scopes?: string[];
1061 > }
1062 >
1063 > /**
1064 > * Result of the `authenticate` command.
1065 > *
1066 > * An empty object on success. If the token is invalid or the resource is
1067 > * unrecognized, the server MUST return a JSON-RPC error (e.g. `AuthRequired`
1068 > * `-32007` or `InvalidParams` `-32602`).
1069 > */
1070 > export interface AuthenticateResult {
1071 > }
src/vs/platform/contextkey/common/contextkey.ts 1043 covered LOC · 303 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); contextkey.ts
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); contextkey.ts
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); contextkey.ts
610 > }
611 > public static or(...expr: Array<ContextKeyExpression | undefined | null>): ContextKeyExpression | undefined { contextkey.ts
612 > return ContextKeyOrExpr.create(expr, null, true); contextkey.ts
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 { contextkey.ts
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;
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) { contextkey.ts
784 > return this.type - other.type; contextkey.ts
785 > }
786 return cmp1(this.key, other.key);
787 > } contextkey.ts
789 > public equals(other: ContextKeyExpression): boolean {
790 > if (other.type === this.type) { contextkey.ts
791 return (this.key === other.key);
792 }
793 > return false; contextkey.ts
794 > } contextkey.ts
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) { contextkey.ts
822 > this.negated = ContextKeyNotExpr.create(this.key, this);
823 > }
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';
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, contextkey.ts
846 > private readonly value: any,
847 > private negated: ContextKeyExpression | null
848 > ) {
849 > }
851 > public cmp(other: ContextKeyExpression): number {
852 > if (other.type !== this.type) { contextkey.ts
853 return this.type - other.type;
854 }
855 > return cmp2(this.key, this.value, other.key, other.value); contextkey.ts
856 > } contextkey.ts
858 > public equals(other: ContextKeyExpression): boolean {
859 > if (other.type === this.type) { contextkey.ts
860 > return (this.key === other.key && this.value === other.value); contextkey.ts
861 > }
862 return false;
863 > } contextkey.ts
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) { contextkey.ts
894 > this.negated = ContextKeyNotEqualsExpr.create(this.key, this.value, this);
895 > }
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) {
1048 return ContextKeyNotExpr.create(key, negated);
1050 return ContextKeyDefinedExpr.create(key, negated);
1051 }
1052 > const constantValue = CONSTANT_VALUES.get(key); contextkey.ts
1053 > if (typeof constantValue === 'boolean') {
1054 const falseValue = constantValue ? 'true' : 'false';
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, contextkey.ts
1064 > private readonly value: any,
1065 > private negated: ContextKeyExpression | null
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) { contextkey.ts
1078 return (this.key === other.key && this.value === other.value);
1079 }
1080 > return false; contextkey.ts
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, contextkey.ts
1132 > private negated: ContextKeyExpression | null
1133 > ) {
1134 > }
1135 > contextkey.ts
1136 > public cmp(other: ContextKeyExpression): number {
1137 > if (other.type !== this.type) { contextkey.ts
1138 return this.type - other.type;
1139 }
1140 > return cmp1(this.key, other.key); contextkey.ts
1141 > } contextkey.ts
1142 > contextkey.ts
1143 > public equals(other: ContextKeyExpression): boolean {
1144 > if (other.type === this.type) { contextkey.ts
1145 > return (this.key === other.key); contextkey.ts
1146 > }
1147 return false;
1148 > } contextkey.ts
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) { contextkey.ts
1176 this.negated = ContextKeyDefinedExpr.create(this.key, this);
1177 }
1178 > return this.negated; contextkey.ts
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, contextkey.ts
1444 > private readonly regexp: RegExp | null
1445 > ) {
1446 > //
1447 > }
1448 > contextkey.ts
1449 > public cmp(other: ContextKeyExpression): number {
1450 > if (other.type !== this.type) { contextkey.ts
1451 return this.type - other.type;
1452 }
1453 > if (this.key < other.key) { contextkey.ts
1454 return -1;
1455 }
1456 > if (this.key > other.key) { contextkey.ts
1457 return 1;
1458 }
1459 > const thisSource = this.regexp ? this.regexp.source : ''; contextkey.ts
1460 > const otherSource = other.regexp ? other.regexp.source : '';
1461 > if (thisSource < otherSource) {
1462 return -1;
1463 }
1464 > if (thisSource > otherSource) { contextkey.ts
1465 > return 1;
1466 > }
1467 return 0;
1468 > } contextkey.ts
1469 > contextkey.ts
1470 > public equals(other: ContextKeyExpression): boolean {
1471 > if (other.type === this.type) { contextkey.ts
1472 > const thisSource = this.regexp ? this.regexp.source : '';
1473 > const otherSource = other.regexp ? other.regexp.source : '';
1474 > return (this.key === other.key && thisSource === otherSource);
1475 > }
1476 return false;
1477 > } contextkey.ts
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) { contextkey.ts
1505 > this.negated = ContextKeyNotRegexExpr.create(this);
1506 > }
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 > // contextkey.ts
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) { contextkey.ts
1532 return this._actual.equals(other._actual);
1533 }
1534 > return false; contextkey.ts
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[], contextkey.ts
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[] = []; contextkey.ts
1662 > let hasTrue = false;
1663 >
1664 > for (const e of arr) {
1665 > if (!e) {
1666 continue;
1667 }
1668 > contextkey.ts
1669 > if (e.type === ContextKeyExprType.True) {
1670 // anything && true ==> anything
1671 hasTrue = true;
1672 continue;
1673 }
1674 > contextkey.ts
1675 > if (e.type === ContextKeyExprType.False) {
1676 // anything && false ==> false
1677 return ContextKeyFalseExpr.INSTANCE;
1678 }
1679 > contextkey.ts
1680 > if (e.type === ContextKeyExprType.And) {
1681 expr.push(...e.expr);
1682 continue;
1683 }
1684 > contextkey.ts
1685 > expr.push(e);
1686 > }
1687 >
1688 > if (expr.length === 0 && hasTrue) {
1689 return ContextKeyTrueExpr.INSTANCE;
1690 }
1691 > contextkey.ts
1692 > if (expr.length === 0) {
1693 return undefined;
1694 }
1695 > contextkey.ts
1696 > if (expr.length === 1) {
1697 return expr[0];
1698 }
1699 > contextkey.ts
1700 > expr.sort(cmp);
1701 >
1702 > // eliminate duplicate terms
1703 > for (let i = 1; i < expr.length; i++) {
1704 > if (expr[i - 1].equals(expr[i])) {
1705 expr.splice(i, 1);
1706 i--;
1707 }
1708 > } contextkey.ts
1709 >
1710 > if (expr.length === 1) {
1711 return expr[0];
1712 }
1713 > contextkey.ts
1714 > // We must distribute any OR expression because we don't support parens
1715 > // OR extensions will be at the end (due to sorting rules)
1716 > while (expr.length > 1) {
1717 > const lastElement = expr[expr.length - 1];
1718 > if (lastElement.type !== ContextKeyExprType.Or) {
1719 > break;
1720 > }
1721 // pop the last element
1722 expr.pop();
1738 expr.sort(cmp);
1739 }
1740 > } contextkey.ts
1741 >
1742 > if (expr.length === 1) {
1743 return expr[0];
1744 }
1745 > contextkey.ts
1746 > // resolve false AND expressions
1747 > if (extraRedundantCheck) {
1748 > for (let i = 0; i < expr.length; i++) {
1749 > for (let j = i + 1; j < expr.length; j++) {
1750 > if (expr[i].negate().equals(expr[j])) {
1751 // A && !A case
1752 return ContextKeyFalseExpr.INSTANCE;
1753 }
1754 > } contextkey.ts
1755 > } contextkey.ts
1756 >
1757 > if (expr.length === 1) {
1758 return expr[0];
1759 }
1760 > } contextkey.ts
1761 > contextkey.ts
1762 > return new ContextKeyAndExpr(expr, negated);
1763 > } contextkey.ts
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[], contextkey.ts
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[] = []; contextkey.ts
1861 > let hasFalse = false;
1862 >
1863 > if (arr) {
1864 > for (let i = 0, len = arr.length; i < len; i++) {
1865 > const e = arr[i];
1866 > if (!e) {
1867 continue;
1868 }
1869 > contextkey.ts
1870 > if (e.type === ContextKeyExprType.False) {
1871 // anything || false ==> anything
1872 hasFalse = true;
1873 continue;
1874 }
1875 > contextkey.ts
1876 > if (e.type === ContextKeyExprType.True) {
1877 > // anything || true ==> true contextkey.ts
1878 > return ContextKeyTrueExpr.INSTANCE;
1879 > }
1880 > contextkey.ts
1881 > if (e.type === ContextKeyExprType.Or) {
1882 expr = expr.concat(e.expr);
1883 continue;
1884 }
1885 > contextkey.ts
1886 > expr.push(e);
1887 > }
1888 >
1889 > if (expr.length === 0 && hasFalse) {
1890 return ContextKeyFalseExpr.INSTANCE;
1891 }
1892 > contextkey.ts
1893 > expr.sort(cmp);
1894 > }
1895 >
1896 > if (expr.length === 0) {
1897 return undefined;
1898 }
1899 > contextkey.ts
1900 > if (expr.length === 1) {
1901 return expr[0];
1902 }
1903 > contextkey.ts
1904 > // eliminate duplicate terms
1905 > for (let i = 1; i < expr.length; i++) {
1906 > if (expr[i - 1].equals(expr[i])) {
1907 expr.splice(i, 1);
1908 i--;
1909 }
1910 > } contextkey.ts
1911 >
1912 > if (expr.length === 1) {
1913 return expr[0];
1914 }
1915 > contextkey.ts
1916 > // resolve true OR expressions
1917 > if (extraRedundantCheck) {
1918 > for (let i = 0; i < expr.length; i++) {
1919 > for (let j = i + 1; j < expr.length; j++) {
1920 > if (expr[i].negate().equals(expr[j])) {
1921 // A || !A case
1922 return ContextKeyTrueExpr.INSTANCE;
1923 }
1924 > } contextkey.ts
1925 > } contextkey.ts
1926 >
1927 > if (expr.length === 1) {
1928 return expr[0];
1929 }
1930 > } contextkey.ts
1931 > contextkey.ts
1932 > return new ContextKeyOrExpr(expr, negated);
1933 > } contextkey.ts
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 }); contextkey.ts
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(); contextkey.ts
2018 > }
2019 > contextkey.ts
2020 > public isEqualTo(value: any): ContextKeyExpression {
2021 > return ContextKeyEqualsExpr.create(this.key, value); contextkey.ts
2022 > }
2023 > contextkey.ts
2024 > public notEqualsTo(value: any): ContextKeyExpression {
2025 > return ContextKeyNotEqualsExpr.create(this.key, value); contextkey.ts
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 { contextkey.ts
2086 > if (key1 < key2) {
2087 > return -1; contextkey.ts
2088 > }
2089 > if (key1 > key2) { contextkey.ts
2090 > return 1;
2091 > }
2092 return 0;
2093 }
2094 > contextkey.ts
2095 > function cmp2(key1: string, value1: any, key2: string, value2: any): number { contextkey.ts
2096 > if (key1 < key2) {
2097 return -1;
2098 }
2099 > if (key1 > key2) { contextkey.ts
2100 return 1;
2101 }
2102 > if (value1 < value2) { contextkey.ts
2103 > return -1; contextkey.ts
2104 > }
2105 if (value1 > value2) {
2106 return 1;
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/workbench/contrib/chat/common/languageModels.ts 986 covered LOC · 93 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- languageModels.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { SequencerByKey, timeout } from '../../../../base/common/async.js';
7 > import { VSBuffer } from '../../../../base/common/buffer.js';
8 > import { CancellationToken } from '../../../../base/common/cancellation.js';
9 > import { IStringDictionary } from '../../../../base/common/collections.js';
10 > import { CancellationError, getErrorMessage, isCancellationError } from '../../../../base/common/errors.js';
11 > import { Emitter, Event } from '../../../../base/common/event.js';
12 > import { hash } from '../../../../base/common/hash.js';
13 > import { Iterable } from '../../../../base/common/iterator.js';
14 > import { IJSONSchema, TypeFromJsonSchema } from '../../../../base/common/jsonSchema.js';
15 > import { DisposableStore, IDisposable, toDisposable } from '../../../../base/common/lifecycle.js';
16 > import { IObservable, observableValue } from '../../../../base/common/observable.js';
17 > import { equals } from '../../../../base/common/objects.js';
18 > import Severity from '../../../../base/common/severity.js';
19 > import { format, isFalsyOrWhitespace } from '../../../../base/common/strings.js';
20 > import { ThemeIcon } from '../../../../base/common/themables.js';
21 > import { IAction, SubmenuAction } from '../../../../base/common/actions.js';
22 > import { isObject, isString } from '../../../../base/common/types.js';
23 > import { Schemas } from '../../../../base/common/network.js';
24 > import { URI } from '../../../../base/common/uri.js';
25 > import { generateUuid } from '../../../../base/common/uuid.js';
26 > import { localize } from '../../../../nls.js';
27 > import { ContextKeyExpr, IContextKey, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';
28 > import { ExtensionIdentifier } from '../../../../platform/extensions/common/extensions.js';
29 > import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
30 > import { ILogService } from '../../../../platform/log/common/log.js';
31 > import { INotificationService, NeverShowAgainScope } from '../../../../platform/notification/common/notification.js';
32 > import { IOpenerService } from '../../../../platform/opener/common/opener.js';
33 > import { IProductService } from '../../../../platform/product/common/productService.js';
34 > import { asJson, IRequestService } from '../../../../platform/request/common/request.js';
35 > import { IQuickInputService, IQuickPickItem, QuickInputHideReason } from '../../../../platform/quickinput/common/quickInput.js';
36 > import { ISecretStorageService } from '../../../../platform/secrets/common/secrets.js';
37 > import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js';
38 > import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js';
39 > import { IExtensionService } from '../../../services/extensions/common/extensions.js';
40 > import { ExtensionsRegistry } from '../../../services/extensions/common/extensionsRegistry.js';
41 > import { ChatContextKeys } from './actions/chatContextKeys.js';
42 > import { ChatAgentLocation } from './constants.js';
43 > import { ILanguageModelsProviderGroup, ILanguageModelsConfigurationService } from './languageModelsConfiguration.js';
44 >
45 > /**
46 > * Vendor id used for the built-in GitHub Copilot language model provider. Treated as the default
47 > * vendor across the chat stack (see `ILanguageModelProviderDescriptor.isDefault`).
48 > */
49 > export const COPILOT_VENDOR_ID = 'copilot';
50 >
51 > /** Whether a missing model is conclusively absent from a vendor's live model list. Empty Copilot results remain transient while token-backed discovery completes. */
52 > export function isLanguageModelVendorAbsenceConclusive(vendor: string, hasLiveModels: boolean, hasResolved: boolean): boolean {
53 return hasLiveModels || (hasResolved && vendor !== COPILOT_VENDOR_ID);
54 }
56 > /**
57 > * Vendor ids of the BYOK language-model providers that ship in-built with the GitHub Copilot Chat
58 > * extension. Each provider's vendor id is `providerName.toLowerCase()` (see
59 > * `extensions/copilot/src/extension/byok/vscode-node/*Provider.ts`). This list is intentionally
60 > * hardcoded: the in-built provider set is stable and known ahead of time, which lets us report these
61 > * providers by name while bucketing every other (third-party) provider as `3p-extension`.
62 > */
63 > const BUILT_IN_BYOK_VENDOR_IDS = new Set<string>([
64 > 'openai',
65 > 'anthropic',
66 > 'gemini',
67 > 'ollama',
68 > 'openrouter',
69 > 'azure',
70 > 'xai',
71 > 'customoai',
72 > 'customendpoint',
73 > ]);
74 >
75 > /**
76 > * Bucket reported for any non-Copilot provider that is not an in-built BYOK provider, i.e. a model
77 > * contributed by a third-party extension. We never report the third-party vendor id directly to avoid
78 > * logging potentially identifying values.
79 > */
80 > export const THIRD_PARTY_PROVIDER_TELEMETRY_NAME = '3p-extension';
81 >
82 > const BUILT_IN_BYOK_EXTENSION_IDS = [
83 > 'github.copilot-chat',
84 > 'github.copilot',
85 > ];
86 >
87 > /**
88 > * Normalizes a non-Copilot model vendor into a non-identifying provider name suitable for telemetry:
89 > * the in-built BYOK vendor id (e.g. `openai`, `ollama`) when contributed by the built-in Copilot
90 > * extensions, or {@link THIRD_PARTY_PROVIDER_TELEMETRY_NAME} otherwise. Returns `undefined` for the
91 > * first-party Copilot vendor (or no vendor) so callers skip logging first-party usage.
92 > */
93 > export function getByokProviderTelemetryName(vendor: string | undefined, extension: ExtensionIdentifier | undefined): string | undefined {
94 if (!vendor || vendor === COPILOT_VENDOR_ID) {
95 return undefined;
100 return THIRD_PARTY_PROVIDER_TELEMETRY_NAME;
101 }
103 > export const enum ChatMessageRole {
104 > System,
105 > User,
106 > Assistant,
107 > }
108 >
109 > export enum LanguageModelPartAudience {
110 > Assistant = 0,
111 > User = 1,
112 > Extension = 2,
113 > }
114 >
115 > export interface IChatMessageTextPart {
116 > type: 'text';
117 > value: string;
118 > audience?: LanguageModelPartAudience[];
119 > }
120 >
121 > export interface IChatMessageImagePart {
122 > type: 'image_url';
123 > value: IChatImageURLPart;
124 > }
125 >
126 > export interface IChatMessageThinkingPart {
127 > type: 'thinking';
128 > value: string | string[];
129 > id?: string;
130 > // eslint-disable-next-line @typescript-eslint/no-explicit-any
131 > metadata?: { readonly [key: string]: any };
132 > }
133 >
134 > export interface IChatMessageDataPart {
135 > type: 'data';
136 > mimeType: string;
137 > data: VSBuffer;
138 > audience?: LanguageModelPartAudience[];
139 > }
140 >
141 > export interface IChatImageURLPart {
142 > /**
143 > * The image's MIME type (e.g., "image/png", "image/jpeg").
144 > */
145 > mimeType: ChatImageMimeType;
146 >
147 > /**
148 > * The raw binary data of the image, encoded as a Uint8Array. Note: do not use base64 encoding. Maximum image size is 5MB.
149 > */
150 > data: VSBuffer;
151 > }
152 >
153 > /**
154 > * Enum for supported image MIME types.
155 > */
156 > export enum ChatImageMimeType {
157 > PNG = 'image/png',
158 > JPEG = 'image/jpeg',
159 > GIF = 'image/gif',
160 > WEBP = 'image/webp',
161 > BMP = 'image/bmp',
162 > }
163 >
164 > /**
165 > * Specifies the detail level of the image.
166 > */
167 > export enum ImageDetailLevel {
168 > Low = 'low',
169 > High = 'high'
170 > }
171 >
172 >
173 > export interface IChatMessageToolResultPart {
174 > type: 'tool_result';
175 > toolCallId: string;
176 > value: (IChatResponseTextPart | IChatResponsePromptTsxPart | IChatResponseDataPart)[];
177 > isError?: boolean;
178 > }
179 >
180 > export type IChatMessagePart = IChatMessageTextPart | IChatMessageToolResultPart | IChatResponseToolUsePart | IChatMessageImagePart | IChatMessageDataPart | IChatMessageThinkingPart;
181 >
182 > export interface IChatMessage {
183 > readonly name?: string | undefined;
184 > readonly role: ChatMessageRole;
185 > readonly content: IChatMessagePart[];
186 > }
187 >
188 > export interface IChatResponseTextPart {
189 > type: 'text';
190 > value: string;
191 > audience?: LanguageModelPartAudience[];
192 > }
193 >
194 > export interface IChatResponsePromptTsxPart {
195 > type: 'prompt_tsx';
196 > value: unknown;
197 > }
198 >
199 > export interface IChatResponseDataPart {
200 > type: 'data';
201 > mimeType: string;
202 > data: VSBuffer;
203 > audience?: LanguageModelPartAudience[];
204 > }
205 >
206 > export interface IChatResponseToolUsePart {
207 > type: 'tool_use';
208 > name: string;
209 > toolCallId: string;
210 > // eslint-disable-next-line @typescript-eslint/no-explicit-any
211 > parameters: any;
212 > }
213 >
214 > export interface IChatResponseThinkingPart {
215 > type: 'thinking';
216 > value: string | string[];
217 > id?: string;
218 > // eslint-disable-next-line @typescript-eslint/no-explicit-any
219 > metadata?: { readonly [key: string]: any };
220 > }
221 >
222 > export interface IChatResponsePullRequestPart {
223 > type: 'pullRequest';
224 > uri: URI;
225 > title: string;
226 > description: string;
227 > author: string;
228 > linkTag: string;
229 > }
230 >
231 > export type IChatResponsePart = IChatResponseTextPart | IChatResponseToolUsePart | IChatResponseDataPart | IChatResponseThinkingPart;
232 >
233 > export type IExtendedChatResponsePart = IChatResponsePullRequestPart;
234 >
235 > export interface ILanguageModelConfigurationSchema extends IJSONSchema {
236 > properties?: {
237 > [key: string]: IJSONSchema & {
238 > /** When set to `'navigation'`, the property is shown as a primary action in the model picker. */
239 > group?: string;
240 > /** Labels for enum values. If provided, these are shown instead of the raw enum values. */
241 > enumItemLabels?: string[];
242 > };
243 > };
244 > }
245 >
246 > export interface ILanguageModelChatMetadata {
247 > readonly extension: ExtensionIdentifier;
248 >
249 > readonly name: string;
250 > readonly id: string;
251 > readonly vendor: string;
252 > readonly version: string;
253 > readonly tooltip?: string;
254 > readonly detail?: string;
255 > readonly multiplierNumeric?: number;
256 > readonly isBYOK?: boolean;
257 > readonly pricing?: string;
258 > readonly inputCost?: number;
259 > readonly cacheCost?: number;
260 > readonly cacheWriteCost?: number;
261 > readonly outputCost?: number;
262 > readonly longContextInputCost?: number;
263 > readonly longContextCacheCost?: number;
264 > readonly longContextCacheWriteCost?: number;
265 > readonly longContextOutputCost?: number;
266 > readonly priceCategory?: string;
267 > readonly category?: string;
268 > readonly family: string;
269 > readonly maxInputTokens: number;
270 > readonly maxOutputTokens: number;
271 >
272 > readonly isDefaultForLocation: { [K in ChatAgentLocation]?: boolean };
273 > readonly isUserSelectable?: boolean;
274 > readonly statusIcon?: ThemeIcon;
275 > readonly auth?: {
276 > readonly providerLabel: string;
277 > readonly accountLabel?: string;
278 > };
279 > readonly capabilities?: {
280 > readonly vision?: boolean;
281 > readonly toolCalling?: boolean;
282 > readonly agentMode?: boolean;
283 > readonly editTools?: ReadonlyArray<string>;
284 > };
285 > /**
286 > * When set, this model is only shown in the model picker for the specified chat session type.
287 > * Models with this property are excluded from the general model picker and only appear
288 > * when the user is in a session matching this type.
289 > */
290 > readonly targetChatSessionType?: string;
291 > /**
292 > * Optional grouping hint for the model picker. When set, the picker buckets this model
293 > * under a sub-group within its vendor, identified by this vendor id — e.g. agent-host models,
294 > * which all share one vendor, grouped by their upstream provider — instead of a single
295 > * vendor-wide bucket. The display name is resolved from the vendor registry
296 > * ({@link ILanguageModelsService.getVendors}), the same source used for every other vendor.
297 > * Presentation-only; it does not affect model selection or routing.
298 > */
299 > readonly modelGroup?: { readonly id: string };
300 > /**
301 > * For an agent-host copy of an extension-provided BYOK model, the identifier the
302 > * original model is registered under in the renderer's LM service
303 > * (`toModelIdentifier(vendor, group, id)` — `<vendor>/<group>/<id>` or `<vendor>/<id>`).
304 > * This is exactly the id the "Manage Models" view keys visibility by; it is carried
305 > * across the agent-host bridge and surfaced here so the model picker can honour the
306 > * model's visibility toggle. Absent for native agent-host models and non-agent-host
307 > * models.
308 > */
309 > readonly byokModelIdentifier?: string;
310 > /**
311 > * An optional JSON schema describing the per-model configuration options.
312 > * Used to validate user-provided per-model configuration in `chatLanguageModels.json`.
313 > */
314 > readonly configurationSchema?: ILanguageModelConfigurationSchema;
315 > /**
316 > * Optional warning text to display in the model picker hover as a warning banner.
317 > * The keys are warning categories (e.g. "data_retention") and the values are markdown strings.
318 > */
319 > readonly warningText?: IStringDictionary<string>;
320 > /**
321 > * Optional promotional information for this model. Positive discounts surface
322 > * promotional UI; non-positive discounts only feature the model in the picker.
323 > */
324 > readonly promo?: {
325 > readonly id: string;
326 > readonly discountPercent: number;
327 > readonly endsAt: string;
328 > readonly message: string;
329 > };
330 > }
331 >
332 > export namespace ILanguageModelChatMetadata {
333 > export function suitableForAgentMode(metadata: ILanguageModelChatMetadata): boolean {
334 const supportsToolsAgent = typeof metadata.capabilities?.agentMode === 'undefined' || metadata.capabilities.agentMode;
335 return supportsToolsAgent && !!metadata.capabilities?.toolCalling;
336 }
338 > export function asQualifiedName(metadata: ILanguageModelChatMetadata): string {
339 return `${metadata.name} (${metadata.vendor})`;
340 }
342 > export function matchesQualifiedName(name: string, metadata: ILanguageModelChatMetadata): boolean {
343 if (metadata.vendor === COPILOT_VENDOR_ID && name === metadata.name) {
344 return true;
346 return name === asQualifiedName(metadata);
347 }
349 > export function hasPromoDiscount(metadata: ILanguageModelChatMetadata): metadata is ILanguageModelChatMetadata & { readonly promo: NonNullable<ILanguageModelChatMetadata['promo']> } {
350 return !!metadata.promo && metadata.promo.discountPercent > 0;
351 }
353 > /**
354 > * Documentation link explaining how Auto model selection works.
355 > * NOTE: Also defined in extensions/copilot/src/extension/conversation/common/languageModelAccess.ts — keep in sync.
356 > */
357 > export const autoModelSelectionDocsUrl = 'https://docs.github.com/en/copilot/concepts/models/auto-model-selection';
358 >
359 > /**
360 > * Builds the shared description shown for the Auto model, rendered as Markdown
361 > * (it contains a "Learn More" link). The discount sentence is only included
362 > * when a positive discount is provided.
363 > *
364 > * @param discountPercent Whole-number percentage (e.g. `10` for 10%). When
365 > * omitted or not positive, the discount sentence is left out entirely.
366 > */
367 > export function getAutoModelDescription(discountPercent?: number): string {
368 const base = localize('autoModel.description', "Auto routes based on your task and real-time system health and model performance.");
369 const learnMore = localize('autoModel.learnMore', "[Learn More]({0})", autoModelSelectionDocsUrl);
374 return `${base} ${learnMore}`;
375 }
377 > /**
378 > * The "Manage Models" identifier that an agent-host copy of an extension-provided
379 > * BYOK model is toggled under, or `undefined` when the model is not such a copy.
380 > *
381 > * Agent-host BYOK models make a round trip that rewrites their id (the node agent host
382 > * re-advertises the extension model under the agent-host vendor). Their original LM
383 > * service identifier — `toModelIdentifier(vendor, group, id)`, i.e. `<vendor>/<group>/<id>`
384 > * or `<vendor>/<id>`, which is what the Manage Models view stores when hiding the model —
385 > * is carried across the bridge and surfaced on {@link ILanguageModelChatMetadata.byokModelIdentifier}.
386 > * This returns it, so callers can match the copy against the user's visibility toggles.
387 > *
388 > * Returns `undefined` for models that are not agent-host BYOK copies (native harness
389 > * models and non-agent-host models), which are matched by their own identifier instead.
390 > */
391 > export function getAgentHostByokManageModelsIdentifier(metadata: ILanguageModelChatMetadata): string | undefined {
392 return metadata.byokModelIdentifier;
393 }
395 >
396 > export interface ILanguageModelChatResponse {
397 > stream: AsyncIterable<IChatResponsePart | IChatResponsePart[]>;
398 > // eslint-disable-next-line @typescript-eslint/no-explicit-any
399 > result: Promise<any>;
400 > }
401 >
402 export async function getTextResponseFromStream(response: ILanguageModelChatResponse): Promise<string> {
403 let responseText = '';
429 }
430 }
432 > export interface ILanguageModelChatProvider {
433 > readonly onDidChange: Event<void>;
434 > provideLanguageModelChatInfo(options: ILanguageModelChatInfoOptions, token: CancellationToken): Promise<ILanguageModelChatMetadataAndIdentifier[]>;
435 > sendChatRequest(modelId: string, messages: IChatMessage[], from: ExtensionIdentifier | undefined, options: ILanguageModelChatRequestOptions, token: CancellationToken): Promise<ILanguageModelChatResponse>;
436 > provideTokenCount(modelId: string, message: string | IChatMessage, token: CancellationToken): Promise<number>;
437 > }
438 >
439 > export interface ILanguageModelChat {
440 > metadata: ILanguageModelChatMetadata;
441 > sendChatRequest(messages: IChatMessage[], from: ExtensionIdentifier | undefined, options: ILanguageModelChatRequestOptions, token: CancellationToken): Promise<ILanguageModelChatResponse>;
442 > provideTokenCount(message: string | IChatMessage, token: CancellationToken): Promise<number>;
443 > }
444 >
445 > export interface ILanguageModelChatSelector {
446 > readonly name?: string;
447 > readonly id?: string;
448 > readonly vendor?: string;
449 > readonly version?: string;
450 > readonly family?: string;
451 > readonly tokens?: number;
452 > readonly extension?: ExtensionIdentifier;
453 > }
454 >
455 >
456 > export function isILanguageModelChatSelector(value: unknown): value is ILanguageModelChatSelector {
457 if (typeof value !== 'object' || value === null) {
458 return false;
469 );
470 }
472 > export const ILanguageModelsService = createDecorator<ILanguageModelsService>('ILanguageModelsService');
473 >
474 > export interface ILanguageModelChatMetadataAndIdentifier {
475 > metadata: ILanguageModelChatMetadata;
476 > identifier: string;
477 > }
478 >
479 > export interface ILanguageModelChatInfoOptions {
480 > readonly group?: string;
481 > readonly silent: boolean;
482 > readonly configuration?: IStringDictionary<unknown>;
483 > }
484 >
485 > export interface ILanguageModelChatRequestOptions {
486 > readonly modelOptions?: IStringDictionary<unknown>;
487 > readonly configuration?: IStringDictionary<unknown>;
488 > // eslint-disable-next-line @typescript-eslint/no-explicit-any
489 > readonly [name: string]: any;
490 > }
491 >
492 > export interface ILanguageModelsGroup {
493 > readonly group?: ILanguageModelsProviderGroup;
494 > readonly modelIdentifiers: string[];
495 > readonly status?: {
496 > readonly message: string;
497 > readonly severity: Severity;
498 > };
499 > }
500 >
501 > export interface ILanguageModelsService {
502 >
503 > readonly _serviceBrand: undefined;
504 >
505 > readonly onDidChangeLanguageModelVendors: Event<readonly string[]>;
506 > readonly onDidChangeLanguageModels: Event<string>;
507 >
508 > getLanguageModelIds(): string[];
509 >
510 > getVendors(): ILanguageModelProviderDescriptor[];
511 >
512 > lookupLanguageModel(modelId: string): ILanguageModelChatMetadata | undefined;
513 >
514 > /**
515 > * Find a model by its qualified name. The qualified name is what is used in prompt and agent files and is in the format "Model Name (Vendor)".
516 > */
517 > lookupLanguageModelByQualifiedName(qualifiedName: string): ILanguageModelChatMetadataAndIdentifier | undefined;
518 >
519 > getLanguageModelGroups(vendor: string): ILanguageModelsGroup[];
520 >
521 > /**
522 > * Returns true if the given vendor's provider has completed at least one
523 > * model resolution since registration. A `false` result indicates the
524 > * vendor is still in a startup/reload race where its model list isn't yet
525 > * authoritative — callers can fall back to a cached list in that case.
526 > */
527 > hasResolvedVendor(vendor: string): boolean;
528 >
529 > /**
530 > * Given a selector, returns a list of model identifiers
531 > * @param selector The selector to lookup for language models. If the selector is empty, all language models are returned.
532 > */
533 > selectLanguageModels(selector: ILanguageModelChatSelector): Promise<string[]>;
534 >
535 > registerLanguageModelProvider(vendor: string, provider: ILanguageModelChatProvider): IDisposable;
536 >
537 > deltaLanguageModelChatProviderDescriptors(added: IUserFriendlyLanguageModel[], removed: IUserFriendlyLanguageModel[]): void;
538 >
539 > sendChatRequest(modelId: string, from: ExtensionIdentifier | undefined, messages: IChatMessage[], options: ILanguageModelChatRequestOptions, token: CancellationToken): Promise<ILanguageModelChatResponse>;
540 >
541 > computeTokenLength(modelId: string, message: string | IChatMessage, token: CancellationToken): Promise<number>;
542 >
543 > /**
544 > * Returns the resolved per-model configuration for the given model identifier.
545 > * Includes schema defaults with user overrides applied on top.
546 > * Returns undefined if the model has no configuration schema and no user config.
547 > */
548 > getModelConfiguration(modelId: string): IStringDictionary<unknown> | undefined;
549 >
550 > /**
551 > * Updates the per-model configuration for the given model.
552 > * Merges the provided values into the existing configuration.
553 > */
554 > setModelConfiguration(modelId: string, values: IStringDictionary<unknown>): Promise<void>;
555 >
556 > /**
557 > * Returns actions for configuring the given model based on its configuration schema.
558 > * For enum properties, returns submenu actions with checkable values.
559 > * Returns an empty array if the model has no configuration schema.
560 > */
561 > getModelConfigurationActions(modelId: string): IAction[];
562 >
563 > addLanguageModelsProviderGroup(name: string, vendorId: string, configuration: IStringDictionary<unknown> | undefined): Promise<void>;
564 >
565 > removeLanguageModelsProviderGroup(vendorId: string, providerGroupName: string): Promise<void>;
566 >
567 > configureLanguageModelsProviderGroup(vendorId: string, name?: string): Promise<void>;
568 >
569 > renameLanguageModelsProviderGroup(vendorId: string, providerGroupName: string): Promise<void>;
570 >
571 > updateLanguageModelsProviderGroupApiKey(vendorId: string, providerGroupName: string): Promise<void>;
572 >
573 > addLanguageModelsProviderGroupModel(vendorId: string, providerGroupName: string): Promise<void>;
574 >
575 > openLanguageModelsProviderGroupSettings(vendorId: string, providerGroupName: string): Promise<void>;
576 >
577 > /**
578 > * Opens the language models configuration file and navigates to
579 > * or creates the per-model configuration for the given model.
580 > */
581 > configureModel(modelId: string): Promise<void>;
582 >
583 > migrateLanguageModelsProviderGroup(languageModelsProviderGroup: ILanguageModelsProviderGroup): Promise<void>;
584 >
585 > /**
586 > * Returns the most recently used model identifiers, ordered by most-recent-first.
587 > * @param maxCount Maximum number of entries to return (default 7).
588 > */
589 > getRecentlyUsedModelIds(): string[];
590 >
591 > /**
592 > * Records that a model was used, updating the recently used list.
593 > */
594 > addToRecentlyUsedList(modelIdentifier: string): void;
595 >
596 > /**
597 > * Clears the recently used model list.
598 > */
599 > clearRecentlyUsedList(): void;
600 >
601 > /**
602 > * Returns the pinned model identifiers, in the order they were pinned.
603 > */
604 > getPinnedModelIds(): string[];
605 >
606 > /**
607 > * Pins a model so it appears in the pinned section of the model picker.
608 > */
609 > pinModel(modelIdentifier: string): void;
610 >
611 > /**
612 > * Unpins a model, removing it from the pinned section.
613 > */
614 > unpinModel(modelIdentifier: string): void;
615 >
616 > /**
617 > * Returns whether the given model is pinned.
618 > */
619 > isModelPinned(modelIdentifier: string): boolean;
620 >
621 > /**
622 > * Fires when the pinned models list changes.
623 > */
624 > readonly onDidChangePinnedModels: Event<void>;
625 >
626 > /**
627 > * Returns whether the given model is hidden from the chat model picker.
628 > */
629 > isModelHidden(modelIdentifier: string): boolean;
630 >
631 > /**
632 > * Returns whether every resolved model in the given (vendor, groupName)
633 > * bucket is hidden from the chat model picker.
634 > */
635 > isGroupHidden(vendor: string, groupName: string): boolean;
636 >
637 > /**
638 > * Hide or show a single model in the chat model picker.
639 > */
640 > setModelHidden(modelIdentifier: string, hidden: boolean): void;
641 >
642 > /**
643 > * Hide or show every model in a (vendor, groupName) bucket.
644 > */
645 > setGroupHidden(vendor: string, groupName: string, hidden: boolean): void;
646 >
647 > /**
648 > * Returns the persisted per-model hidden identifiers.
649 > */
650 > getHiddenModelIds(): string[];
651 >
652 > /**
653 > * Fires when any model or group visibility state changes.
654 > */
655 > readonly onDidChangeModelVisibility: Event<void>;
656 >
657 > /**
658 > * Returns the models from the control manifest,
659 > * separated into free and paid tiers.
660 > */
661 > getModelsControlManifest(): IModelsControlManifest;
662 >
663 > /**
664 > * Fires when models control manifest changes.
665 > */
666 > readonly onDidChangeModelsControlManifest: Event<IModelsControlManifest>;
667 >
668 > /**
669 > * Observable map of restricted chat participant names to allowed extension publisher/IDs.
670 > * Fetched from the chat control manifest.
671 > */
672 > readonly restrictedChatParticipants: IObservable<{ [name: string]: string[] }>;
673 > }
674 >
675 > export interface IModelControlEntry {
676 > readonly label: string;
677 > readonly featured?: boolean;
678 > readonly minVSCodeVersion?: string;
679 > readonly exists: boolean;
680 > }
681 >
682 > export interface IModelsControlManifest {
683 > readonly free: IStringDictionary<IModelControlEntry>;
684 > readonly paid: IStringDictionary<IModelControlEntry>;
685 > }
686 >
687 > const languageModelChatProviderType = {
688 > type: 'object',
689 > required: ['vendor', 'displayName'],
690 > properties: {
691 > vendor: {
692 > type: 'string',
693 > description: localize('vscode.extension.contributes.languageModels.vendor', "A globally unique vendor of language model chat provider.")
694 > },
695 > displayName: {
696 > type: 'string',
697 > description: localize('vscode.extension.contributes.languageModels.displayName', "The display name of the language model chat provider.")
698 > },
699 > configuration: {
700 > type: 'object',
701 > description: localize('vscode.extension.contributes.languageModels.configuration', "Configuration options for the language model chat provider."),
702 > anyOf: [
703 > {
704 > $ref: 'http://json-schema.org/draft-07/schema#'
705 > },
706 > {
707 > properties: {
708 > properties: {
709 > type: 'object',
710 > additionalProperties: {
711 > $ref: 'http://json-schema.org/draft-07/schema#',
712 > properties: {
713 > secret: {
714 > type: 'boolean',
715 > description: localize('vscode.extension.contributes.languageModels.configuration.secret', "Whether the property is a secret.")
716 > }
717 > }
718 > }
719 > },
720 > additionalProperties: {
721 > $ref: 'http://json-schema.org/draft-07/schema#',
722 > properties: {
723 > secret: {
724 > type: 'boolean',
725 > description: localize('vscode.extension.contributes.languageModels.configuration.secret', "Whether the property is a secret.")
726 > }
727 > }
728 > }
729 > }
730 > }
731 > ]
732 >
733 > },
734 > managementCommand: {
735 > type: 'string',
736 > description: localize('vscode.extension.contributes.languageModels.managementCommand', "A command to manage the language model chat provider, e.g. 'Manage Copilot models'. This is used in the chat model picker. If not provided, a gear icon is not rendered during vendor selection."),
737 > deprecated: true,
738 > deprecationMessage: localize('vscode.extension.contributes.languageModels.managementCommand.deprecated', "The managementCommand property is deprecated and will be removed in a future release. Use the new configuration property instead.")
739 > },
740 > deprecation: {
741 > type: 'object',
742 > description: localize('vscode.extension.contributes.languageModels.deprecation', "Marks this language model chat provider as deprecated. When set, the Manage Models view renders the provider with a link pointing to a replacement."),
743 > properties: {
744 > link: {
745 > type: 'string',
746 > description: localize('vscode.extension.contributes.languageModels.deprecation.link', "A URL opened when the user clicks the deprecation link shown next to the provider name. Use a 'vscode:extension/<publisher>.<name>' URI to open a replacement extension in the Extensions view.")
747 > }
748 > }
749 > },
750 > when: {
751 > type: 'string',
752 > description: localize('vscode.extension.contributes.languageModels.when', "Condition which must be true to show this language model chat provider in the Manage Models list.")
753 > }
754 > }
755 > } as const satisfies IJSONSchema;
756 >
757 > export type IUserFriendlyLanguageModel = Omit<TypeFromJsonSchema<typeof languageModelChatProviderType>, 'deprecation'> & {
758 > /**
759 > * Marks a provider as deprecated. The Manage Models view renders a link
760 > * (pointing to a replacement, e.g. a `vscode:extension/<publisher>.<name>` URI)
761 > * next to the provider name. Optional so existing provider descriptors are unaffected.
762 > */
763 > readonly deprecation?: { readonly link?: string };
764 > };
765 >
766 > export interface ILanguageModelProviderDescriptor extends IUserFriendlyLanguageModel {
767 > readonly isDefault: boolean;
768 > }
769 >
770 > /**
771 > * Resolves a provider `deprecation.link` for opening inside the current build. Contributions point
772 > * at the replacement extension with a stable `vscode:extension/<id>` URI, but the URL service only
773 > * routes URIs whose scheme matches this build's `urlProtocol` (e.g. `code-oss`, `vscode-insiders`).
774 > * The `vscode:` scheme is therefore rewritten to the current protocol so the extensions URL handler
775 > * opens the extension; without this the opener falls back to treating the URI as a (non-existent)
776 > * file resource and fails. Other schemes (http(s), command) are returned unchanged.
777 > */
778 > export function resolveProviderDeprecationLink(link: string, urlProtocol: string | undefined): URI {
779 const uri = URI.parse(link);
780 return uri.scheme === Schemas.vscode && urlProtocol ? uri.with({ scheme: urlProtocol }) : uri;
781 }
783 > export const languageModelChatProviderExtensionPoint = ExtensionsRegistry.registerExtensionPoint<IUserFriendlyLanguageModel | IUserFriendlyLanguageModel[]>({
784 > extensionPoint: 'languageModelChatProviders',
785 > jsonSchema: {
786 > description: localize('vscode.extension.contributes.languageModelChatProviders', "Contribute language model chat providers of a specific vendor."),
787 > oneOf: [
788 > languageModelChatProviderType,
789 > {
790 > type: 'array',
791 > items: languageModelChatProviderType
792 > }
793 > ]
794 > },
795 > activationEventsGenerator: function* (contribs: readonly IUserFriendlyLanguageModel[]) {
796 for (const contrib of contribs) {
797 yield `onLanguageModelChatProvider:${contrib.vendor}`;
798 }
799 }
800 > }); languageModels.ts
801 >
802 > const CHAT_MODEL_RECENTLY_USED_STORAGE_KEY = 'chatModelRecentlyUsed';
803 > const CHAT_MODEL_PINNED_STORAGE_KEY = 'chatModelPinned';
804 > const CHAT_MODEL_VISIBILITY_STORAGE_KEY = 'chatModelVisibility';
805 >
806 > /**
807 > * The identifier for the Auto model which dynamically routes to the best backend.
808 > * Auto should never appear in user-curated lists (MRU, pinned).
809 > */
810 > const AUTO_MODEL_IDENTIFIER = 'copilot/auto';
811 >
812 > export function isAutoLanguageModel(model: ILanguageModelChatMetadataAndIdentifier | undefined): boolean {
813 return model?.metadata.id === 'auto' || model?.identifier === AUTO_MODEL_IDENTIFIER;
814 }
816 > const CHAT_PARTICIPANT_NAME_REGISTRY_STORAGE_KEY = 'chat.participantNameRegistry';
817 > const CHAT_MODELS_CONTROL_STORAGE_KEY = 'chat.modelsControl';
818 >
819 > interface IChatControlResponse {
820 > readonly version: number;
821 > readonly restrictedChatParticipants: { [name: string]: string[] };
822 > readonly models?: {
823 > readonly free?: Record<string, { readonly label: string; readonly featured?: boolean }>;
824 > readonly paid?: Record<string, { readonly label: string; readonly featured?: boolean; readonly minVSCodeVersion?: string }>;
825 > };
826 > }
827 >
828 > /**
829 > * Builds the per-model configuration submenu actions from a model's
830 > * {@link ILanguageModelConfigurationSchema}. The current value is read from
831 > * `currentConfig` and selections are routed through `setValue`, allowing the
832 > * caller to decide whether changes apply globally or to a per-editor override.
833 > */
834 > export function createModelConfigurationActions(
835 schema: ILanguageModelConfigurationSchema | undefined,
836 currentConfig: IStringDictionary<unknown>,
873 return actions;
874 }
876 > export class LanguageModelsService implements ILanguageModelsService {
877 >
878 > private static SECRET_KEY_PREFIX = 'chat.lm.secret.';
879 > private static SECRET_INPUT = '${input:{0}}';
880 >
881 > readonly _serviceBrand: undefined;
882 >
883 > private readonly _store = new DisposableStore();
884 >
885 > private readonly _providers = new Map<string, ILanguageModelChatProvider>();
886 > private readonly _vendors = new Map<string, ILanguageModelProviderDescriptor>();
887 >
888 > /** Vendors for which a deprecation notice has already been shown this session. */
889 > private readonly _deprecationNoticeShownVendors = new Set<string>();
890 >
891 > private readonly _onDidChangeLanguageModelVendors = this._store.add(new Emitter<string[]>());
892 > readonly onDidChangeLanguageModelVendors = this._onDidChangeLanguageModelVendors.event;
893 >
894 > private readonly _modelsGroups = new Map<string, ILanguageModelsGroup[]>();
895 > private readonly _modelCache = new Map<string, ILanguageModelChatMetadata>();
896 > private readonly _resolveLMSequencer = new SequencerByKey<string>();
897 > private readonly _modelConfigurations = new Map<string, IStringDictionary<unknown>>();
898 > private readonly _hasUserSelectableModels: IContextKey<boolean>;
899 > private readonly _hasNonCopilotUserSelectableModels: IContextKey<boolean>;
900 >
901 > private readonly _onLanguageModelChange = this._store.add(new Emitter<string>());
902 > readonly onDidChangeLanguageModels: Event<string> = this._onLanguageModelChange.event;
903 >
904 > private _recentlyUsedModelIds: string[] = [];
905 > private _pinnedModelIds: string[] = [];
906 >
907 > private _hiddenModelIds = new Set<string>();
908 >
909 > private readonly _onDidChangeModelsControlManifest = this._store.add(new Emitter<IModelsControlManifest>());
910 > readonly onDidChangeModelsControlManifest = this._onDidChangeModelsControlManifest.event;
911 >
912 > private readonly _onDidChangePinnedModels = this._store.add(new Emitter<void>());
913 > readonly onDidChangePinnedModels = this._onDidChangePinnedModels.event;
914 >
915 > private readonly _onDidChangeModelVisibility = this._store.add(new Emitter<void>());
916 > readonly onDidChangeModelVisibility = this._onDidChangeModelVisibility.event;
917 >
918 > private _modelsControlManifest: IModelsControlManifest = { free: {}, paid: {} };
919 > private _modelsControlRawResponse: IChatControlResponse['models'] | undefined;
920 >
921 > private _chatControlUrl: string | undefined;
922 > private _chatControlDisposed = false;
923 >
924 > private readonly _restrictedChatParticipants = observableValue<{ [name: string]: string[] }>(this, Object.create(null));
925 > readonly restrictedChatParticipants: IObservable<{ [name: string]: string[] }> = this._restrictedChatParticipants;
926 >
927 > constructor(
928 @IExtensionService private readonly _extensionService: IExtensionService,
929 @ILogService private readonly _logService: ILogService,
996 }));
997 }
999 > deltaLanguageModelChatProviderDescriptors(added: IUserFriendlyLanguageModel[], removed: IUserFriendlyLanguageModel[]): void {
1000 const addedVendorIds: string[] = [];
1001 const removedVendorIds: string[] = [];
1051 }
1052 }
1054 > private async _onDidChangeLanguageModelGroups(changedGroups: readonly ILanguageModelsProviderGroup[]): Promise<void> {
1055 const changedVendors = new Set(changedGroups.map(g => g.vendor));
1056 await Promise.all(Array.from(changedVendors).map(vendor => this._resolveAllLanguageModels(vendor, true)));
1057 }
1059 > getVendors(): ILanguageModelProviderDescriptor[] {
1060 return Array.from(this._vendors.values())
1061 .filter(vendor => {
1067 });
1068 }
1070 > getLanguageModelIds(): string[] {
1071 return Array.from(this._modelCache.keys());
1072 }
1074 > lookupLanguageModel(modelIdentifier: string): ILanguageModelChatMetadata | undefined {
1075 return this._modelCache.get(modelIdentifier);
1076 }
1078 > lookupLanguageModelByQualifiedName(referenceName: string): ILanguageModelChatMetadataAndIdentifier | undefined {
1079 for (const [identifier, model] of this._modelCache.entries()) {
1080 if (ILanguageModelChatMetadata.matchesQualifiedName(referenceName, model)) {
1084 return undefined;
1085 }
1087 > private async _resolveAllLanguageModels(vendorId: string, silent: boolean): Promise<void> {
1088
1089 const vendor = this._vendors.get(vendorId);
1247 });
1248 }
1250 > private _hasGroupStructureChanged(oldGroups: readonly ILanguageModelsGroup[], newGroups: readonly ILanguageModelsGroup[]): boolean {
1251 if (oldGroups.length !== newGroups.length) {
1252 return true;
1265 return false;
1266 }
1268 > getLanguageModelGroups(vendor: string): ILanguageModelsGroup[] {
1269 return this._modelsGroups.get(vendor) ?? [];
1270 }
1272 > hasResolvedVendor(vendor: string): boolean {
1273 return this._modelsGroups.has(vendor);
1274 }
1276 > async selectLanguageModels(selector: ILanguageModelChatSelector): Promise<string[]> {
1277
1278 if (selector.vendor) {
1298 return result;
1299 }
1301 > registerLanguageModelProvider(vendor: string, provider: ILanguageModelChatProvider): IDisposable {
1302 this._logService.trace('[LM] registering language model provider', vendor, provider);
1303
1323 });
1324 }
1326 > async sendChatRequest(modelId: string, from: ExtensionIdentifier | undefined, messages: IChatMessage[], options: ILanguageModelChatRequestOptions, token: CancellationToken): Promise<ILanguageModelChatResponse> {
1327 const metadata = this._modelCache.get(modelId);
1328 const provider = this._providers.get(metadata?.vendor || '');
1338 return provider.sendChatRequest(modelId, messages, from, mergedOptions, token);
1339 }
1341 > /**
1342 > * When a chat request is made against a deprecated provider (one that contributes a
1343 > * `deprecation.link`), prompt the user once per session to install the replacement
1344 > * extension. The notification can be dismissed, and offers a "Don't Show Again" choice that
1345 > * is persisted across sessions via the notification service's `neverShowAgain` support.
1346 > */
1347 > private _maybeShowProviderDeprecationNotice(metadata: ILanguageModelChatMetadata): void {
1348 const vendor = this._vendors.get(metadata.vendor);
1349 const link = vendor?.deprecation?.link;
1369 );
1370 }
1372 > /**
1373 > * Reports which in-built BYOK provider (or third-party extension) backs a model request. First-party
1374 > * Copilot models are intentionally not reported here (see {@link getByokProviderTelemetryName}).
1375 > */
1376 > private _logProviderUsageTelemetry(metadata: ILanguageModelChatMetadata | undefined): void {
1377 const provider = getByokProviderTelemetryName(metadata?.vendor, metadata?.extension);
1378 if (!provider) {
1394 });
1395 }
1397 > private _resolveModelConfigurationWithDefaults(modelId: string, metadata: ILanguageModelChatMetadata | undefined): IStringDictionary<unknown> | undefined {
1398 const userConfig = this._modelConfigurations.get(modelId);
1399 const schema = metadata?.configurationSchema;
1420 return { ...defaults, ...userConfig };
1421 }
1423 > computeTokenLength(modelId: string, message: string | IChatMessage, token: CancellationToken): Promise<number> {
1424 const model = this._modelCache.get(modelId);
1425 if (!model) {
1432 return provider.provideTokenCount(modelId, message, token);
1433 }
1435 > getModelConfiguration(modelId: string): IStringDictionary<unknown> | undefined {
1436 const metadata = this._modelCache.get(modelId);
1437 return this._resolveModelConfigurationWithDefaults(modelId, metadata);
1438 }
1440 > async setModelConfiguration(modelId: string, values: IStringDictionary<unknown>): Promise<void> {
1441 const metadata = this._modelCache.get(modelId);
1442 if (!metadata) {
1528 this._onLanguageModelChange.fire(metadata.vendor);
1529 }
1531 > getModelConfigurationActions(modelId: string): IAction[] {
1532 const metadata = this._modelCache.get(modelId);
1533 const currentConfig = this._modelConfigurations.get(modelId) ?? {};
1538 );
1539 }
1541 > async configureLanguageModelsProviderGroup(vendorId: string, providerGroupName?: string): Promise<void> {
1542
1543 const vendor = this.getVendors().find(({ vendor }) => vendor === vendorId);
1583 }
1584 }
1586 > async renameLanguageModelsProviderGroup(vendorId: string, providerGroupName: string): Promise<void> {
1587 const vendor = this.getVendors().find(({ vendor }) => vendor === vendorId);
1588 if (!vendor) {
1603 await this._languageModelsConfigurationService.updateLanguageModelsProviderGroup(existing, { ...existing, name });
1604 }
1606 > async updateLanguageModelsProviderGroupApiKey(vendorId: string, providerGroupName: string): Promise<void> {
1607 const vendor = this.getVendors().find(({ vendor }) => vendor === vendorId);
1608 const schema = vendor?.configuration as IJSONSchema | undefined;
1638 }
1639 }
1641 > async addLanguageModelsProviderGroupModel(vendorId: string, providerGroupName: string): Promise<void> {
1642 const vendor = this.getVendors().find(({ vendor }) => vendor === vendorId);
1643 const schema = vendor?.configuration as IJSONSchema | undefined;
1664 });
1665 }
1667 > async openLanguageModelsProviderGroupSettings(vendorId: string, providerGroupName: string): Promise<void> {
1668 const group = this._languageModelsConfigurationService.getLanguageModelsProviderGroups().find(group => group.vendor === vendorId && group.name === providerGroupName);
1669 if (!group) {
1673 await this._languageModelsConfigurationService.configureLanguageModels({ group });
1674 }
1676 > async configureModel(modelId: string): Promise<void> {
1677 const metadata = this._modelCache.get(modelId);
1678 if (!metadata || !metadata.configurationSchema) {
1708 await this._languageModelsConfigurationService.configureLanguageModels({ group, snippet });
1709 }
1711 > private _getModelConfigurationSnippet(modelId: string, schema: ILanguageModelConfigurationSchema): string {
1712 const properties: string[] = [];
1713 if (schema.properties) {
1730 return `"settings": {\n\t\t"${modelId}": ${modelContent}\n\t}`;
1731 }
1733 > async addLanguageModelsProviderGroup(name: string, vendorId: string, configuration: IStringDictionary<unknown> | undefined): Promise<void> {
1734 const vendor = this.getVendors().find(({ vendor }) => vendor === vendorId);
1735 if (!vendor) {
1740 await this._languageModelsConfigurationService.addLanguageModelsProviderGroup(languageModelProviderGroup);
1741 }
1743 > async removeLanguageModelsProviderGroup(vendorId: string, providerGroupName: string): Promise<void> {
1744 const vendor = this.getVendors().find(({ vendor }) => vendor === vendorId);
1745 if (!vendor) {
1757 await this._languageModelsConfigurationService.removeLanguageModelsProviderGroup(existing);
1758 }
1760 > private requireConfiguring(schema: IJSONSchema): boolean {
1761 if (schema.additionalProperties) {
1762 return true;
1772 return false;
1773 }
1775 > private getSnippetForFirstUnconfiguredProperty(configuration: IStringDictionary<unknown>, schema: IJSONSchema): string | undefined {
1776 if (!schema.properties) {
1777 return undefined;
1788 return undefined;
1789 }
1791 > private getSnippetForProperty(property: string, propertySchema: IJSONSchema): string | undefined {
1792 const bodyText = this.getDefaultSnippetBodyText(propertySchema);
1793 return bodyText ? `"${property}": ${bodyText}` : undefined;
1794 }
1796 > private getSnippetForArrayItem(propertySchema: IJSONSchema): string | undefined {
1797 return this.getDefaultSnippetBodyText(propertySchema, true);
1798 }
1800 > private getDefaultSnippetBodyText(propertySchema: IJSONSchema, arrayItem = false): string | undefined {
1801 const snippet = propertySchema.defaultSnippets?.[0];
1802 if (!snippet) {
1813 return bodyText.replace(/"(\^[^"]*)"/g, (_, value) => value.substring(1));
1814 }
1816 > private async promptForName(languageModelProviderGroups: readonly ILanguageModelsProviderGroup[], vendor: IUserFriendlyLanguageModel, existing: ILanguageModelsProviderGroup | undefined): Promise<string | undefined> {
1817 let providerGroupName = existing?.name;
1818 if (!providerGroupName) {
1861 return result;
1862 }
1864 > private async promptForConfiguration(groupName: string, configuration: IJSONSchema, existing: IStringDictionary<unknown> | undefined): Promise<IStringDictionary<unknown> | undefined> {
1865 if (!configuration.properties) {
1866 return;
1880 return result;
1881 }
1883 > private async promptForValue(groupName: string, property: string, propertySchema: IJSONSchema | undefined, required: boolean, existing: IStringDictionary<unknown> | undefined): Promise<unknown | undefined> {
1884 if (!propertySchema) {
1885 return undefined;
1909 return value;
1910 }
1912 > private canPromptForProperty(propertySchema: IJSONSchema | undefined): boolean {
1913 if (!propertySchema || typeof propertySchema === 'boolean') {
1914 return false;
1925 return false;
1926 }
1928 > private getDescriptionPlaintext(propertySchema: IJSONSchema): string | undefined {
1929 if (propertySchema.description) {
1930 return propertySchema.description;
1942 .replace(/\[([^\]]+)\]\([^)]+\)/g, '$1');
1943 }
1945 > private async promptForArray(groupName: string, property: string, propertySchema: IJSONSchema): Promise<string[] | undefined> {
1946 if (!propertySchema.items || Array.isArray(propertySchema.items) || !propertySchema.items.enum) {
1947 return undefined;
1971 }
1972 }
1974 > private async promptForEnum(groupName: string, property: string, propertySchema: IJSONSchema & { enumItemLabels?: string[] }, existing: IStringDictionary<unknown> | undefined): Promise<string | undefined> {
1975 const values = propertySchema.enum;
1976 if (!Array.isArray(values) || values.length === 0) {
2014 }
2015 }
2017 > private async promptForInput(groupName: string, property: string, propertySchema: IJSONSchema, required: boolean, existing: IStringDictionary<unknown> | undefined): Promise<string | number | boolean | undefined> {
2018 const disposables = new DisposableStore();
2019 try {
2090 }
2091 }
2093 > private encodeSecretKey(property: string): string {
2094 return format(LanguageModelsService.SECRET_INPUT, property);
2095 }
2097 > private decodeSecretKey(secretInput: unknown): string | undefined {
2098 if (!isString(secretInput)) {
2099 return undefined;
2101 return secretInput.substring(secretInput.indexOf(':') + 1, secretInput.length - 1);
2102 }
2104 > private _clearModelCache(vendor: string): Map<string, ILanguageModelChatMetadata> {
2105 const removed = new Map<string, ILanguageModelChatMetadata>();
2106 for (const [id, model] of this._modelCache.entries()) {
2112 return removed;
2113 }
2115 > private _clearModelConfigurations(vendor: string): void {
2116 for (const [id] of this._modelConfigurations) {
2117 if (this._modelCache.get(id)?.vendor === vendor || id.startsWith(`${vendor}/`)) {
2120 }
2121 }
2123 > private async _resolveConfiguration(group: ILanguageModelsProviderGroup, schema: IJSONSchema | undefined): Promise<IStringDictionary<unknown>> {
2124 if (!schema) {
2125 return {};
2141 return result;
2142 }
2144 > private async _resolveLanguageModelProviderGroup(name: string, vendor: string, configuration: IStringDictionary<unknown> | undefined, schema: IJSONSchema | undefined): Promise<ILanguageModelsProviderGroup> {
2145 if (!schema) {
2146 return { name, vendor };
2160 return { name, vendor, ...result };
2161 }
2163 > private async _deleteSecretsInConfiguration(group: ILanguageModelsProviderGroup, schema: IJSONSchema | undefined): Promise<void> {
2164 if (!schema) {
2165 return;
2177 }
2178 }
2180 > async migrateLanguageModelsProviderGroup(languageModelsProviderGroup: ILanguageModelsProviderGroup): Promise<void> {
2181 const { vendor, name, ...configuration } = languageModelsProviderGroup;
2182 if (!this._vendors.get(vendor)) {
2194 await this.addLanguageModelsProviderGroup(name, vendor, configuration);
2195 }
2197 > //#region Recently used models
2198 >
2199 > private _readRecentlyUsedModels(): string[] {
2200 return this._storageService.getObject<string[]>(CHAT_MODEL_RECENTLY_USED_STORAGE_KEY, StorageScope.PROFILE, []);
2201 }
2203 > private _saveRecentlyUsedModels(): void {
2204 this._storageService.store(CHAT_MODEL_RECENTLY_USED_STORAGE_KEY, this._recentlyUsedModelIds, StorageScope.PROFILE, StorageTarget.USER);
2205 }
2207 > getRecentlyUsedModelIds(): string[] {
2208 // Filter to only include models that still exist in the cache
2209 return this._recentlyUsedModelIds
2211 .slice(0, 4);
2212 }
2214 > addToRecentlyUsedList(modelIdentifier: string): void {
2215 if (modelIdentifier === AUTO_MODEL_IDENTIFIER) {
2216 return;
2230 this._saveRecentlyUsedModels();
2231 }
2233 > clearRecentlyUsedList(): void {
2234 this._recentlyUsedModelIds = [];
2235 this._saveRecentlyUsedModels();
2236 }
2238 > //#endregion
2239 >
2240 > //#region Pinned models
2241 >
2242 > private _readPinnedModels(): string[] {
2243 return this._storageService.getObject<string[]>(CHAT_MODEL_PINNED_STORAGE_KEY, StorageScope.PROFILE, []);
2244 }
2246 > private _savePinnedModels(): void {
2247 this._storageService.store(CHAT_MODEL_PINNED_STORAGE_KEY, this._pinnedModelIds, StorageScope.PROFILE, StorageTarget.USER);
2248 }
2250 > getPinnedModelIds(): string[] {
2251 return this._pinnedModelIds.filter(id => id !== AUTO_MODEL_IDENTIFIER && this._modelCache.has(id));
2252 }
2254 > pinModel(modelIdentifier: string): void {
2255 if (modelIdentifier === AUTO_MODEL_IDENTIFIER || this._pinnedModelIds.includes(modelIdentifier)) {
2256 return;
2260 this._onDidChangePinnedModels.fire();
2261 }
2263 > unpinModel(modelIdentifier: string): void {
2264 const index = this._pinnedModelIds.indexOf(modelIdentifier);
2265 if (index === -1) {
2270 this._onDidChangePinnedModels.fire();
2271 }
2273 > isModelPinned(modelIdentifier: string): boolean {
2274 return modelIdentifier !== AUTO_MODEL_IDENTIFIER && this._pinnedModelIds.includes(modelIdentifier);
2275 }
2277 > //#endregion
2278 >
2279 > //#region Model visibility
2280 >
2281 > private _getGroupNameForVendor(vendor: string): string {
2282 return this._vendors.get(vendor)?.displayName ?? vendor;
2283 }
2285 > private _getModelIdsInGroup(vendor: string, groupName: string): string[] {
2286 const vendorGroups = this._modelsGroups.get(vendor);
2287 if (!vendorGroups) {
2311 return result;
2312 }
2314 > private _readVisibility(): void {
2315 const raw = this._storageService.getObject<{ hiddenModels?: string[] }>(CHAT_MODEL_VISIBILITY_STORAGE_KEY, StorageScope.PROFILE, {});
2316 this._hiddenModelIds = new Set(Array.isArray(raw?.hiddenModels) ? raw.hiddenModels : []);
2317 }
2319 > private _saveVisibility(): void {
2320 this._storageService.store(
2321 CHAT_MODEL_VISIBILITY_STORAGE_KEY,
2325 );
2326 }
2328 > isGroupHidden(vendor: string, groupName: string): boolean {
2329 const modelIds = this._getModelIdsInGroup(vendor, groupName);
2330 return modelIds.length > 0 && modelIds.every(id => this._hiddenModelIds.has(id));
2331 }
2333 > isModelHidden(modelIdentifier: string): boolean {
2334 return this._hiddenModelIds.has(modelIdentifier);
2335 }
2337 > setGroupHidden(vendor: string, groupName: string, hidden: boolean): void {
2338 let changed = false;
2339 const modelIds = this._getModelIdsInGroup(vendor, groupName);
2353 }
2354 }
2356 > setModelHidden(modelIdentifier: string, hidden: boolean): void {
2357 let changed = false;
2358 if (hidden) {
2369 }
2370 }
2372 > getHiddenModelIds(): string[] {
2373 return Array.from(this._hiddenModelIds);
2374 }
2376 > //#endregion
2377 >
2378 > //#region Models control manifest
2379 >
2380 > getModelsControlManifest(): IModelsControlManifest {
2381 return this._modelsControlManifest;
2382 }
2384 > private _setModelsControlManifest(response: IChatControlResponse['models']): void {
2385 this._modelsControlRawResponse = response;
2386 this._refreshModelsControlManifest();
2387 }
2389 > private _refreshModelsControlManifest(): void {
2390 const response = this._modelsControlRawResponse;
2391 const free: IStringDictionary<IModelControlEntry> = {};
2415 this._onDidChangeModelsControlManifest.fire(this._modelsControlManifest);
2416 }
2418 > //#region Chat control data
2419 > private _initChatControlData(): void {
2420 this._chatControlUrl = this._productService.chatParticipantRegistry;
2421 if (!this._chatControlUrl) {
2444 this._refreshChatControlData();
2445 }
2447 > private _refreshChatControlData(): void {
2448 if (this._chatControlDisposed) {
2449 return;
2455 .then(() => this._refreshChatControlData());
2456 }
2458 > private async _fetchChatControlData(): Promise<void> {
2459 this._logService.trace('[LM] Fetching chat control data from', this._chatControlUrl);
2460
2499 }
2500 }
2502 > //#endregion
2503 >
2504 > dispose() {
2505 this._chatControlDisposed = true;
2506 this._store.dispose();
2507 this._providers.clear();
2508 }
2510 > }
src/vs/workbench/contrib/mcp/common/mcpTypes.ts 935 covered LOC · 31 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- mcpTypes.ts
2 > * Copyright (c) Microsoft 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 as arraysEqual } from '../../../../base/common/arrays.js';
7 > import { assertNever } from '../../../../base/common/assert.js';
8 > import { decodeHex, encodeHex, VSBuffer } from '../../../../base/common/buffer.js';
9 > import { CancellationToken } from '../../../../base/common/cancellation.js';
10 > import { Event } from '../../../../base/common/event.js';
11 > import { IMarkdownString } from '../../../../base/common/htmlContent.js';
12 > import { Disposable, IDisposable } from '../../../../base/common/lifecycle.js';
13 > import { equals as objectsEqual } from '../../../../base/common/objects.js';
14 > import { IObservable, ObservableMap } from '../../../../base/common/observable.js';
15 > import { IIterativePager } from '../../../../base/common/paging.js';
16 > import Severity from '../../../../base/common/severity.js';
17 > import { URI, UriComponents } from '../../../../base/common/uri.js';
18 > import { Location } from '../../../../editor/common/languages.js';
19 > import { localize } from '../../../../nls.js';
20 > import { ConfigurationTarget } from '../../../../platform/configuration/common/configuration.js';
21 > import { RawContextKey } from '../../../../platform/contextkey/common/contextkey.js';
22 > import { IEditorOptions } from '../../../../platform/editor/common/editor.js';
23 > import { ExtensionIdentifier } from '../../../../platform/extensions/common/extensions.js';
24 > import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
25 > import { McpGalleryManifestStatus } from '../../../../platform/mcp/common/mcpGalleryManifest.js';
26 > import { IGalleryMcpServer, IGalleryMcpServerConfiguration, IInstallableMcpServer, IQueryOptions } from '../../../../platform/mcp/common/mcpManagement.js';
27 > import { IMcpDevModeConfig, IMcpSandboxConfiguration, IMcpServerConfiguration } from '../../../../platform/mcp/common/mcpPlatformTypes.js';
28 > import { StorageScope } from '../../../../platform/storage/common/storage.js';
29 > import { IWorkspaceFolder, IWorkspaceFolderData } from '../../../../platform/workspace/common/workspace.js';
30 > import { IWorkbenchLocalMcpServer, IWorkbencMcpServerInstallOptions, WORKSPACE_FOLDER_CONFIG_ID_PREFIX } from '../../../services/mcp/common/mcpWorkbenchManagementService.js';
31 > import { ContributionEnablementState, IEnablementModel } from '../../chat/common/enablement.js';
32 > import { ToolProgress } from '../../chat/common/tools/languageModelToolsService.js';
33 > import { IMcpServerSamplingConfiguration } from './mcpConfiguration.js';
34 > import { McpServerRequestHandler } from './mcpServerRequestHandler.js';
35 > import { MCP } from './modelContextProtocol.js';
36 > import { UriTemplate } from '../../../../base/common/uriTemplate.js';
37 >
38 > export const extensionMcpCollectionPrefix = 'ext.';
39 >
40 > /**
41 > * Prefix of the collection id used for MCP servers configured via the various
42 > * `mcp.json`-style config files (user, remote user, workspace, and
43 > * `.vscode/mcp.json` workspace-folder configs). The suffix is the
44 > * {@link IMcpConfigPath.id} of the originating config path.
45 > */
46 > export const MCP_CONFIGURATION_COLLECTION_ID_PREFIX = 'mcp.config.';
47 >
48 > export function extensionPrefixedIdentifier(identifier: ExtensionIdentifier, id: string): string {
49 return ExtensionIdentifier.toKey(identifier) + '/' + id;
50 }
52 > /**
53 > * An McpCollection contains McpServers. There may be multiple collections for
54 > * different locations servers are discovered.
55 > */
56 > export interface McpCollectionDefinition {
57 > /** Origin authority from which this collection was discovered. */
58 > readonly remoteAuthority: string | null;
59 > /** Globally-unique, stable ID for this definition */
60 > readonly id: string;
61 > /** Human-readable label for the definition */
62 > readonly label: string;
63 > /** Definitions this collection contains. */
64 > readonly serverDefinitions: IObservable<readonly McpServerDefinition[]>;
65 > /**
66 > * Trust behavior of the servers. `Trusted` means it will run without a prompt, always.
67 > * `TrustedOnNonce` means it will run without a prompt as long as the nonce matches.
68 > */
69 > readonly trustBehavior: McpServerTrust.Kind.Trusted | McpServerTrust.Kind.TrustedOnNonce;
70 > /** Scope where associated collection info should be stored. */
71 > readonly scope: StorageScope;
72 > /** Configuration target where configuration related to this server should be stored. */
73 > readonly configTarget: ConfigurationTarget;
74 > /** Root-level sandbox settings from the mcp config file. */
75 > readonly sandbox?: IMcpSandboxConfiguration;
76 >
77 > /** Resolves a server definition. If present, always called before a server starts. */
78 > resolveServerLanch?(definition: McpServerDefinition): Promise<McpServerLaunch | undefined>;
79 >
80 > /** For lazy-loaded collections only: */
81 > readonly lazy?: {
82 > /** True if `serverDefinitions` were loaded from the cache */
83 > isCached: boolean;
84 > /** Triggers a load of the real server definition, which should be pushed to the IMcpRegistry. If not this definition will be removed. */
85 > load(): Promise<void>;
86 > /** Called after `load()` if the extension is not found. */
87 > removed?(): void;
88 > };
89 >
90 > readonly source?: IWorkbenchMcpServer | ExtensionIdentifier;
91 >
92 > /** Sort order of the collection. Lower values have higher priority. */
93 > readonly order: number;
94 >
95 > readonly presentation?: {
96 > /** Place where this collection is configured, used in workspace trust prompts and "show config" */
97 > readonly origin?: URI;
98 > };
99 > }
100 >
101 > export const enum McpCollectionSortOrder {
102 > WorkspaceFolder = 0,
103 > Workspace = 100,
104 > User = 200,
105 > Extension = 300,
106 > Plugin = 350,
107 > Filesystem = 400,
108 >
109 > RemoteBoost = -50,
110 > }
111 >
112 > export namespace McpCollectionDefinition {
113 > export interface FromExtHost {
114 > readonly id: string;
115 > readonly label: string;
116 > readonly isTrustedByDefault: boolean;
117 > readonly scope: StorageScope;
118 > readonly canResolveLaunch: boolean;
119 > readonly extensionId: string;
120 > readonly configTarget: ConfigurationTarget;
121 > }
122 >
123 > export function equals(a: McpCollectionDefinition, b: McpCollectionDefinition): boolean {
124 return a.id === b.id
125 && a.remoteAuthority === b.remoteAuthority
128 && objectsEqual(a.sandbox, b.sandbox);
129 }
130 > mcpTypes.ts
131 > /**
132 > * Returns `true` when the collection was discovered from the workspace (its
133 > * config target is the workspace or a workspace folder). This is
134 > * intentionally based on the config target and not the storage scope:
135 > * extension-contributed collections use a workspace storage scope but are
136 > * configured at the user level, so they are not workspace-discovered.
137 > */
138 > export function isWorkspaceDiscovered(collection: McpCollectionDefinition): boolean {
139 return collection.configTarget === ConfigurationTarget.WORKSPACE
140 || collection.configTarget === ConfigurationTarget.WORKSPACE_FOLDER;
141 }
142 > mcpTypes.ts
143 > /**
144 > * Returns `true` when the collection originates from a `.vscode/mcp.json`
145 > * workspace-folder config, identified by its collection id prefix (the
146 > * shared `mcp.config.` prefix plus the workspace-folder config id).
147 > */
148 > export function isVscodeMcpJson(collection: McpCollectionDefinition): boolean {
149 return collection.id.startsWith(`${MCP_CONFIGURATION_COLLECTION_ID_PREFIX}${WORKSPACE_FOLDER_CONFIG_ID_PREFIX}`);
150 }
151 > } mcpTypes.ts
152 >
153 > export interface McpServerDefinition {
154 > /** Globally-unique, stable ID for this definition */
155 > readonly id: string;
156 > /** Human-readable label for the definition */
157 > readonly label: string;
158 > /** Descriptor defining how the configuration should be launched. */
159 > readonly launch: McpServerLaunch;
160 > /** Explicit roots. If undefined, all workspace folders. */
161 > readonly roots?: URI[] | undefined;
162 > /** If set, allows configuration variables to be resolved in the {@link launch} with the given context */
163 > readonly variableReplacement?: McpServerDefinitionVariableReplacement;
164 > /** Nonce used for caching the server. Changing the nonce will indicate that tools need to be refreshed. */
165 > readonly cacheNonce: string;
166 > /** Dev mode configuration for the server */
167 > readonly devMode?: IMcpDevModeConfig;
168 > /** Static description of server tools/data, used to hydrate the cache. */
169 > readonly staticMetadata?: McpServerStaticMetadata;
170 > /** Indicates if the sandbox is enabled for this server. */
171 > readonly sandboxEnabled?: boolean;
172 >
173 >
174 > readonly presentation?: {
175 > /** Sort order of the definition. */
176 > readonly order?: number;
177 > /** Place where this server is configured, used in workspace trust prompts and "show config" */
178 > readonly origin?: Location;
179 > };
180 > }
181 >
182 > export const enum McpServerStaticToolAvailability {
183 > /** Tool is expected to be present as soon as the server is started. */
184 > Initial,
185 > /** Tool may be present later. */
186 > Dynamic,
187 > }
188 >
189 > export interface McpServerStaticMetadata {
190 > tools?: { availability: McpServerStaticToolAvailability; definition: MCP.Tool }[];
191 > instructions?: string;
192 > capabilities?: MCP.ServerCapabilities;
193 > serverInfo?: MCP.Implementation;
194 > }
195 >
196 > export namespace McpServerDefinition {
197 > export interface Serialized {
198 > readonly id: string;
199 > readonly label: string;
200 > readonly cacheNonce: string;
201 > readonly launch: McpServerLaunch.Serialized;
202 > readonly variableReplacement?: McpServerDefinitionVariableReplacement.Serialized;
203 > readonly staticMetadata?: McpServerStaticMetadata;
204 > readonly sandboxEnabled?: boolean;
205 > }
206 >
207 > export function toSerialized(def: McpServerDefinition): McpServerDefinition.Serialized {
208 return def;
209 }
210 > mcpTypes.ts
211 > export function fromSerialized(def: McpServerDefinition.Serialized): McpServerDefinition {
212 return {
213 id: def.id,
220 };
221 }
222 > mcpTypes.ts
223 > export function equals(a: McpServerDefinition, b: McpServerDefinition): boolean {
224 return a.id === b.id
225 && a.label === b.label
233
234 }
235 > } mcpTypes.ts
236 >
237 >
238 > export interface McpServerDefinitionVariableReplacement {
239 > section?: string; // e.g. 'mcp'
240 > folder?: IWorkspaceFolderData;
241 > target: ConfigurationTarget;
242 > }
243 >
244 > export namespace McpServerDefinitionVariableReplacement {
245 > export interface Serialized {
246 > target: ConfigurationTarget;
247 > section?: string;
248 > folder?: { name: string; index: number; uri: UriComponents };
249 > }
250 >
251 > export function toSerialized(def: McpServerDefinitionVariableReplacement): McpServerDefinitionVariableReplacement.Serialized {
252 return def;
253 }
254 > mcpTypes.ts
255 > export function fromSerialized(def: McpServerDefinitionVariableReplacement.Serialized): McpServerDefinitionVariableReplacement {
256 return {
257 section: def.section,
260 };
261 }
262 > } mcpTypes.ts
263 >
264 > /** An observable of the auto-starting servers. When 'starting' is empty, the operation is complete. */
265 > export interface IAutostartResult {
266 > working: boolean;
267 > starting: McpDefinitionReference[];
268 > serversRequiringInteraction: Array<McpDefinitionReference & { errorMessage?: string }>;
269 > }
270 >
271 > export namespace IAutostartResult {
272 > export const Empty: IAutostartResult = { working: false, starting: [], serversRequiringInteraction: [] };
273 > }
274 >
275 > export interface IMcpService {
276 > _serviceBrand: undefined;
277 > readonly servers: IObservable<readonly IMcpServer[]>;
278 >
279 > /** The enablement model for MCP servers. */
280 > readonly enablementModel: IEnablementModel;
281 >
282 > /** Resets the cached tools. */
283 > resetCaches(): void;
284 >
285 > /** Resets trusted MCP servers. */
286 > resetTrust(): void;
287 >
288 > /** Set if there are extensions that register MCP servers that have never been activated. */
289 > readonly lazyCollectionState: IObservable<{ state: LazyCollectionState; collections: McpCollectionDefinition[] }>;
290 >
291 > /** Auto-starts pending servers based on user settings. */
292 > autostart(token?: CancellationToken): IObservable<IAutostartResult>;
293 >
294 > /** Cancels any current autostart @internal */
295 > cancelAutostart(): void;
296 >
297 > /** Activates extension-providing MCP servers that have not yet been discovered. */
298 > activateCollections(): Promise<void>;
299 > }
300 >
301 > export const enum LazyCollectionState {
302 > HasUnknown,
303 > LoadingUnknown,
304 > AllKnown,
305 > }
306 >
307 > export const IMcpService = createDecorator<IMcpService>('IMcpService');
308 >
309 > export interface McpCollectionReference {
310 > id: string;
311 > label: string;
312 > order: number;
313 > presentation?: McpCollectionDefinition['presentation'];
314 > }
315 >
316 > export interface McpDefinitionReference {
317 > id: string;
318 > label: string;
319 > }
320 >
321 > export class McpStartServerInteraction {
322 /** @internal */
323 public readonly participants = new ObservableMap</* server definition ID */ string, { s: 'unknown' | 'resolved' } | { s: 'waiting'; definition: McpServerDefinition; collection: McpCollectionDefinition }>();
324 > choice?: Promise<string[] | undefined>; mcpTypes.ts
325 > }
326 >
327 > export interface IMcpServerStartOpts {
328 > /**
329 > * Automatically trust if changed. This should ONLY be set for afforances that
330 > * ensure the user sees the config before it gets started (e.g. code lenses)
331 > */
332 > autoTrustChanges?: boolean;
333 > /**
334 > * When to trigger the trust prompt.
335 > * - only-new: only prompt for servers that are not previously explicitly untrusted (default)
336 > * - all-untrusted: prompt for all servers that are not trusted
337 > * - never: don't prompt, fail silently when trying to start an untrusted server
338 > */
339 > promptType?: 'only-new' | 'all-untrusted' | 'never';
340 > /** True if th servre should be launched with debugging. */
341 > debug?: boolean;
342 > /** Correlate multiple interactions such that any trust prompts are presented in combination. */
343 > interaction?: McpStartServerInteraction;
344 > /**
345 > * If true, throw an error if any user interaction would be required during startup.
346 > * This includes variable resolution, trust prompts, and authentication prompts.
347 > */
348 > errorOnUserInteraction?: boolean;
349 > }
350 >
351 > export namespace McpServerTrust {
352 > export const enum Kind {
353 > /** The server is trusted */
354 > Trusted,
355 > /** The server is trusted as long as its nonce matches */
356 > TrustedOnNonce,
357 > /** The server trust was denied. */
358 > Untrusted,
359 > /** The server is not yet trusted or untrusted. */
360 > Unknown,
361 > }
362 > }
363 >
364 > export interface IMcpServer extends IDisposable {
365 > readonly collection: McpCollectionReference;
366 > readonly definition: McpDefinitionReference;
367 > readonly enablement: IObservable<ContributionEnablementState>;
368 > readonly connection: IObservable<IMcpServerConnection | undefined>;
369 > readonly connectionState: IObservable<McpConnectionState>;
370 > readonly serverMetadata: IObservable<{
371 > serverName?: string;
372 > serverInstructions?: string;
373 > icons: IMcpIcons;
374 > } | undefined>;
375 >
376 > /**
377 > * Full definition as it exists in the MCP registry. Unlike the references
378 > * in `collection` and `definition`, this may change over time.
379 > */
380 > readDefinitions(): IObservable<{ server: McpServerDefinition | undefined; collection: McpCollectionDefinition | undefined }>;
381 >
382 > showOutput(preserveFocus?: boolean): Promise<void>;
383 > /**
384 > * Starts the server and returns its resulting state. One of:
385 > * - Running, if all good
386 > * - Error, if the server failed to start
387 > * - Stopped, if the server was disposed or the user cancelled the launch
388 > */
389 > start(opts?: IMcpServerStartOpts): Promise<McpConnectionState>;
390 > stop(): Promise<void>;
391 >
392 > readonly cacheState: IObservable<McpServerCacheState>;
393 > readonly tools: IObservable<readonly IMcpTool[]>;
394 > readonly prompts: IObservable<readonly IMcpPrompt[]>;
395 > readonly capabilities: IObservable<McpCapability | undefined>;
396 >
397 > /**
398 > * Lists all resources on the server.
399 > */
400 > resources(token?: CancellationToken): AsyncIterable<IMcpResource[]>;
401 >
402 > /**
403 > * List resource templates on the server.
404 > */
405 > resourceTemplates(token?: CancellationToken): Promise<IMcpResourceTemplate[]>;
406 > }
407 >
408 > /**
409 > * A representation of an MCP resource. The `uri` is namespaced to VS Code and
410 > * can be used in filesystem APIs.
411 > */
412 > export interface IMcpResource {
413 > /** Identifier for the file in VS Code and operable with filesystem API */
414 > readonly uri: URI;
415 > /** Identifier of the file as given from the MCP server. */
416 > readonly mcpUri: string;
417 > readonly name: string;
418 > readonly title?: string;
419 > readonly description?: string;
420 > readonly mimeType?: string;
421 > readonly sizeInBytes?: number;
422 > readonly icons: IMcpIcons;
423 > }
424 >
425 > export interface IMcpResourceTemplate {
426 > readonly name: string;
427 > readonly title?: string;
428 > readonly description?: string;
429 > readonly mimeType?: string;
430 > readonly template: UriTemplate;
431 > readonly icons: IMcpIcons;
432 >
433 > /** Gets string completions for the given template part. */
434 > complete(templatePart: string, prefix: string, alreadyResolved: Record<string, string | string[]>, token: CancellationToken): Promise<string[]>;
435 >
436 > /** Gets the resolved URI from template parts. */
437 > resolveURI(vars: Record<string, unknown>): URI;
438 > }
439 >
440 > export const isMcpResourceTemplate = (obj: IMcpResource | IMcpResourceTemplate): obj is IMcpResourceTemplate => {
441 return (obj as IMcpResourceTemplate).template !== undefined;
442 };
443 > export const isMcpResource = (obj: IMcpResource | IMcpResourceTemplate): obj is IMcpResource => { mcpTypes.ts
444 return (obj as IMcpResource).mcpUri !== undefined;
445 };
446 > mcpTypes.ts
447 > export const enum McpServerCacheState {
448 > /** Tools have not been read before */
449 > Unknown,
450 > /** Tools were read from the cache */
451 > Cached,
452 > /** Tools were read from the cache or live, but they may be outdated. */
453 > Outdated,
454 > /** Tools are refreshing for the first time */
455 > RefreshingFromUnknown,
456 > /** Tools are refreshing and the current tools are cached */
457 > RefreshingFromCached,
458 > /** Tool state is live, server is connected */
459 > Live,
460 > }
461 >
462 > export interface IMcpPrompt {
463 > readonly id: string;
464 > readonly name: string;
465 > readonly title?: string;
466 > readonly description?: string;
467 > readonly arguments: readonly MCP.PromptArgument[];
468 >
469 > /** Gets string completions for the given prompt part. */
470 > complete(argument: string, prefix: string, alreadyResolved: Record<string, string>, token: CancellationToken): Promise<string[]>;
471 >
472 > resolve(args: Record<string, string | undefined>, token?: CancellationToken): Promise<IMcpPromptMessage[]>;
473 > }
474 >
475 > export const mcpPromptReplaceSpecialChars = (s: string) => s.replace(/[^a-z0-9_.-]/gi, '_');
476 >
477 > export const mcpPromptPrefix = (definition: McpDefinitionReference) =>
478 `/mcp.` + mcpPromptReplaceSpecialChars(definition.label);
479 > mcpTypes.ts
480 > export interface IMcpPromptMessage extends MCP.PromptMessage { }
481 >
482 > export interface IMcpToolCallContext {
483 > chatSessionResource: URI | undefined;
484 > chatRequestId?: string;
485 > /**
486 > * Optional W3C trace context `traceparent` value to forward to the MCP server
487 > * via `_meta.traceparent` on the JSON-RPC `tools/call` request (MCP SEP-414).
488 > */
489 > traceparent?: string;
490 > /** Optional W3C trace context `tracestate` value paired with {@link traceparent}. */
491 > tracestate?: string;
492 > }
493 >
494 > /**
495 > * Visibility of an MCP tool, based on the MCP Apps `_meta.ui.visibility` field.
496 > * @see https://github.com/anthropics/mcp/blob/main/apps.md
497 > */
498 > export const enum McpToolVisibility {
499 > /** Tool is visible to and callable by the language model */
500 > Model = 1 << 0,
501 > /** Tool is callable by the MCP App UI */
502 > App = 1 << 1,
503 > }
504 >
505 > /**
506 > * Serializable data for MCP App UI rendering.
507 > * This contains all the information needed to render an MCP App webview.
508 > *
509 > * The transport for the App's sub-RPCs (`tools/call`, `resources/read`,
510 > * `sampling/createMessage`, …) is determined by the discriminator:
511 > *
512 > * - `local`: resolves the MCP server via {@link IMcpService} from
513 > * `serverDefinitionId` + `collectionId`. Used for locally-configured
514 > * MCP servers.
515 > * - `agentHost`: routes through {@link IAgentHostService.handleMcpRequest}
516 > * on the AHP `mcp://` side `channel`. Used for MCP servers owned by
517 > * an agent host.
518 > */
519 > export type IMcpToolCallUIData =
520 > | {
521 > readonly kind: 'local';
522 > /** URI of the UI resource for rendering (e.g., "ui://weather-server/dashboard") */
523 > readonly resourceUri: string;
524 > /** Reference to the server definition for reconnection */
525 > readonly serverDefinitionId: string;
526 > /** Reference to the collection containing the server */
527 > readonly collectionId: string;
528 > }
529 > | {
530 > readonly kind: 'agentHost';
531 > /** URI of the UI resource for rendering (e.g., "ui://weather-server/dashboard") */
532 > readonly resourceUri: string;
533 > /** AHP `mcp://` channel URI for the originating server. */
534 > readonly channel: string;
535 > /** Stable identifier for the originating server (used as webview origin key). */
536 > readonly serverId: string;
537 > };
538 >
539 > export interface IMcpTool {
540 >
541 > readonly id: string;
542 > /** Name for #referencing in chat */
543 > readonly referenceName: string;
544 > readonly icons: IMcpIcons;
545 > readonly definition: MCP.Tool;
546 > /** Visibility of the tool (Model, App, or both). Defaults to Model | App. */
547 > readonly visibility: McpToolVisibility;
548 > /** Optional UI resource URI for MCP App rendering */
549 > readonly uiResourceUri?: string;
550 >
551 > /**
552 > * Calls a tool
553 > * @throws {@link MpcResponseError} if the tool fails to execute
554 > * @throws {@link McpConnectionFailedError} if the connection to the server fails
555 > */
556 > call(params: Record<string, unknown>, context?: IMcpToolCallContext, token?: CancellationToken): Promise<MCP.CallToolResult>;
557 >
558 > /**
559 > * Identical to {@link call}, but reports progress.
560 > */
561 > callWithProgress(params: Record<string, unknown>, progress: ToolProgress, context?: IMcpToolCallContext, token?: CancellationToken): Promise<MCP.CallToolResult>;
562 > }
563 >
564 > export const enum McpServerTransportType {
565 > /** A command-line MCP server communicating over standard in/out */
566 > Stdio = 1 << 0,
567 > /** An MCP server that uses Server-Sent Events */
568 > HTTP = 1 << 1,
569 > }
570 >
571 > /**
572 > * MCP server launched on the command line which communicated over stdio.
573 > * https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/transports/#stdio
574 > */
575 > export interface McpServerTransportStdio {
576 > readonly type: McpServerTransportType.Stdio;
577 > readonly cwd: string | undefined;
578 > readonly command: string;
579 > readonly args: readonly string[];
580 > readonly env: Record<string, string | number | null>;
581 > readonly envFile: string | undefined;
582 > readonly sandbox: IMcpSandboxConfiguration | undefined;
583 > }
584 >
585 > export interface McpServerTransportHTTPAuthentication {
586 > /**
587 > * Authentication provider ID to use to get a session for the initial MCP server connection.
588 > */
589 > readonly providerId: string;
590 > /**
591 > * Scopes to use to get a session for the initial MCP server connection.
592 > */
593 > readonly scopes: string[];
594 > }
595 >
596 > export interface McpServerTransportHTTPOAuth {
597 > readonly clientId?: string;
598 > /**
599 > * (Preview) When true, the MCP server uses enterprise-managed authentication via the configured
600 > * SSO issuer (see `mcp.enterpriseManagedAuth.idp`). Tokens are obtained through OAuth Identity
601 > * Assertion Authorization Grant (ID-JAG) so that, after a one-time sign-in, subsequent enterprise-managed
602 > * servers connect silently.
603 > */
604 > readonly enterpriseManaged?: boolean;
605 > }
606 >
607 > /**
608 > * Returns the secret-storage key under which an MCP server OAuth client secret is stored.
609 > * Scoped by the MCP server URL AND the OAuth client_id so that two servers sharing the same
610 > * client_id string (e.g. against different authorization servers) cannot clobber each other's
611 > * secret, and so the key is stable across mcp.json configurations that happen to share a label
612 > * (e.g. user mcp.json vs. workspace mcp.json). Set by the "Set Client Secret" code lens in
613 > * mcp.json and read at authentication time so that client secrets are never stored in
614 > * plain-text config files.
615 > */
616 > export function mcpOAuthClientSecretStorageKey(mcpServerUrl: string, clientId: string): string {
617 return `mcp.oauth.clientSecret:${mcpServerUrl}:${clientId}`;
618 }
619 > mcpTypes.ts
620 > /**
621 > * MCP server launched on the command line which communicated over SSE or Streamable HTTP.
622 > * https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/transports/#http-with-sse
623 > * https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http
624 > */
625 > export interface McpServerTransportHTTP {
626 > readonly type: McpServerTransportType.HTTP;
627 > readonly uri: URI;
628 > readonly headers: [string, string][];
629 > readonly oauth?: McpServerTransportHTTPOAuth;
630 > /**
631 > * @deprecated this was originally used for step-auth auth but a different approach was used instead
632 > * so it's effectively dead code.
633 > */
634 > readonly authentication?: McpServerTransportHTTPAuthentication;
635 > }
636 >
637 > export type McpServerLaunch =
638 > | McpServerTransportStdio
639 > | McpServerTransportHTTP;
640 >
641 > export namespace McpServerLaunch {
642 > export type Serialized =
643 > | { type: McpServerTransportType.HTTP; uri: UriComponents; headers: [string, string][]; oauth?: McpServerTransportHTTPOAuth; authentication?: McpServerTransportHTTPAuthentication }
644 > | { type: McpServerTransportType.Stdio; cwd: string | undefined; command: string; args: readonly string[]; env: Record<string, string | number | null>; envFile: string | undefined; sandbox: IMcpSandboxConfiguration | undefined };
645 >
646 > export function toSerialized(launch: McpServerLaunch): McpServerLaunch.Serialized {
647 return launch;
648 }
649 > mcpTypes.ts
650 > export function fromSerialized(launch: McpServerLaunch.Serialized): McpServerLaunch {
651 switch (launch.type) {
652 case McpServerTransportType.HTTP:
664 }
665 }
666 > mcpTypes.ts
667 > export async function hash(launch: McpServerLaunch): Promise<string> {
668 const nonce = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(JSON.stringify(launch)));
669 return encodeHex(VSBuffer.wrap(new Uint8Array(nonce)));
670 }
671 > } mcpTypes.ts
672 >
673 > /**
674 > * An instance that manages a connection to an MCP server. It can be started,
675 > * stopped, and restarted. Once started and in a running state, it will
676 > * eventually build a {@link IMcpServerConnection.handler}.
677 > */
678 > export interface IMcpPotentialSandboxBlock {
679 > readonly kind: 'network' | 'filesystem';
680 > readonly message: string;
681 > readonly host?: string;
682 > readonly path?: string;
683 > }
684 >
685 > export interface IMcpServerConnection extends IDisposable {
686 > readonly definition: McpServerDefinition;
687 > readonly state: IObservable<McpConnectionState>;
688 > readonly handler: IObservable<McpServerRequestHandler | undefined>;
689 > readonly onPotentialSandboxBlock: Event<IMcpPotentialSandboxBlock>;
690 >
691 > /**
692 > * Resolved launch definition. Might not match the `definition.launch` due to
693 > * resolution logic in extension-provided MCPs.
694 > */
695 > readonly launchDefinition: McpServerLaunch;
696 >
697 > /**
698 > * Starts the server if it's stopped. Returns a promise that resolves once
699 > * server exits a 'starting' state.
700 > */
701 > start(methods: IMcpClientMethods): Promise<McpConnectionState>;
702 >
703 > /**
704 > * Stops the server.
705 > */
706 > stop(): Promise<void>;
707 > }
708 >
709 > /** Client methods whose implementations are passed through the server connection. */
710 > export interface IMcpClientMethods {
711 > /** Handler for `sampling/createMessage` */
712 > createMessageRequestHandler?(req: MCP.CreateMessageRequest['params'], token?: CancellationToken): Promise<MCP.CreateMessageResult>;
713 > /** Handler for `elicitation/create` */
714 > elicitationRequestHandler?(req: MCP.ElicitRequest['params'], token?: CancellationToken): Promise<MCP.ElicitResult>;
715 > }
716 >
717 > /**
718 > * McpConnectionState is the state of the underlying connection and is
719 > * communicated e.g. from the extension host to the renderer.
720 > */
721 > export namespace McpConnectionState {
722 > export const enum Kind {
723 > Stopped,
724 > Starting,
725 > Running,
726 > Error,
727 > }
728 >
729 > export const toString = (s: McpConnectionState): string => {
730 switch (s.state) {
731 case Kind.Stopped:
741 }
742 };
743 > mcpTypes.ts
744 > export const toKindString = (s: McpConnectionState.Kind): string => {
745 switch (s) {
746 case Kind.Stopped:
756 }
757 };
758 > mcpTypes.ts
759 > /** Returns if the MCP state is one where starting a new server is valid */
760 > export const canBeStarted = (s: Kind) => s === Kind.Error || s === Kind.Stopped;
761 >
762 > /** Gets whether the state is a running state. */
763 > export const isRunning = (s: McpConnectionState) => !canBeStarted(s.state);
764 >
765 > export interface Stopped {
766 > readonly state: Kind.Stopped;
767 > readonly reason?: 'needs-user-interaction';
768 > }
769 >
770 > export interface Starting {
771 > readonly state: Kind.Starting;
772 > }
773 >
774 > export interface Running {
775 > readonly state: Kind.Running;
776 > }
777 >
778 > export interface Error {
779 > readonly state: Kind.Error;
780 > readonly code?: string;
781 > readonly shouldRetry?: boolean;
782 > readonly message: string;
783 > }
784 > }
785 >
786 > export type McpConnectionState =
787 > | McpConnectionState.Stopped
788 > | McpConnectionState.Starting
789 > | McpConnectionState.Running
790 > | McpConnectionState.Error;
791 >
792 > export class MpcResponseError extends Error {
793 > constructor(message: string, public readonly code: number, public readonly data: unknown) {
794 super(`MPC ${code}: ${message}`);
795 }
796 > } mcpTypes.ts
797 >
798 > export class McpConnectionFailedError extends Error { }
799 >
800 > export class UserInteractionRequiredError extends Error {
801 > private static readonly prefix = 'User interaction required: ';
802 >
803 > public static is(error: Error): boolean {
804 return error.message.startsWith(this.prefix);
805 }
806 > mcpTypes.ts
807 > constructor(public readonly reason: string) {
808 super(`${UserInteractionRequiredError.prefix}${reason}`);
809 }
810 > } mcpTypes.ts
811 >
812 > export interface IMcpConfigPath {
813 > id: string;
814 > key: 'userLocalValue' | 'userRemoteValue' | 'workspaceValue' | 'workspaceFolderValue';
815 > label: string;
816 > scope: StorageScope;
817 > target: ConfigurationTarget;
818 > order: number;
819 > remoteAuthority?: string;
820 > uri: URI | undefined;
821 > section?: string[];
822 > workspaceFolder?: IWorkspaceFolder;
823 > }
824 >
825 > export interface IMcpServerContainer extends IDisposable {
826 > mcpServer: IWorkbenchMcpServer | null;
827 > update(): void;
828 > }
829 >
830 > export interface IMcpServerEditorOptions extends IEditorOptions {
831 > tab?: McpServerEditorTab;
832 > sideByside?: boolean;
833 > }
834 >
835 > export const enum McpServerEnablementState {
836 > Disabled,
837 > DisabledByAccess,
838 > DisabledProfile,
839 > DisabledWorkspace,
840 > Enabled,
841 > }
842 >
843 > export const enum McpServerInstallState {
844 > Installing,
845 > Installed,
846 > Uninstalling,
847 > Uninstalled
848 > }
849 >
850 > export const enum McpServerEditorTab {
851 > Readme = 'readme',
852 > Manifest = 'manifest',
853 > Configuration = 'configuration',
854 > }
855 >
856 > export type McpServerEnablementStatus = {
857 > readonly state: McpServerEnablementState;
858 > readonly message?: {
859 > readonly severity: Severity;
860 > readonly text: IMarkdownString;
861 > };
862 > };
863 >
864 > export interface IWorkbenchMcpServer {
865 > readonly gallery: IGalleryMcpServer | undefined;
866 > readonly local: IWorkbenchLocalMcpServer | undefined;
867 > readonly installable: IInstallableMcpServer | undefined;
868 > readonly installState: McpServerInstallState;
869 > readonly runtimeStatus: McpServerEnablementStatus | undefined;
870 > readonly id: string;
871 > readonly name: string;
872 > readonly label: string;
873 > readonly description: string;
874 > readonly icon?: {
875 > readonly dark: string;
876 > readonly light: string;
877 > };
878 > readonly codicon?: string;
879 > readonly publisherUrl?: string;
880 > readonly publisherDisplayName?: string;
881 > readonly starsCount?: number;
882 > readonly license?: string;
883 > readonly repository?: string;
884 > readonly config?: IMcpServerConfiguration | undefined;
885 > readonly readmeUrl?: URI;
886 > getReadme(token: CancellationToken): Promise<string>;
887 > getManifest(token: CancellationToken): Promise<IGalleryMcpServerConfiguration>;
888 > }
889 >
890 > export const IMcpWorkbenchService = createDecorator<IMcpWorkbenchService>('IMcpWorkbenchService');
891 > export interface IMcpWorkbenchService {
892 > readonly _serviceBrand: undefined;
893 > readonly onChange: Event<IWorkbenchMcpServer | undefined>;
894 > readonly onReset: Event<void>;
895 > readonly local: readonly IWorkbenchMcpServer[];
896 > getEnabledLocalMcpServers(): IWorkbenchLocalMcpServer[];
897 > queryLocal(): Promise<IWorkbenchMcpServer[]>;
898 > queryGallery(options?: IQueryOptions, token?: CancellationToken): Promise<IIterativePager<IWorkbenchMcpServer>>;
899 > canInstall(mcpServer: IWorkbenchMcpServer): true | IMarkdownString;
900 > install(server: IWorkbenchMcpServer, installOptions?: IWorkbencMcpServerInstallOptions): Promise<IWorkbenchMcpServer>;
901 > uninstall(mcpServer: IWorkbenchMcpServer): Promise<void>;
902 > getMcpConfigPath(arg: IWorkbenchLocalMcpServer): IMcpConfigPath | undefined;
903 > getMcpConfigPath(arg: URI): Promise<IMcpConfigPath | undefined>;
904 > openSearch(searchValue: string, preserveFocus?: boolean): Promise<void>;
905 > open(extension: IWorkbenchMcpServer | string, options?: IMcpServerEditorOptions): Promise<void>;
906 > }
907 >
908 > export class McpServerContainers extends Disposable {
909 > constructor(
910 private readonly containers: IMcpServerContainer[],
911 @IMcpWorkbenchService mcpWorkbenchService: IMcpWorkbenchService
914 this._register(mcpWorkbenchService.onChange(this.update, this));
915 }
916 > mcpTypes.ts
917 > set mcpServer(extension: IWorkbenchMcpServer | null) {
918 this.containers.forEach(c => c.mcpServer = extension);
919 }
920 > mcpTypes.ts
921 > update(server: IWorkbenchMcpServer | undefined): void {
922 for (const container of this.containers) {
923 if (server && container.mcpServer) {
930 }
931 }
932 > } mcpTypes.ts
933 >
934 > export const McpServersGalleryStatusContext = new RawContextKey<string>('mcpServersGalleryStatus', McpGalleryManifestStatus.Unavailable);
935 > export const HasInstalledMcpServersContext = new RawContextKey<boolean>('hasInstalledMcpServers', true);
936 > export const InstalledMcpServersViewId = 'workbench.views.mcp.installed';
937 >
938 > export namespace McpResourceURI {
939 > export const scheme = 'mcp-resource';
940 >
941 > // Random placeholder for empty authorities, otherwise they're represente as
942 > // `scheme//path/here` in the URI which would get normalized to `scheme/path/here`.
943 > const emptyAuthorityPlaceholder = 'dylo78gyp'; // chosen by a fair dice roll. Guaranteed to be random.
944 >
945 > export function fromServer(def: McpDefinitionReference, resourceURI: URI | string): URI {
946 if (typeof resourceURI === 'string') {
947 resourceURI = URI.parse(resourceURI);
953 });
954 }
955 > mcpTypes.ts
956 > export function toServer(uri: URI | string): { definitionId: string; resourceURL: URL } {
957 if (typeof uri === 'string') {
958 uri = URI.parse(uri);
978 };
979 }
980 > mcpTypes.ts
981 > }
982 >
983 > /** Warning: this enum is cached in `mcpServer.ts` and all changes MUST only be additive. */
984 > export const enum McpCapability {
985 > Logging = 1 << 0,
986 > Completions = 1 << 1,
987 > Prompts = 1 << 2,
988 > PromptsListChanged = 1 << 3,
989 > Resources = 1 << 4,
990 > ResourcesSubscribe = 1 << 5,
991 > ResourcesListChanged = 1 << 6,
992 > Tools = 1 << 7,
993 > ToolsListChanged = 1 << 8,
994 > }
995 >
996 > export interface ISamplingOptions {
997 > server: IMcpServer;
998 > isDuringToolCall: boolean;
999 > params: MCP.CreateMessageRequest['params'];
1000 > }
1001 >
1002 > export interface ISamplingResult {
1003 > sample: MCP.CreateMessageResult;
1004 > }
1005 >
1006 > export interface IMcpSamplingService {
1007 > _serviceBrand: undefined;
1008 >
1009 > sample(opts: ISamplingOptions, token?: CancellationToken): Promise<ISamplingResult>;
1010 >
1011 > /** Whether MCP sampling logs are available for this server */
1012 > hasLogs(server: IMcpServer): boolean;
1013 > /** Gets a text report of the MCP server's sampling usage */
1014 > getLogText(server: IMcpServer): string;
1015 >
1016 > getConfig(server: IMcpServer): IMcpServerSamplingConfiguration;
1017 > updateConfig(server: IMcpServer, mutate: (r: IMcpServerSamplingConfiguration) => unknown): Promise<IMcpServerSamplingConfiguration>;
1018 > }
1019 >
1020 > export const IMcpSamplingService = createDecorator<IMcpSamplingService>('IMcpServerSampling');
1021 >
1022 > export class McpError extends Error {
1023 > public static methodNotFound(method: string) {
1024 > return new McpError(MCP.METHOD_NOT_FOUND, `Method not found: ${method}`);
1025 > }
1026 >
1027 > public static notAllowed() {
1028 return new McpError(-32000, 'The user has denied permission to call this method.');
1029 }
1030 > mcpTypes.ts
1031 > public static unknown(e: Error) {
1032 const mcpError = new McpError(MCP.INTERNAL_ERROR, `Unknown error: ${e.stack}`);
1033 mcpError.cause = e;
1034 return mcpError;
1035 }
1036 > mcpTypes.ts
1037 > constructor(
1038 public readonly code: number,
1039 message: string,
1042 super(message);
1043 }
1044 > } mcpTypes.ts
1045 >
1046 > export const enum McpToolName {
1047 > Prefix = 'mcp_',
1048 > MaxPrefixLen = 18,
1049 > MaxLength = 64,
1050 > }
1051 >
1052 >
1053 > export interface IMcpElicitationService {
1054 > _serviceBrand: undefined;
1055 >
1056 > /**
1057 > * Elicits a response from the user. The `context` is optional and can be used
1058 > * to provide additional information about the request.
1059 > *
1060 > * @param context Context for the elicitation, e.g. chat session ID.
1061 > * @param elicitation Request to elicit a response.
1062 > * @returns A promise that resolves to an {@link ElicitationResult}.
1063 > */
1064 > elicit(server: IMcpServer, context: IMcpToolCallContext | undefined, elicitation: MCP.ElicitRequest['params'], token: CancellationToken): Promise<ElicitResult>;
1065 > }
1066 >
1067 > export const enum ElicitationKind {
1068 > Form,
1069 > URL,
1070 > }
1071 >
1072 > export interface IUrlModeElicitResult extends IDisposable {
1073 > kind: ElicitationKind.URL;
1074 > value: MCP.ElicitResult;
1075 > /**
1076 > * Waits until the server tells us the elicitation is completed before resolving.
1077 > * Rejects with a CancellationError if the server stops before elicitation is
1078 > * complete, or if the token is cancelled.
1079 > */
1080 > wait: Promise<void>;
1081 > }
1082 >
1083 > export interface IFormModeElicitResult extends IDisposable {
1084 > kind: ElicitationKind.Form;
1085 > value: MCP.ElicitResult;
1086 > }
1087 >
1088 > export type ElicitResult = IUrlModeElicitResult | IFormModeElicitResult;
1089 >
1090 > export const IMcpElicitationService = createDecorator<IMcpElicitationService>('IMcpElicitationService');
1091 >
1092 > export const McpToolResourceLinkMimeType = 'application/vnd.code.resource-link';
1093 >
1094 > export interface IMcpToolResourceLinkContents {
1095 > uri: UriComponents;
1096 > underlyingMimeType?: string;
1097 > }
1098 >
1099 > export interface IMcpIcons {
1100 > /** Gets the image URI appropriate to the approximate display size */
1101 > getUrl(size: number): { dark: URI; light?: URI } | undefined;
1102 > }
src/vs/workbench/contrib/notebook/common/notebookCommon.ts 925 covered LOC · 26 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- notebookCommon.ts
2 > * Copyright (c) Microsoft 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 { IDiffResult } from '../../../../base/common/diff/diff.js';
9 > import { Event } from '../../../../base/common/event.js';
10 > import * as glob from '../../../../base/common/glob.js';
11 > import { IMarkdownString } from '../../../../base/common/htmlContent.js';
12 > import { Iterable } from '../../../../base/common/iterator.js';
13 > import { IDisposable } from '../../../../base/common/lifecycle.js';
14 > import { Mimes } from '../../../../base/common/mime.js';
15 > import { Schemas } from '../../../../base/common/network.js';
16 > import { basename } from '../../../../base/common/path.js';
17 > import { isWindows } from '../../../../base/common/platform.js';
18 > import { ISplice } from '../../../../base/common/sequence.js';
19 > import { ThemeColor } from '../../../../base/common/themables.js';
20 > import { URI, UriComponents } from '../../../../base/common/uri.js';
21 > import { Range } from '../../../../editor/common/core/range.js';
22 > import * as editorCommon from '../../../../editor/common/editorCommon.js';
23 > import { Command, WorkspaceEditMetadata } from '../../../../editor/common/languages.js';
24 > import { IReadonlyTextBuffer, ITextModel } from '../../../../editor/common/model.js';
25 > import { IAccessibilityInformation } from '../../../../platform/accessibility/common/accessibility.js';
26 > import { RawContextKey } from '../../../../platform/contextkey/common/contextkey.js';
27 > import { ExtensionIdentifier } from '../../../../platform/extensions/common/extensions.js';
28 > import { IFileReadLimits } from '../../../../platform/files/common/files.js';
29 > import { UndoRedoGroup } from '../../../../platform/undoRedo/common/undoRedo.js';
30 > import { IRevertOptions, ISaveOptions, IUntypedEditorInput } from '../../../common/editor.js';
31 > import { NotebookTextModel } from './model/notebookTextModel.js';
32 > import { ICellExecutionError } from './notebookExecutionStateService.js';
33 > import { INotebookTextModelLike } from './notebookKernelService.js';
34 > import { ICellRange } from './notebookRange.js';
35 > import { RegisteredEditorPriority } from '../../../services/editor/common/editorResolverService.js';
36 > import { generateMetadataUri, generate as generateUri, extractCellOutputDetails, parseMetadataUri, parse as parseUri } from '../../../services/notebook/common/notebookDocumentService.js';
37 > import { IWorkingCopyBackupMeta, IWorkingCopySaveEvent } from '../../../services/workingCopy/common/workingCopy.js';
38 > import { SnapshotContext } from '../../../services/workingCopy/common/fileWorkingCopy.js';
39 >
40 > export const NOTEBOOK_EDITOR_ID = 'workbench.editor.notebook';
41 > export const NOTEBOOK_DIFF_EDITOR_ID = 'workbench.editor.notebookTextDiffEditor';
42 > export const NOTEBOOK_MULTI_DIFF_EDITOR_ID = 'workbench.editor.notebookMultiTextDiffEditor';
43 > export const INTERACTIVE_WINDOW_EDITOR_ID = 'workbench.editor.interactive';
44 > export const REPL_EDITOR_ID = 'workbench.editor.repl';
45 > export const NOTEBOOK_OUTPUT_EDITOR_ID = 'workbench.editor.notebookOutputEditor';
46 >
47 > export const EXECUTE_REPL_COMMAND_ID = 'replNotebook.input.execute';
48 >
49 > export enum CellKind {
50 > Markup = 1,
51 > Code = 2
52 > }
53 >
54 > export const NOTEBOOK_DISPLAY_ORDER: readonly string[] = [
55 > 'application/json',
56 > 'application/javascript',
57 > 'text/html',
58 > 'image/svg+xml',
59 > Mimes.latex,
60 > Mimes.markdown,
61 > 'image/png',
62 > 'image/jpeg',
63 > Mimes.text
64 > ];
65 >
66 > export const ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER: readonly string[] = [
67 > Mimes.latex,
68 > Mimes.markdown,
69 > 'application/json',
70 > 'text/html',
71 > 'image/svg+xml',
72 > 'image/png',
73 > 'image/jpeg',
74 > Mimes.text,
75 > ];
76 >
77 > /**
78 > * A mapping of extension IDs who contain renderers, to notebook ids who they
79 > * should be treated as the same in the renderer selection logic. This is used
80 > * to prefer the 1st party Jupyter renderers even though they're in a separate
81 > * extension, for instance. See #136247.
82 > */
83 > export const RENDERER_EQUIVALENT_EXTENSIONS: ReadonlyMap<string, ReadonlySet<string>> = new Map([
84 > ['ms-toolsai.jupyter', new Set(['jupyter-notebook', 'interactive'])],
85 > ['ms-toolsai.jupyter-renderers', new Set(['jupyter-notebook', 'interactive'])],
86 > ]);
87 >
88 > export const RENDERER_NOT_AVAILABLE = '_notAvailable';
89 >
90 > export type ContributedNotebookRendererEntrypoint = string | { readonly extends: string; readonly path: string };
91 >
92 > export enum NotebookRunState {
93 > Running = 1,
94 > Idle = 2
95 > }
96 >
97 > export type NotebookDocumentMetadata = Record<string, unknown>;
98 >
99 > export enum NotebookCellExecutionState {
100 > Unconfirmed = 1,
101 > Pending = 2,
102 > Executing = 3
103 > }
104 > export enum NotebookExecutionState {
105 > Unconfirmed = 1,
106 > Pending = 2,
107 > Executing = 3
108 > }
109 >
110 > export interface INotebookCellPreviousExecutionResult {
111 > executionOrder?: number;
112 > success?: boolean;
113 > duration?: number;
114 > }
115 >
116 > export interface NotebookCellMetadata {
117 > /**
118 > * custom metadata
119 > */
120 > [key: string]: unknown;
121 > }
122 >
123 > export interface NotebookCellInternalMetadata {
124 > /**
125 > * Used only for diffing of Notebooks.
126 > * This is not persisted and generally useful only when diffing two notebooks.
127 > * Useful only after we've manually matched a few cells together so we know which cells are matching.
128 > */
129 > internalId?: string;
130 > executionId?: string;
131 > executionOrder?: number;
132 > lastRunSuccess?: boolean;
133 > runStartTime?: number;
134 > runStartTimeAdjustment?: number;
135 > runEndTime?: number;
136 > renderDuration?: { [key: string]: number };
137 > error?: ICellExecutionError;
138 > }
139 >
140 > export interface NotebookCellCollapseState {
141 > inputCollapsed?: boolean;
142 > outputCollapsed?: boolean;
143 > }
144 >
145 > export interface NotebookCellDefaultCollapseConfig {
146 > codeCell?: NotebookCellCollapseState;
147 > markupCell?: NotebookCellCollapseState;
148 > }
149 >
150 > export type InteractiveWindowCollapseCodeCells = 'always' | 'never' | 'fromEditor';
151 >
152 > export type TransientCellMetadata = { readonly [K in keyof NotebookCellMetadata]?: boolean };
153 > export type CellContentMetadata = { readonly [K in keyof NotebookCellMetadata]?: boolean };
154 > export type TransientDocumentMetadata = { readonly [K in keyof NotebookDocumentMetadata]?: boolean };
155 >
156 > export interface TransientOptions {
157 > readonly transientOutputs: boolean;
158 > readonly transientCellMetadata: TransientCellMetadata;
159 > readonly transientDocumentMetadata: TransientDocumentMetadata;
160 > readonly cellContentMetadata: CellContentMetadata;
161 > }
162 >
163 > /** Note: enum values are used for sorting */
164 > export const enum NotebookRendererMatch {
165 > /** Renderer has a hard dependency on an available kernel */
166 > WithHardKernelDependency = 0,
167 > /** Renderer works better with an available kernel */
168 > WithOptionalKernelDependency = 1,
169 > /** Renderer is kernel-agnostic */
170 > Pure = 2,
171 > /** Renderer is for a different mimeType or has a hard dependency which is unsatisfied */
172 > Never = 3,
173 > }
174 >
175 > /**
176 > * Renderer messaging requirement. While this allows for 'optional' messaging,
177 > * VS Code effectively treats it the same as true right now. "Partial
178 > * activation" of extensions is a very tricky problem, which could allow
179 > * solving this. But for now, optional is mostly only honored for aznb.
180 > */
181 > export const enum RendererMessagingSpec {
182 > Always = 'always',
183 > Never = 'never',
184 > Optional = 'optional',
185 > }
186 >
187 > export type NotebookRendererEntrypoint = { readonly extends: string | undefined; readonly path: URI };
188 >
189 > export interface INotebookRendererInfo {
190 > readonly id: string;
191 > readonly displayName: string;
192 > readonly entrypoint: NotebookRendererEntrypoint;
193 > readonly extensionLocation: URI;
194 > readonly extensionId: ExtensionIdentifier;
195 > readonly messaging: RendererMessagingSpec;
196 >
197 > readonly mimeTypes: readonly string[];
198 >
199 > readonly isBuiltin: boolean;
200 >
201 > matchesWithoutKernel(mimeType: string): NotebookRendererMatch;
202 > matches(mimeType: string, kernelProvides: ReadonlyArray<string>): NotebookRendererMatch;
203 > }
204 >
205 > export interface INotebookStaticPreloadInfo {
206 > readonly type: string;
207 > readonly entrypoint: URI;
208 > readonly extensionLocation: URI;
209 > readonly localResourceRoots: readonly URI[];
210 > }
211 >
212 > export interface IOrderedMimeType {
213 > mimeType: string;
214 > rendererId: string;
215 > isTrusted: boolean;
216 > }
217 >
218 > export interface IOutputItemDto {
219 > readonly mime: string;
220 > readonly data: VSBuffer;
221 > }
222 >
223 > export interface IOutputDto {
224 > outputs: IOutputItemDto[];
225 > outputId: string;
226 > metadata?: Record<string, any>;
227 > }
228 >
229 > export interface ICellOutput {
230 > readonly versionId: number;
231 > outputs: IOutputItemDto[];
232 > metadata?: Record<string, any>;
233 > outputId: string;
234 > /**
235 > * Alternative output id that's reused when the output is updated.
236 > */
237 > alternativeOutputId: string;
238 > readonly onDidChangeData: Event<void>;
239 > replaceData(items: IOutputDto): void;
240 > appendData(items: IOutputItemDto[]): void;
241 > appendedSinceVersion(versionId: number, mime: string): VSBuffer | undefined;
242 > asDto(): IOutputDto;
243 > bumpVersion(): void;
244 > dispose(): void;
245 > }
246 >
247 > export interface CellInternalMetadataChangedEvent {
248 > readonly lastRunSuccessChanged?: boolean;
249 > }
250 >
251 > export interface INotebookDocumentMetadataTextModel {
252 > /**
253 > * Notebook Metadata Uri.
254 > */
255 > readonly uri: URI;
256 > /**
257 > * Triggered when the Notebook Metadata changes.
258 > */
259 > readonly onDidChange: Event<void>;
260 > readonly metadata: Readonly<NotebookDocumentMetadata>;
261 > readonly textBuffer: IReadonlyTextBuffer;
262 > /**
263 > * Text representation of the Notebook Metadata
264 > */
265 > getValue(): string;
266 > getHash(): string;
267 > }
268 >
269 > export interface ICell {
270 > readonly uri: URI;
271 > handle: number;
272 > language: string;
273 > cellKind: CellKind;
274 > outputs: ICellOutput[];
275 > metadata: NotebookCellMetadata;
276 > internalMetadata: NotebookCellInternalMetadata;
277 > getHashValue(): number;
278 > textBuffer: IReadonlyTextBuffer;
279 > textModel?: ITextModel;
280 > readonly onDidChangeTextModel: Event<void>;
281 > getValue(): string;
282 > readonly onDidChangeOutputs?: Event<NotebookCellOutputsSplice>;
283 > readonly onDidChangeOutputItems?: Event<void>;
284 > readonly onDidChangeLanguage: Event<string>;
285 > readonly onDidChangeMetadata: Event<void>;
286 > readonly onDidChangeInternalMetadata: Event<CellInternalMetadataChangedEvent>;
287 > }
288 >
289 > export interface INotebookSnapshotOptions {
290 > context: SnapshotContext;
291 > outputSizeLimit: number;
292 > transientOptions?: TransientOptions;
293 > }
294 >
295 > export interface INotebookTextModel extends INotebookTextModelLike, IDisposable {
296 > readonly notebookType: string;
297 > readonly viewType: string;
298 > metadata: NotebookDocumentMetadata;
299 > readonly transientOptions: TransientOptions;
300 > readonly uri: URI;
301 > readonly versionId: number;
302 > readonly length: number;
303 > readonly cells: readonly ICell[];
304 > reset(cells: ICellDto2[], metadata: NotebookDocumentMetadata, transientOptions: TransientOptions): void;
305 > createSnapshot(options: INotebookSnapshotOptions): NotebookData;
306 > restoreSnapshot(snapshot: NotebookData, transientOptions?: TransientOptions): void;
307 > applyEdits(rawEdits: ICellEditOperation[], synchronous: boolean, beginSelectionState: ISelectionState | undefined, endSelectionsComputer: () => ISelectionState | undefined, undoRedoGroup: UndoRedoGroup | undefined, computeUndoRedo?: boolean): boolean;
308 > readonly onDidChangeContent: Event<NotebookTextModelChangedEvent>;
309 > readonly onWillDispose: Event<void>;
310 > }
311 >
312 > export type NotebookCellTextModelSplice<T> = [
313 > start: number,
314 > deleteCount: number,
315 > newItems: T[]
316 > ];
317 >
318 > export type NotebookCellOutputsSplice = {
319 > start: number /* start */;
320 > deleteCount: number /* delete count */;
321 > newOutputs: ICellOutput[];
322 > };
323 >
324 > export interface IMainCellDto {
325 > handle: number;
326 > url: string;
327 > source: string[];
328 > eol: string;
329 > versionId: number;
330 > language: string;
331 > cellKind: CellKind;
332 > outputs: IOutputDto[];
333 > metadata?: NotebookCellMetadata;
334 > internalMetadata?: NotebookCellInternalMetadata;
335 > }
336 >
337 > export enum NotebookCellsChangeType {
338 > ModelChange = 1,
339 > Move = 2,
340 > ChangeCellLanguage = 5,
341 > Initialize = 6,
342 > ChangeCellMetadata = 7,
343 > Output = 8,
344 > OutputItem = 9,
345 > ChangeCellContent = 10,
346 > ChangeDocumentMetadata = 11,
347 > ChangeCellInternalMetadata = 12,
348 > ChangeCellMime = 13,
349 > Unknown = 100
350 > }
351 >
352 > export interface NotebookCellsInitializeEvent<T> {
353 > readonly kind: NotebookCellsChangeType.Initialize;
354 > readonly changes: NotebookCellTextModelSplice<T>[];
355 > }
356 >
357 > export interface NotebookCellContentChangeEvent {
358 > readonly kind: NotebookCellsChangeType.ChangeCellContent;
359 > readonly index: number;
360 > }
361 >
362 > export interface NotebookCellsModelChangedEvent<T> {
363 > readonly kind: NotebookCellsChangeType.ModelChange;
364 > readonly changes: NotebookCellTextModelSplice<T>[];
365 > }
366 >
367 > export interface NotebookCellsModelMoveEvent<T> {
368 > readonly kind: NotebookCellsChangeType.Move;
369 > readonly index: number;
370 > readonly length: number;
371 > readonly newIdx: number;
372 > readonly cells: T[];
373 > }
374 >
375 > export interface NotebookOutputChangedEvent {
376 > readonly kind: NotebookCellsChangeType.Output;
377 > readonly index: number;
378 > readonly outputs: IOutputDto[];
379 > readonly append: boolean;
380 > }
381 >
382 > export interface NotebookOutputItemChangedEvent {
383 > readonly kind: NotebookCellsChangeType.OutputItem;
384 > readonly index: number;
385 > readonly outputId: string;
386 > readonly outputItems: IOutputItemDto[];
387 > readonly append: boolean;
388 > }
389 >
390 > export interface NotebookCellsChangeLanguageEvent {
391 > readonly kind: NotebookCellsChangeType.ChangeCellLanguage;
392 > readonly index: number;
393 > readonly language: string;
394 > }
395 >
396 > export interface NotebookCellsChangeMimeEvent {
397 > readonly kind: NotebookCellsChangeType.ChangeCellMime;
398 > readonly index: number;
399 > readonly mime: string | undefined;
400 > }
401 >
402 > export interface NotebookCellsChangeMetadataEvent {
403 > readonly kind: NotebookCellsChangeType.ChangeCellMetadata;
404 > readonly index: number;
405 > readonly metadata: NotebookCellMetadata;
406 > }
407 >
408 > export interface NotebookCellsChangeInternalMetadataEvent {
409 > readonly kind: NotebookCellsChangeType.ChangeCellInternalMetadata;
410 > readonly index: number;
411 > readonly internalMetadata: NotebookCellInternalMetadata;
412 > }
413 >
414 > export interface NotebookDocumentChangeMetadataEvent {
415 > readonly kind: NotebookCellsChangeType.ChangeDocumentMetadata;
416 > readonly metadata: NotebookDocumentMetadata;
417 > }
418 >
419 > export interface NotebookDocumentUnknownChangeEvent {
420 > readonly kind: NotebookCellsChangeType.Unknown;
421 > }
422 >
423 > export type NotebookRawContentEventDto = NotebookCellsInitializeEvent<IMainCellDto> | NotebookDocumentChangeMetadataEvent | NotebookCellContentChangeEvent | NotebookCellsModelChangedEvent<IMainCellDto> | NotebookCellsModelMoveEvent<IMainCellDto> | NotebookOutputChangedEvent | NotebookOutputItemChangedEvent | NotebookCellsChangeLanguageEvent | NotebookCellsChangeMimeEvent | NotebookCellsChangeMetadataEvent | NotebookCellsChangeInternalMetadataEvent | NotebookDocumentUnknownChangeEvent;
424 >
425 > export type NotebookCellsChangedEventDto = {
426 > readonly rawEvents: NotebookRawContentEventDto[];
427 > readonly versionId: number;
428 > };
429 >
430 > export type NotebookRawContentEvent = (NotebookCellsInitializeEvent<ICell> | NotebookDocumentChangeMetadataEvent | NotebookCellContentChangeEvent | NotebookCellsModelChangedEvent<ICell> | NotebookCellsModelMoveEvent<ICell> | NotebookOutputChangedEvent | NotebookOutputItemChangedEvent | NotebookCellsChangeLanguageEvent | NotebookCellsChangeMimeEvent | NotebookCellsChangeMetadataEvent | NotebookCellsChangeInternalMetadataEvent | NotebookDocumentUnknownChangeEvent) & { transient: boolean };
431 >
432 > export enum SelectionStateType {
433 > Handle = 0,
434 > Index = 1
435 > }
436 >
437 > export interface ISelectionHandleState {
438 > kind: SelectionStateType.Handle;
439 > primary: number | null;
440 > selections: number[];
441 > }
442 >
443 > export interface ISelectionIndexState {
444 > kind: SelectionStateType.Index;
445 > focus: ICellRange;
446 > selections: ICellRange[];
447 > }
448 >
449 > export type ISelectionState = ISelectionHandleState | ISelectionIndexState;
450 >
451 > export type NotebookTextModelChangedEvent = {
452 > readonly rawEvents: NotebookRawContentEvent[];
453 > readonly versionId: number;
454 > readonly synchronous: boolean | undefined;
455 > readonly endSelectionState: ISelectionState | undefined;
456 > };
457 >
458 > export type NotebookTextModelWillAddRemoveEvent = {
459 > readonly rawEvent: NotebookCellsModelChangedEvent<ICell>;
460 > };
461 >
462 > export const enum CellEditType {
463 > Replace = 1,
464 > Output = 2,
465 > Metadata = 3,
466 > CellLanguage = 4,
467 > DocumentMetadata = 5,
468 > Move = 6,
469 > OutputItems = 7,
470 > PartialMetadata = 8,
471 > PartialInternalMetadata = 9,
472 > }
473 >
474 > export interface ICellDto2 {
475 > source: string;
476 > language: string;
477 > mime: string | undefined;
478 > cellKind: CellKind;
479 > outputs: IOutputDto[];
480 > metadata?: NotebookCellMetadata;
481 > internalMetadata?: NotebookCellInternalMetadata;
482 > collapseState?: NotebookCellCollapseState;
483 > }
484 >
485 > export interface ICellReplaceEdit {
486 > editType: CellEditType.Replace;
487 > index: number;
488 > count: number;
489 > cells: ICellDto2[];
490 > }
491 >
492 > export interface ICellOutputEdit {
493 > editType: CellEditType.Output;
494 > index: number;
495 > outputs: IOutputDto[];
496 > append?: boolean;
497 > }
498 >
499 > export interface ICellOutputEditByHandle {
500 > editType: CellEditType.Output;
501 > handle: number;
502 > outputs: IOutputDto[];
503 > append?: boolean;
504 > }
505 >
506 > export interface ICellOutputItemEdit {
507 > editType: CellEditType.OutputItems;
508 > outputId: string;
509 > items: IOutputItemDto[];
510 > append?: boolean;
511 > }
512 >
513 > export interface ICellMetadataEdit {
514 > editType: CellEditType.Metadata;
515 > index: number;
516 > metadata: NotebookCellMetadata;
517 > }
518 >
519 > // These types are nullable because we need to use 'null' on the EH side so it is JSON-stringified
520 > export type NullablePartialNotebookCellMetadata = {
521 > [Key in keyof Partial<NotebookCellMetadata>]: NotebookCellMetadata[Key] | null
522 > };
523 >
524 > export interface ICellPartialMetadataEdit {
525 > editType: CellEditType.PartialMetadata;
526 > index: number;
527 > metadata: NullablePartialNotebookCellMetadata;
528 > }
529 >
530 > export interface ICellPartialMetadataEditByHandle {
531 > editType: CellEditType.PartialMetadata;
532 > handle: number;
533 > metadata: NullablePartialNotebookCellMetadata;
534 > }
535 >
536 > export type NullablePartialNotebookCellInternalMetadata = {
537 > [Key in keyof Partial<NotebookCellInternalMetadata>]: NotebookCellInternalMetadata[Key] | null
538 > };
539 > export interface ICellPartialInternalMetadataEdit {
540 > editType: CellEditType.PartialInternalMetadata;
541 > index: number;
542 > internalMetadata: NullablePartialNotebookCellInternalMetadata;
543 > }
544 >
545 > export interface ICellPartialInternalMetadataEditByHandle {
546 > editType: CellEditType.PartialInternalMetadata;
547 > handle: number;
548 > internalMetadata: NullablePartialNotebookCellInternalMetadata;
549 > }
550 >
551 > export interface ICellLanguageEdit {
552 > editType: CellEditType.CellLanguage;
553 > index: number;
554 > language: string;
555 > }
556 >
557 > export interface IDocumentMetadataEdit {
558 > editType: CellEditType.DocumentMetadata;
559 > metadata: NotebookDocumentMetadata;
560 > }
561 >
562 > export interface ICellMoveEdit {
563 > editType: CellEditType.Move;
564 > index: number;
565 > length: number;
566 > newIdx: number;
567 > }
568 >
569 > export type IImmediateCellEditOperation = ICellOutputEditByHandle | ICellPartialMetadataEditByHandle | ICellOutputItemEdit | ICellPartialInternalMetadataEdit | ICellPartialInternalMetadataEditByHandle | ICellPartialMetadataEdit;
570 > export type ICellEditOperation = IImmediateCellEditOperation | ICellReplaceEdit | ICellOutputEdit | ICellMetadataEdit | ICellPartialMetadataEdit | ICellPartialInternalMetadataEdit | IDocumentMetadataEdit | ICellMoveEdit | ICellOutputItemEdit | ICellLanguageEdit;
571 >
572 >
573 > export interface IWorkspaceNotebookCellEdit {
574 > metadata?: WorkspaceEditMetadata;
575 > resource: URI;
576 > notebookVersionId: number | undefined;
577 > cellEdit: ICellPartialMetadataEdit | IDocumentMetadataEdit | ICellReplaceEdit;
578 > }
579 >
580 > export interface IWorkspaceNotebookCellEditDto {
581 > metadata?: WorkspaceEditMetadata;
582 > resource: URI;
583 > notebookVersionId: number | undefined;
584 > cellEdit: ICellPartialMetadataEdit | IDocumentMetadataEdit | ICellReplaceEdit;
585 > }
586 >
587 > export interface NotebookData {
588 > readonly cells: ICellDto2[];
589 > readonly metadata: NotebookDocumentMetadata;
590 > }
591 >
592 >
593 > export interface INotebookContributionData {
594 > extension?: ExtensionIdentifier;
595 > providerDisplayName: string;
596 > displayName: string;
597 > filenamePattern: (string | glob.IRelativePattern | INotebookExclusiveDocumentFilter)[];
598 > priority?: RegisteredEditorPriority;
599 > }
600 >
601 > export namespace NotebookMetadataUri {
602 > export const scheme = Schemas.vscodeNotebookMetadata;
603 > export function generate(notebook: URI): URI {
604 return generateMetadataUri(notebook);
605 }
606 > export function parse(metadata: URI): URI | undefined { notebookCommon.ts
607 return parseMetadataUri(metadata);
608 }
610 >
611 > export namespace CellUri {
612 > export const scheme = Schemas.vscodeNotebookCell;
613 > export function generate(notebook: URI, handle: number): URI {
614 return generateUri(notebook, handle);
615 }
617 > export function parse(cell: URI): { notebook: URI; handle: number } | undefined {
618 return parseUri(cell);
619 }
621 > /**
622 > * Generates a URI for a cell output in a notebook using the output ID.
623 > * Used when URI should be opened as text in the editor.
624 > */
625 > export function generateCellOutputUriWithId(notebook: URI, outputId?: string) {
626 return notebook.with({
627 scheme: Schemas.vscodeNotebookCellOutput,
633 });
634 }
635 > /** notebookCommon.ts
636 > * Generates a URI for a cell output in a notebook using the output index.
637 > * Used when URI should be opened in notebook editor.
638 > */
639 > export function generateCellOutputUriWithIndex(notebook: URI, cellUri: URI, outputIndex: number): URI {
640 return notebook.with({
641 scheme: Schemas.vscodeNotebookCellOutput,
647 });
648 }
650 > export function generateOutputEditorUri(notebook: URI, cellId: string, cellIndex: number, outputId: string, outputIndex: number): URI {
651 return notebook.with({
652 scheme: Schemas.vscodeNotebookCellOutput,
660 });
661 }
663 > export function parseCellOutputUri(uri: URI): { notebook: URI; openIn: string; outputId?: string; cellFragment?: string; outputIndex?: number; cellHandle?: number; cellIndex?: number } | undefined {
664 return extractCellOutputDetails(uri);
665 }
667 > export function generateCellPropertyUri(notebook: URI, handle: number, scheme: string): URI {
668 return CellUri.generate(notebook, handle).with({ scheme: scheme });
669 }
671 > export function parseCellPropertyUri(uri: URI, propertyScheme: string) {
672 if (uri.scheme !== propertyScheme) {
673 return undefined;
676 return CellUri.parse(uri.with({ scheme: scheme }));
677 }
679 >
680 > const normalizeSlashes = (str: string) => isWindows ? str.replace(/\//g, '\\') : str;
681 >
682 > interface IMimeTypeWithMatcher {
683 > pattern: string;
684 > matches: glob.ParsedPattern;
685 > }
686 >
687 > export class MimeTypeDisplayOrder {
688 > private readonly order: IMimeTypeWithMatcher[];
689 >
690 > constructor(
691 initialValue: readonly string[] = [],
692 private readonly defaultOrder = NOTEBOOK_DISPLAY_ORDER,
697 }));
698 }
700 > /**
701 > * Returns a sorted array of the input mimeTypes.
702 > */
703 > public sort(mimeTypes: Iterable<string>): string[] {
704 const remaining = new Map(Iterable.map(mimeTypes, m => [m, normalizeSlashes(m)]));
705 let sorted: string[] = [];
723 return sorted;
724 }
726 > /**
727 > * Records that the user selected the given mimetype over the other
728 > * possible mimeTypes, prioritizing it for future reference.
729 > */
730 > public prioritize(chosenMimetype: string, otherMimeTypes: readonly string[]) {
731 const chosenIndex = this.findIndex(chosenMimetype);
732 if (chosenIndex === -1) {
747 }
748 }
750 > /**
751 > * Gets an array of in-order mimetype preferences.
752 > */
753 > public toArray() {
754 return this.order.map(o => o.pattern);
755 }
757 > private findIndex(mimeType: string, maxIndex = this.order.length) {
758 const normalized = normalizeSlashes(mimeType);
759 for (let i = 0; i < maxIndex; i++) {
765 return -1;
766 }
768 >
769 > interface IMutableSplice<T> extends ISplice<T> {
770 > readonly toInsert: T[];
771 > deleteCount: number;
772 > }
773 >
774 > export function diff<T>(before: T[], after: T[], contains: (a: T) => boolean, equal: (a: T, b: T) => boolean = (a: T, b: T) => a === b): ISplice<T>[] {
775 const result: IMutableSplice<T>[] = [];
776
827 return result;
828 }
830 > export interface ICellEditorViewState {
831 > selections: editorCommon.ICursorState[];
832 > }
833 >
834 > export const NOTEBOOK_EDITOR_CURSOR_BOUNDARY = new RawContextKey<'none' | 'top' | 'bottom' | 'both'>('notebookEditorCursorAtBoundary', 'none');
835 >
836 > export const NOTEBOOK_EDITOR_CURSOR_LINE_BOUNDARY = new RawContextKey<'none' | 'start' | 'end' | 'both'>('notebookEditorCursorAtLineBoundary', 'none');
837 >
838 > export interface INotebookLoadOptions {
839 > /**
840 > * Go to disk bypassing any cache of the model if any.
841 > */
842 > forceReadFromFile?: boolean;
843 > /**
844 > * If provided, the size of the file will be checked against the limits
845 > * and an error will be thrown if any limit is exceeded.
846 > */
847 > readonly limits?: IFileReadLimits;
848 > }
849 >
850 > export type NotebookEditorModelCreationOptions = {
851 > limits?: IFileReadLimits;
852 > scratchpad?: boolean;
853 > viewType?: string;
854 > };
855 >
856 > export interface IResolvedNotebookEditorModel extends INotebookEditorModel {
857 > notebook: NotebookTextModel;
858 > }
859 >
860 > export interface INotebookEditorModel extends IDisposable {
861 > readonly onDidChangeDirty: Event<void>;
862 > readonly onDidSave: Event<IWorkingCopySaveEvent>;
863 > readonly onDidChangeOrphaned: Event<void>;
864 > readonly onDidChangeReadonly: Event<void>;
865 > readonly onDidRevertUntitled: Event<void>;
866 > readonly resource: URI;
867 > readonly viewType: string;
868 > readonly notebook: INotebookTextModel | undefined;
869 > readonly hasErrorState: boolean;
870 > isResolved(): boolean;
871 > isDirty(): boolean;
872 > isModified(): boolean;
873 > isReadonly(): boolean | IMarkdownString;
874 > isOrphaned(): boolean;
875 > hasAssociatedFilePath(): boolean;
876 > load(options?: INotebookLoadOptions): Promise<IResolvedNotebookEditorModel>;
877 > save(options?: ISaveOptions): Promise<boolean>;
878 > saveAs(target: URI): Promise<IUntypedEditorInput | undefined>;
879 > revert(options?: IRevertOptions): Promise<void>;
880 > }
881 >
882 > export interface INotebookDiffEditorModel extends IDisposable {
883 > original: { notebook: NotebookTextModel; resource: URI; viewType: string };
884 > modified: { notebook: NotebookTextModel; resource: URI; viewType: string };
885 > }
886 >
887 > export interface NotebookDocumentBackupData extends IWorkingCopyBackupMeta {
888 > readonly viewType: string;
889 > readonly backupId?: string;
890 > readonly mtime?: number;
891 > }
892 >
893 > export enum NotebookEditorPriority {
894 > default = 'default',
895 > option = 'option',
896 > }
897 >
898 > export interface INotebookFindOptions {
899 > regex?: boolean;
900 > wholeWord?: boolean;
901 > caseSensitive?: boolean;
902 > wordSeparators?: string;
903 > includeMarkupInput?: boolean;
904 > includeMarkupPreview?: boolean;
905 > includeCodeInput?: boolean;
906 > includeOutput?: boolean;
907 > findScope?: INotebookFindScope;
908 > }
909 >
910 > export interface INotebookFindScope {
911 > findScopeType: NotebookFindScopeType;
912 > selectedCellRanges?: ICellRange[];
913 > selectedTextRanges?: Range[];
914 > }
915 >
916 > export enum NotebookFindScopeType {
917 > Cells = 'cells',
918 > Text = 'text',
919 > None = 'none'
920 > }
921 >
922 > export interface INotebookExclusiveDocumentFilter {
923 > include?: string | glob.IRelativePattern;
924 > exclude?: string | glob.IRelativePattern;
925 > }
926 >
927 > export interface INotebookDocumentFilter {
928 > viewType?: string | string[];
929 > filenamePattern?: string | glob.IRelativePattern | INotebookExclusiveDocumentFilter;
930 > }
931 >
932 > //TODO@rebornix test
933 >
934 > export function isDocumentExcludePattern(filenamePattern: string | glob.IRelativePattern | INotebookExclusiveDocumentFilter): filenamePattern is { include: string | glob.IRelativePattern; exclude: string | glob.IRelativePattern } {
935 const arg = filenamePattern as INotebookExclusiveDocumentFilter;
936
942 return false;
943 }
944 > export function notebookDocumentFilterMatch(filter: INotebookDocumentFilter, viewType: string, resource: URI): boolean { notebookCommon.ts
945 if (Array.isArray(filter.viewType) && filter.viewType.indexOf(viewType) >= 0) {
946 return true;
967 return false;
968 }
970 > export interface INotebookCellStatusBarItemProvider {
971 > viewType: string;
972 > onDidChangeStatusBarItems?: Event<void>;
973 > provideCellStatusBarItems(uri: URI, index: number, token: CancellationToken): Promise<INotebookCellStatusBarItemList | undefined>;
974 > }
975 >
976 >
977 > export interface INotebookDiffResult {
978 > cellsDiff: IDiffResult;
979 > metadataChanged: boolean;
980 > }
981 >
982 > export interface INotebookCellStatusBarItem {
983 > readonly alignment: CellStatusbarAlignment;
984 > readonly priority?: number;
985 > readonly text: string;
986 > readonly color?: string | ThemeColor;
987 > readonly backgroundColor?: string | ThemeColor;
988 > readonly tooltip?: string | IMarkdownString;
989 > readonly command?: string | Command;
990 > readonly accessibilityInformation?: IAccessibilityInformation;
991 > readonly opacity?: string;
992 > readonly onlyShowWhenActive?: boolean;
993 > }
994 >
995 > export interface INotebookCellStatusBarItemList {
996 > items: INotebookCellStatusBarItem[];
997 > dispose?(): void;
998 > }
999 >
1000 > export type ShowCellStatusBarType = 'hidden' | 'visible' | 'visibleAfterExecute';
1001 > export const NotebookSetting = {
1002 > displayOrder: 'notebook.displayOrder',
1003 > cellToolbarLocation: 'notebook.cellToolbarLocation',
1004 > cellToolbarVisibility: 'notebook.cellToolbarVisibility',
1005 > showCellStatusBar: 'notebook.showCellStatusBar',
1006 > cellExecutionTimeVerbosity: 'notebook.cellExecutionTimeVerbosity',
1007 > textDiffEditorPreview: 'notebook.diff.enablePreview',
1008 > diffOverviewRuler: 'notebook.diff.overviewRuler',
1009 > experimentalInsertToolbarAlignment: 'notebook.experimental.insertToolbarAlignment',
1010 > compactView: 'notebook.compactView',
1011 > focusIndicator: 'notebook.cellFocusIndicator',
1012 > insertToolbarLocation: 'notebook.insertToolbarLocation',
1013 > globalToolbar: 'notebook.globalToolbar',
1014 > stickyScrollEnabled: 'notebook.stickyScroll.enabled',
1015 > stickyScrollMode: 'notebook.stickyScroll.mode',
1016 > undoRedoPerCell: 'notebook.undoRedoPerCell',
1017 > consolidatedOutputButton: 'notebook.consolidatedOutputButton',
1018 > openOutputInPreviewEditor: 'notebook.output.openInPreviewEditor.enabled',
1019 > showFoldingControls: 'notebook.showFoldingControls',
1020 > dragAndDropEnabled: 'notebook.dragAndDropEnabled',
1021 > cellEditorOptionsCustomizations: 'notebook.editorOptionsCustomizations',
1022 > consolidatedRunButton: 'notebook.consolidatedRunButton',
1023 > openGettingStarted: 'notebook.experimental.openGettingStarted',
1024 > globalToolbarShowLabel: 'notebook.globalToolbarShowLabel',
1025 > markupFontSize: 'notebook.markup.fontSize',
1026 > markdownLineHeight: 'notebook.markdown.lineHeight',
1027 > interactiveWindowCollapseCodeCells: 'interactiveWindow.collapseCellInputCode',
1028 > outputScrolling: 'notebook.output.scrolling',
1029 > textOutputLineLimit: 'notebook.output.textLineLimit',
1030 > LinkifyOutputFilePaths: 'notebook.output.linkifyFilePaths',
1031 > minimalErrorRendering: 'notebook.output.minimalErrorRendering',
1032 > formatOnSave: 'notebook.formatOnSave.enabled',
1033 > insertFinalNewline: 'notebook.insertFinalNewline',
1034 > defaultFormatter: 'notebook.defaultFormatter',
1035 > formatOnCellExecution: 'notebook.formatOnCellExecution',
1036 > codeActionsOnSave: 'notebook.codeActionsOnSave',
1037 > outputWordWrap: 'notebook.output.wordWrap',
1038 > outputLineHeight: 'notebook.output.lineHeight',
1039 > outputFontSize: 'notebook.output.fontSize',
1040 > outputFontFamily: 'notebook.output.fontFamily',
1041 > findFilters: 'notebook.find.filters',
1042 > logging: 'notebook.logging',
1043 > confirmDeleteRunningCell: 'notebook.confirmDeleteRunningCell',
1044 > remoteSaving: 'notebook.experimental.remoteSave',
1045 > gotoSymbolsAllSymbols: 'notebook.gotoSymbols.showAllSymbols',
1046 > outlineShowMarkdownHeadersOnly: 'notebook.outline.showMarkdownHeadersOnly',
1047 > outlineShowCodeCells: 'notebook.outline.showCodeCells',
1048 > outlineShowCodeCellSymbols: 'notebook.outline.showCodeCellSymbols',
1049 > breadcrumbsShowCodeCells: 'notebook.breadcrumbs.showCodeCells',
1050 > scrollToRevealCell: 'notebook.scrolling.revealNextCellOnExecute',
1051 > cellChat: 'notebook.experimental.cellChat',
1052 > cellGenerate: 'notebook.experimental.generate',
1053 > notebookVariablesView: 'notebook.variablesView',
1054 > notebookInlineValues: 'notebook.inlineValues',
1055 > InteractiveWindowPromptToSave: 'interactiveWindow.promptToSaveOnClose',
1056 > cellFailureDiagnostics: 'notebook.cellFailureDiagnostics',
1057 > outputBackupSizeLimit: 'notebook.backup.sizeLimit',
1058 > multiCursor: 'notebook.multiCursor.enabled',
1059 > markupFontFamily: 'notebook.markup.fontFamily',
1060 > } as const;
1061 >
1062 > export const enum CellStatusbarAlignment {
1063 > Left = 1,
1064 > Right = 2
1065 > }
1066 >
1067 > export class NotebookWorkingCopyTypeIdentifier {
1068 >
1069 > private static _prefix = 'notebook/';
1070 >
1071 > static create(notebookType: string, viewType?: string): string {
1072 return `${NotebookWorkingCopyTypeIdentifier._prefix}${notebookType}/${viewType ?? notebookType}`;
1073 }
1075 > static parse(candidate: string): { notebookType: string; viewType: string } | undefined {
1076 if (candidate.startsWith(NotebookWorkingCopyTypeIdentifier._prefix)) {
1077 const split = candidate.substring(NotebookWorkingCopyTypeIdentifier._prefix.length).split('/');
1082 return undefined;
1083 }
1085 >
1086 > export interface NotebookExtensionDescription {
1087 > readonly id: ExtensionIdentifier;
1088 > readonly location: UriComponents | undefined;
1089 > }
1090 >
1091 > const textDecoder = new TextDecoder();
1092 >
1093 > /**
1094 > * Given a stream of individual stdout outputs, this function will return the compressed lines, escaping some of the common terminal escape codes.
1095 > * E.g. some terminal escape codes would result in the previous line getting cleared, such if we had 3 lines and
1096 > * last line contained such a code, then the result string would be just the first two lines.
1097 > * @returns a single VSBuffer with the concatenated and compressed data, and whether any compression was done.
1098 > */
1099 > export function compressOutputItemStreams(outputs: Uint8Array[]) {
1100 const buffers: Uint8Array[] = [];
1101 let startAppending = false;
1115 return { data, didCompression };
1116 }
1118 > export const MOVE_CURSOR_1_LINE_COMMAND = `${String.fromCharCode(27)}[A`;
1119 > const MOVE_CURSOR_1_LINE_COMMAND_BYTES = MOVE_CURSOR_1_LINE_COMMAND.split('').map(c => c.charCodeAt(0));
1120 > const LINE_FEED = 10;
1121 function compressStreamBuffer(streams: Uint8Array[]) {
1122 let didCompress = false;
1143 return didCompress;
1144 }
1146 >
1147 >
1148 > /**
1149 > * Took this from jupyter/notebook
1150 > * https://github.com/jupyter/notebook/blob/b8b66332e2023e83d2ee04f83d8814f567e01a4e/notebook/static/base/js/utils.js
1151 > * Remove characters that are overridden by backspace characters
1152 > */
1153 function fixBackspace(txt: string) {
1154 let tmp = txt;
1160 return txt;
1161 }
1163 > /**
1164 > * Remove chunks that should be overridden by the effect of carriage return characters
1165 > * From https://github.com/jupyter/notebook/blob/master/notebook/static/base/js/utils.js
1166 > */
1167 function fixCarriageReturn(txt: string) {
1168 txt = txt.replace(/\r+\n/gm, '\n'); // \r followed by \n --> newline
1175 return txt;
1176 }
1178 > const BACKSPACE_CHARACTER = '\b'.charCodeAt(0);
1179 > const CARRIAGE_RETURN_CHARACTER = '\r'.charCodeAt(0);
1180 function formatStreamText(buffer: VSBuffer): VSBuffer {
1181 // We have special handling for backspace and carriage return characters.
1187 return VSBuffer.fromString(fixCarriageReturn(fixBackspace(textDecoder.decode(buffer.buffer))));
1188 }
1190 > export interface INotebookKernelSourceAction {
1191 > readonly label: string;
1192 > readonly description?: string;
1193 > readonly detail?: string;
1194 > readonly command?: string | Command;
1195 > readonly documentation?: UriComponents | string;
1196 > }
src/vs/base/common/event.ts 904 covered LOC · 119 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- event.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { CancelablePromise } from './async.js';
7 > import { CancellationToken } from './cancellation.js';
8 > import { diffSets } from './collections.js';
9 > import { onUnexpectedError } from './errors.js';
10 > import { createSingleCallFunction } from './functional.js';
11 > import { combinedDisposable, Disposable, DisposableMap, DisposableStore, IDisposable, toDisposable } from './lifecycle.js';
12 > import { LinkedList } from './linkedList.js';
13 > import { IObservable, IObservableWithChange, IObserver } from './observable.js';
14 > import { env } from './process.js';
15 > import { StopWatch } from './stopwatch.js';
16 > import { MicrotaskDelay } from './symbols.js';
17 >
18 >
19 > // -----------------------------------------------------------------------------------------------------------------------
20 > // Uncomment the next line to print warnings whenever an emitter with listeners is disposed. That is a sign of code smell.
21 > // -----------------------------------------------------------------------------------------------------------------------
22 > const _enableDisposeWithListenerWarning = false
23 > // || Boolean("TRUE") // causes a linter warning so that it cannot be pushed
24 > ;
25 >
26 >
27 > // -----------------------------------------------------------------------------------------------------------------------
28 > // Uncomment the next line to print warnings whenever a snapshotted event is used repeatedly without cleanup.
29 > // See https://github.com/microsoft/vscode/issues/142851
30 > // -----------------------------------------------------------------------------------------------------------------------
31 > const _enableSnapshotPotentialLeakWarning = false
32 > // || Boolean("TRUE") // causes a linter warning so that it cannot be pushed
33 > ;
34 >
35 >
36 > const _bufferLeakWarnCountThreshold = 100;
37 > const _bufferLeakWarnTimeThreshold = 60_000; // 1 minute
38 >
39 function _isBufferLeakWarningEnabled(): boolean {
40 return !!env['VSCODE_DEV'];
41 }
42 > event.ts
43 > /**
44 > * An event with zero or one parameters that can be subscribed to. The event is a function itself.
45 > */
46 > export interface Event<T> {
47 > (listener: (e: T) => unknown, thisArgs?: any, disposables?: IDisposable[] | DisposableStore): IDisposable;
48 > }
49 >
50 > export namespace Event {
51 > export const None: Event<any> = () => Disposable.None;
52 >
53 > function _addLeakageTraceLogic(options: EmitterOptions) {
54 if (_enableSnapshotPotentialLeakWarning) {
55 const { onDidAddListener: origListenerDidAdd } = options;
65 }
66 }
67 > event.ts
68 > /**
69 > * Given an event, returns another event which debounces calls and defers the listeners to a later task via a shared
70 > * `setTimeout`. The event is converted into a signal (`Event<void>`) to avoid additional object creation as a
71 > * result of merging events and to try prevent race conditions that could arise when using related deferred and
72 > * non-deferred events.
73 > *
74 > * This is useful for deferring non-critical work (eg. general UI updates) to ensure it does not block critical work
75 > * (eg. latency of keypress to text rendered).
76 > *
77 > * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned
78 > * event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the
79 > * returned event causes this utility to leak a listener on the original event.
80 > *
81 > * @param event The event source for the new event.
82 > * @param flushOnListenerRemove Whether to fire all debounced events when a listener is removed. If this is not
83 > * specified, some events could go missing. Use this if it's important that all events are processed, even if the
84 > * listener gets disposed before the debounced event fires.
85 > * @param disposable A disposable store to add the new EventEmitter to.
86 > */
87 > export function defer(event: Event<unknown>, flushOnListenerRemove?: boolean, disposable?: DisposableStore): Event<void> {
88 return debounce<unknown, void>(event, () => void 0, 0, undefined, flushOnListenerRemove ?? true, undefined, disposable);
89 }
90 > event.ts
91 > /**
92 > * Given an event, returns another event which only fires once.
93 > *
94 > * @param event The event source for the new event.
95 > */
96 > export function once<T>(event: Event<T>): Event<T> {
97 return (listener, thisArgs = null, disposables?) => {
98 // we need this, in case the event fires during the listener call
118 };
119 }
120 > event.ts
121 > /**
122 > * Given an event, returns another event which only fires once, and only when the condition is met.
123 > *
124 > * @param event The event source for the new event.
125 > */
126 > export function onceIf<T>(event: Event<T>, condition: (e: T) => boolean): Event<T> {
127 return Event.once(Event.filter(event, condition));
128 }
129 > event.ts
130 > /**
131 > * Maps an event of one type into an event of another type using a mapping function, similar to how
132 > * `Array.prototype.map` works.
133 > *
134 > * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned
135 > * event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the
136 > * returned event causes this utility to leak a listener on the original event.
137 > *
138 > * @param event The event source for the new event.
139 > * @param map The mapping function.
140 > * @param disposable A disposable store to add the new EventEmitter to.
141 > */
142 > export function map<I, O>(event: Event<I>, map: (i: I) => O, disposable?: DisposableStore): Event<O> {
143 return snapshot((listener, thisArgs = null, disposables?) => event(i => listener.call(thisArgs, map(i)), null, disposables), disposable);
144 }
145 > event.ts
146 > /**
147 > * Wraps an event in another event that performs some function on the event object before firing.
148 > *
149 > * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned
150 > * event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the
151 > * returned event causes this utility to leak a listener on the original event.
152 > *
153 > * @param event The event source for the new event.
154 > * @param each The function to perform on the event object.
155 > * @param disposable A disposable store to add the new EventEmitter to.
156 > */
157 > export function forEach<I>(event: Event<I>, each: (i: I) => void, disposable?: DisposableStore): Event<I> {
158 return snapshot((listener, thisArgs = null, disposables?) => event(i => { each(i); listener.call(thisArgs, i); }, null, disposables), disposable);
159 }
160 > event.ts
161 > /**
162 > * Wraps an event in another event that fires only when some condition is met.
163 > *
164 > * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned
165 > * event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the
166 > * returned event causes this utility to leak a listener on the original event.
167 > *
168 > * @param event The event source for the new event.
169 > * @param filter The filter function that defines the condition. The event will fire for the object if this function
170 > * returns true.
171 > * @param disposable A disposable store to add the new EventEmitter to.
172 > */
173 > export function filter<T, U>(event: Event<T | U>, filter: (e: T | U) => e is T, disposable?: DisposableStore): Event<T>;
174 > export function filter<T>(event: Event<T>, filter: (e: T) => boolean, disposable?: DisposableStore): Event<T>;
175 > export function filter<T, R>(event: Event<T | R>, filter: (e: T | R) => e is R, disposable?: DisposableStore): Event<R>;
176 > export function filter<T>(event: Event<T>, filter: (e: T) => boolean, disposable?: DisposableStore): Event<T> {
177 return snapshot((listener, thisArgs = null, disposables?) => event(e => filter(e) && listener.call(thisArgs, e), null, disposables), disposable);
178 }
179 > event.ts
180 > /**
181 > * Given an event, returns the same event but typed as `Event<void>`.
182 > */
183 > export function signal<T>(event: Event<T>): Event<void> {
184 return event as Event<any> as Event<void>;
185 }
186 > event.ts
187 > /**
188 > * Given a collection of events, returns a single event which emits whenever any of the provided events emit.
189 > */
190 > export function any<T>(...events: Event<T>[]): Event<T>;
191 > export function any(...events: Event<any>[]): Event<void>;
192 > export function any<T>(...events: Event<T>[]): Event<T> {
193 return (listener, thisArgs = null, disposables?) => {
194 const disposable = combinedDisposable(...events.map(event => event(e => listener.call(thisArgs, e))));
196 };
197 }
198 > event.ts
199 > /**
200 > * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned
201 > * event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the
202 > * returned event causes this utility to leak a listener on the original event.
203 > */
204 > export function reduce<I, O>(event: Event<I>, merge: (last: O | undefined, event: I) => O, initial?: O, disposable?: DisposableStore): Event<O> {
205 let output: O | undefined = initial;
206
210 }, disposable);
211 }
212 > event.ts
213 > function snapshot<T>(event: Event<T>, disposable: DisposableStore | undefined): Event<T> {
214 let listener: IDisposable | undefined;
215
233 return emitter.event;
234 }
235 > event.ts
236 > /**
237 > * Adds the IDisposable to the store if it's set, and returns it. Useful to
238 > * Event function implementation.
239 > */
240 > function addAndReturnDisposable<T extends IDisposable>(d: T, store: DisposableStore | IDisposable[] | undefined): T {
241 if (store instanceof Array) {
242 store.push(d);
246 return d;
247 }
248 > event.ts
249 > /**
250 > * Given an event, creates a new emitter that event that will debounce events based on {@link delay} and give an
251 > * array event object of all events that fired.
252 > *
253 > * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned
254 > * event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the
255 > * returned event causes this utility to leak a listener on the original event.
256 > *
257 > * @param event The original event to debounce.
258 > * @param merge A function that reduces all events into a single event.
259 > * @param delay The number of milliseconds to debounce.
260 > * @param leading Whether to fire a leading event without debouncing.
261 > * @param flushOnListenerRemove Whether to fire all debounced events when a listener is removed. If this is not
262 > * specified, some events could go missing. Use this if it's important that all events are processed, even if the
263 > * listener gets disposed before the debounced event fires.
264 > * @param leakWarningThreshold See {@link EmitterOptions.leakWarningThreshold}.
265 > * @param disposable A disposable store to register the debounce emitter to.
266 > */
267 > export function debounce<T>(event: Event<T>, merge: (last: T | undefined, event: T) => T, delay?: number | typeof MicrotaskDelay, leading?: boolean, flushOnListenerRemove?: boolean, leakWarningThreshold?: number, disposable?: DisposableStore): Event<T>;
268 > export function debounce<I, O>(event: Event<I>, merge: (last: O | undefined, event: I) => O, delay?: number | typeof MicrotaskDelay, leading?: boolean, flushOnListenerRemove?: boolean, leakWarningThreshold?: number, disposable?: DisposableStore): Event<O>;
269 > export function debounce<I, O>(event: Event<I>, merge: (last: O | undefined, event: I) => O, delay: number | typeof MicrotaskDelay = 100, leading = false, flushOnListenerRemove = false, leakWarningThreshold?: number, disposable?: DisposableStore): Event<O> {
270 let subscription: IDisposable;
271 let output: O | undefined = undefined;
330 return emitter.event;
331 }
332 > event.ts
333 > /**
334 > * Debounces an event, firing after some delay (default=0) with an array of all event original objects.
335 > *
336 > * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned
337 > * event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the
338 > * returned event causes this utility to leak a listener on the original event.
339 > *
340 > * @param event The event source for the new event.
341 > * @param delay The number of milliseconds to debounce.
342 > * @param flushOnListenerRemove Whether to fire all debounced events when a listener is removed. If this is not
343 > * specified, some events could go missing. Use this if it's important that all events are processed, even if the
344 > * listener gets disposed before the debounced event fires.
345 > * @param disposable A disposable store to add the new EventEmitter to.
346 > */
347 > export function accumulate<T>(event: Event<T>, delay: number | typeof MicrotaskDelay = 0, flushOnListenerRemove?: boolean, disposable?: DisposableStore): Event<T[]> {
348 return Event.debounce<T, T[]>(event, (last, e) => {
349 if (!last) {
354 }, delay, undefined, flushOnListenerRemove ?? true, undefined, disposable);
355 }
356 > event.ts
357 > /**
358 > * Throttles an event, ensuring the event is fired at most once during the specified delay period.
359 > * Unlike debounce, throttle will fire immediately on the leading edge and/or after the delay on the trailing edge.
360 > *
361 > * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned
362 > * event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the
363 > * returned event causes this utility to leak a listener on the original event.
364 > *
365 > * @param event The event source for the new event.
366 > * @param merge An accumulator function that merges events if multiple occur during the throttle period.
367 > * @param delay The number of milliseconds to throttle.
368 > * @param leading Whether to fire on the leading edge (immediately on first event).
369 > * @param trailing Whether to fire on the trailing edge (after delay with the last value).
370 > * @param leakWarningThreshold See {@link EmitterOptions.leakWarningThreshold}.
371 > * @param disposable A disposable store to register the throttle emitter to.
372 > */
373 > export function throttle<T>(event: Event<T>, merge: (last: T | undefined, event: T) => T, delay?: number | typeof MicrotaskDelay, leading?: boolean, trailing?: boolean, leakWarningThreshold?: number, disposable?: DisposableStore): Event<T>;
374 > export function throttle<I, O>(event: Event<I>, merge: (last: O | undefined, event: I) => O, delay?: number | typeof MicrotaskDelay, leading?: boolean, trailing?: boolean, leakWarningThreshold?: number, disposable?: DisposableStore): Event<O>;
375 > export function throttle<I, O>(event: Event<I>, merge: (last: O | undefined, event: I) => O, delay: number | typeof MicrotaskDelay = 100, leading = true, trailing = true, leakWarningThreshold?: number, disposable?: DisposableStore): Event<O> {
376 let subscription: IDisposable;
377 let output: O | undefined = undefined;
437 return emitter.event;
438 }
439 > event.ts
440 > /**
441 > * Filters an event such that some condition is _not_ met more than once in a row, effectively ensuring duplicate
442 > * event objects from different sources do not fire the same event object.
443 > *
444 > * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned
445 > * event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the
446 > * returned event causes this utility to leak a listener on the original event.
447 > *
448 > * @param event The event source for the new event.
449 > * @param equals The equality condition.
450 > * @param disposable A disposable store to add the new EventEmitter to.
451 > *
452 > * @example
453 > * ```
454 > * // Fire only one time when a single window is opened or focused
455 > * Event.latch(Event.any(onDidOpenWindow, onDidFocusWindow))
456 > * ```
457 > */
458 > export function latch<T>(event: Event<T>, equals: (a: T, b: T) => boolean = (a, b) => a === b, disposable?: DisposableStore): Event<T> {
459 let firstCall = true;
460 let cache: T;
467 }, disposable);
468 }
469 > event.ts
470 > /**
471 > * Splits an event whose parameter is a union type into 2 separate events for each type in the union.
472 > *
473 > * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned
474 > * event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the
475 > * returned event causes this utility to leak a listener on the original event.
476 > *
477 > * @example
478 > * ```
479 > * const event = new EventEmitter<number | undefined>().event;
480 > * const [numberEvent, undefinedEvent] = Event.split(event, isUndefined);
481 > * ```
482 > *
483 > * @param event The event source for the new event.
484 > * @param isT A function that determines what event is of the first type.
485 > * @param disposable A disposable store to add the new EventEmitter to.
486 > */
487 > export function split<T, U>(event: Event<T | U>, isT: (e: T | U) => e is T, disposable?: DisposableStore): [Event<T>, Event<U>] {
488 return [
489 Event.filter(event, isT, disposable),
491 ];
492 }
493 > event.ts
494 > /**
495 > * Buffers an event until it has a listener attached.
496 > *
497 > * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned
498 > * event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the
499 > * returned event causes this utility to leak a listener on the original event.
500 > *
501 > * @param event The event source for the new event.
502 > * @param debugName A name for this buffer, used in leak detection warnings.
503 > * @param flushAfterTimeout Determines whether to flush the buffer after a timeout immediately or after a
504 > * `setTimeout` when the first event listener is added.
505 > * @param _buffer Internal: A source event array used for tests.
506 > *
507 > * @example
508 > * ```
509 > * // Start accumulating events, when the first listener is attached, flush
510 > * // the event after a timeout such that multiple listeners attached before
511 > * // the timeout would receive the event
512 > * this.onInstallExtension = Event.buffer(service.onInstallExtension, 'onInstallExtension', true);
513 > * ```
514 > */
515 > export function buffer<T>(event: Event<T>, debugName: string, flushAfterTimeout = false, _buffer: T[] = [], disposable?: DisposableStore): Event<T> {
516 let buffer: T[] | null = _buffer.slice();
517
600 return emitter.event;
601 }
602 > /** event.ts
603 > * Wraps the event in an {@link IChainableEvent}, allowing a more functional programming style.
604 > *
605 > * @example
606 > * ```
607 > * // Normal
608 > * const onEnterPressNormal = Event.filter(
609 > * Event.map(onKeyPress.event, e => new StandardKeyboardEvent(e)),
610 > * e.keyCode === KeyCode.Enter
611 > * ).event;
612 > *
613 > * // Using chain
614 > * const onEnterPressChain = Event.chain(onKeyPress.event, $ => $
615 > * .map(e => new StandardKeyboardEvent(e))
616 > * .filter(e => e.keyCode === KeyCode.Enter)
617 > * );
618 > * ```
619 > */
620 > export function chain<T, R>(event: Event<T>, sythensize: ($: IChainableSythensis<T>) => IChainableSythensis<R>): Event<R> {
621 const fn: Event<R> = (listener, thisArgs, disposables) => {
622 const cs = sythensize(new ChainableSynthesis()) as ChainableSynthesis;
631 return fn;
632 }
633 > event.ts
634 > const HaltChainable = Symbol('HaltChainable');
635 >
636 > class ChainableSynthesis implements IChainableSythensis<any> {
637 private readonly steps: ((input: any) => unknown)[] = [];
638 > event.ts
639 > map<O>(fn: (i: any) => O): this {
640 this.steps.push(fn);
641 return this;
642 }
643 > event.ts
644 > forEach(fn: (i: any) => void): this {
645 this.steps.push(v => {
646 fn(v);
649 return this;
650 }
651 > event.ts
652 > filter(fn: (e: any) => boolean): this {
653 this.steps.push(v => fn(v) ? v : HaltChainable);
654 return this;
655 }
656 > event.ts
657 > reduce<R>(merge: (last: R | undefined, event: any) => R, initial?: R | undefined): this {
658 let last = initial;
659 this.steps.push(v => {
663 return this;
664 }
665 > event.ts
666 > latch(equals: (a: any, b: any) => boolean = (a, b) => a === b): ChainableSynthesis {
667 let firstCall = true;
668 let cache: any;
676 return this;
677 }
678 > event.ts
679 > public evaluate(value: any) {
680 for (const step of this.steps) {
681 value = step(value);
687 return value;
688 }
689 > } event.ts
690 >
691 > export interface IChainableSythensis<T> {
692 > map<O>(fn: (i: T) => O): IChainableSythensis<O>;
693 > forEach(fn: (i: T) => void): IChainableSythensis<T>;
694 > filter<R extends T>(fn: (e: T) => e is R): IChainableSythensis<R>;
695 > filter(fn: (e: T) => boolean): IChainableSythensis<T>;
696 > reduce<R>(merge: (last: R, event: T) => R, initial: R): IChainableSythensis<R>;
697 > reduce<R>(merge: (last: R | undefined, event: T) => R): IChainableSythensis<R>;
698 > latch(equals?: (a: T, b: T) => boolean): IChainableSythensis<T>;
699 > }
700 >
701 > export interface NodeEventEmitter {
702 > on(event: string | symbol, listener: Function): unknown;
703 > removeListener(event: string | symbol, listener: Function): unknown;
704 > }
705 >
706 > /**
707 > * Creates an {@link Event} from a node event emitter.
708 > */
709 > export function fromNodeEventEmitter<T>(emitter: NodeEventEmitter, eventName: string, map: (...args: any[]) => T = id => id): Event<T> {
710 const fn = (...args: unknown[]) => result.fire(map(...args));
711 const onFirstListenerAdd = () => emitter.on(eventName, fn);
715 return result.event;
716 }
717 > event.ts
718 > export interface DOMEventEmitter {
719 > addEventListener(event: string | symbol, listener: Function): void;
720 > removeEventListener(event: string | symbol, listener: Function): void;
721 > }
722 >
723 > /**
724 > * Creates an {@link Event} from a DOM event emitter.
725 > */
726 > export function fromDOMEventEmitter<T>(emitter: DOMEventEmitter, eventName: string, map: (...args: any[]) => T = id => id): Event<T> {
727 const fn = (...args: unknown[]) => result.fire(map(...args));
728 const onFirstListenerAdd = () => emitter.addEventListener(eventName, fn);
732 return result.event;
733 }
734 > event.ts
735 > /**
736 > * Creates a promise out of an event, using the {@link Event.once} helper.
737 > */
738 > export function toPromise<T>(event: Event<T>, disposables?: IDisposable[] | DisposableStore): CancelablePromise<T> {
739 let cancelRef: () => void;
740 let listener: IDisposable;
756 return promise;
757 }
758 > event.ts
759 > /**
760 > * A convenience function for forwarding an event to another emitter which
761 > * improves readability.
762 > *
763 > * This is similar to {@link Relay} but allows instantiating and forwarding
764 > * on a single line and also allows for multiple source events.
765 > * @param from The event to forward.
766 > * @param to The emitter to forward the event to.
767 > * @example
768 > * Event.forward(event, emitter);
769 > * // equivalent to
770 > * event(e => emitter.fire(e));
771 > * // equivalent to
772 > * event(emitter.fire, emitter);
773 > */
774 > export function forward<T>(from: Event<T>, to: Emitter<T>): IDisposable {
775 return from(e => to.fire(e));
776 }
777 > event.ts
778 > /**
779 > * Adds a listener to an event and calls the listener immediately with undefined as the event object.
780 > *
781 > * @example
782 > * ```
783 > * // Initialize the UI and update it when dataChangeEvent fires
784 > * runAndSubscribe(dataChangeEvent, () => this._updateUI());
785 > * ```
786 > */
787 > export function runAndSubscribe<T>(event: Event<T>, handler: (e: T) => unknown, initial: T): IDisposable;
788 > export function runAndSubscribe<T>(event: Event<T>, handler: (e: T | undefined) => unknown): IDisposable;
789 > export function runAndSubscribe<T>(event: Event<T>, handler: (e: T | undefined) => unknown, initial?: T): IDisposable {
790 handler(initial);
791 return event(e => handler(e));
792 }
793 > event.ts
794 > class EmitterObserver<T> implements IObserver {
795 >
796 > readonly emitter: Emitter<T>;
797 >
798 > private _counter = 0;
799 > private _hasChanged = false;
800 >
801 > constructor(readonly _observable: IObservable<T>, store: DisposableStore | undefined) {
802 const options: EmitterOptions = {
803 onWillAddFirstListener: () => {
819 }
820 }
821 > event.ts
822 > beginUpdate<T>(_observable: IObservable<T>): void {
823 // assert(_observable === this.obs);
824 this._counter++;
825 }
826 > event.ts
827 > handlePossibleChange<T>(_observable: IObservable<T>): void {
828 // assert(_observable === this.obs);
829 }
830 > event.ts
831 > handleChange<T, TChange>(_observable: IObservableWithChange<T, TChange>, _change: TChange): void {
832 // assert(_observable === this.obs);
833 this._hasChanged = true;
834 }
835 > event.ts
836 > endUpdate<T>(_observable: IObservable<T>): void {
837 // assert(_observable === this.obs);
838 this._counter--;
845 }
846 }
847 > } event.ts
848 >
849 > /**
850 > * Creates an event emitter that is fired when the observable changes.
851 > * Each listeners subscribes to the emitter.
852 > */
853 > export function fromObservable<T>(obs: IObservable<T>, store?: DisposableStore): Event<T> {
854 const observer = new EmitterObserver(obs, store);
855 return observer.emitter.event;
856 }
857 > event.ts
858 > /**
859 > * Each listener is attached to the observable directly.
860 > */
861 > export function fromObservableLight(observable: IObservable<unknown>): Event<void> {
862 return (listener, thisArgs, disposables) => {
863 let count = 0;
897 };
898 }
899 > } event.ts
900 >
901 > export interface EmitterOptions {
902 > /**
903 > * Optional function that's called *before* the very first listener is added
904 > */
905 > onWillAddFirstListener?: Function;
906 > /**
907 > * Optional function that's called *after* the very first listener is added
908 > */
909 > onDidAddFirstListener?: Function;
910 > /**
911 > * Optional function that's called after a listener is added
912 > */
913 > onDidAddListener?: Function;
914 > /**
915 > * Optional function that's called *after* remove the very last listener
916 > */
917 > onDidRemoveLastListener?: Function;
918 > /**
919 > * Optional function that's called *before* a listener is removed
920 > */
921 > onWillRemoveListener?: Function;
922 > /**
923 > * Optional function that's called when a listener throws an error. Defaults to
924 > * {@link onUnexpectedError}
925 > */
926 > onListenerError?: (e: any) => void;
927 > /**
928 > * Number of listeners that are allowed before assuming a leak. Default to
929 > * a globally configured value
930 > *
931 > * @see setGlobalLeakWarningThreshold
932 > */
933 > leakWarningThreshold?: number;
934 > /**
935 > * Human-readable name for the emitter, included in leak warning error
936 > * messages to help identify which emitter is leaking in telemetry.
937 > */
938 > leakWarningName?: string;
939 > /**
940 > * Pass in a delivery queue, which is useful for ensuring
941 > * in order event delivery across multiple emitters.
942 > */
943 > deliveryQueue?: EventDeliveryQueue;
944 >
945 > /** ONLY enable this during development */
946 > _profName?: string;
947 > }
948 >
949 >
950 > export class EventProfiling {
951 >
952 > static readonly all = new Set<EventProfiling>();
953 >
954 > private static _idPool = 0;
955 >
956 > readonly name: string;
957 > public listenerCount: number = 0;
958 > public invocationCount = 0;
959 > public elapsedOverall = 0;
960 > public durations: number[] = [];
961 >
962 > private _stopWatch?: StopWatch;
963 >
964 > constructor(name: string) {
965 this.name = `${name}_${EventProfiling._idPool++}`;
966 EventProfiling.all.add(this);
967 }
968 > event.ts
969 > start(listenerCount: number): void {
970 this._stopWatch = new StopWatch();
971 this.listenerCount = listenerCount;
972 }
973 > event.ts
974 > stop(): void {
975 if (this._stopWatch) {
976 const elapsed = this._stopWatch.elapsed();
981 }
982 }
983 > } event.ts
984 >
985 > let _globalLeakWarningThreshold = -1;
986 > export function setGlobalLeakWarningThreshold(n: number): IDisposable {
987 const oldValue = _globalLeakWarningThreshold;
988 _globalLeakWarningThreshold = n;
993 };
994 }
995 > event.ts
996 > class LeakageMonitor {
997 >
998 > private static _idPool = 1;
999 >
1000 > private _stacks: Map<string, number> | undefined;
1001 > private _warnCountdown: number = 0;
1002 >
1003 > constructor(
1004 private readonly _errorHandler: (err: Error) => void,
1005 readonly threshold: number,
1006 readonly name: string = (LeakageMonitor._idPool++).toString(16).padStart(3, '0')
1007 ) { }
1008 > event.ts
1009 > dispose(): void {
1010 this._stacks?.clear();
1011 }
1012 > event.ts
1013 > check(stack: Stacktrace, listenerCount: number): undefined | (() => void) {
1014
1015 const threshold = this.threshold;
1046 };
1047 }
1048 > event.ts
1049 > getMostFrequentStack(): [string, number] | undefined {
1050 if (!this._stacks) {
1051 return undefined;
1061 return topStack;
1062 }
1063 > } event.ts
1064 >
1065 > class Stacktrace {
1066 >
1067 > static create() {
1068 > const err = new Error();
1069 > return new Stacktrace(err.stack ?? '');
1070 > }
1071 >
1072 > private constructor(readonly value: string) { }
1073 >
1074 > print() {
1075 console.warn(this.value.split('\n').slice(2).join('\n'));
1076 }
1077 > } event.ts
1078 >
1079 > // error that is logged when going over the configured listener threshold
1080 > export class ListenerLeakError extends Error {
1081 > readonly kind: string;
1082 > readonly listenerCount: number;
1083 > /**
1084 > * The detailed message including listener count and most frequent stack.
1085 > * Available locally for debugging but intentionally not used as the error
1086 > * `message`. When `emitterName` is provided, errors group by emitter name
1087 > * and kind in telemetry; otherwise they group by kind alone.
1088 > */
1089 > readonly details: string;
1090 > constructor(kind: 'dominated' | 'popular', details: string, stack: string, listenerCount: number, emitterName?: string) {
1091 super(emitterName
1092 ? `[${emitterName}] potential listener LEAK detected, ${kind}`
1098 this.stack = stack;
1099 }
1100 > event.ts
1101 > static is(err: unknown): err is ListenerLeakError {
1102 return err instanceof ListenerLeakError
1103 || (err instanceof Error && typeof (err as Error & { kind: unknown; listenerCount: unknown }).kind === 'string' && typeof (err as Error & { kind: unknown; listenerCount: unknown }).listenerCount === 'number');
1104 }
1105 > } event.ts
1106 >
1107 > // SEVERE error that is logged when having gone way over the configured listener
1108 > // threshold so that the emitter refuses to accept more listeners
1109 > export class ListenerRefusalError extends ListenerLeakError {
1110 > constructor(kind: 'dominated' | 'popular', details: string, stack: string, listenerCount: number, emitterName?: string) {
1111 super(kind, details, stack, listenerCount, emitterName);
1112 this.name = 'ListenerRefusalError';
1113 }
1114 > } event.ts
1115 >
1116 > let id = 0;
1117 > class UniqueContainer<T> {
1118 > stack?: Stacktrace;
1119 > public id = id++;
1120 > constructor(public readonly value: T) { }
1121 > }
1122 > const compactionThreshold = 2;
1123 >
1124 > type ListenerContainer<T> = UniqueContainer<(data: T) => void>;
1125 > type ListenerOrListeners<T> = (ListenerContainer<T> | undefined)[] | ListenerContainer<T>;
1126 >
1127 > const forEachListener = <T>(listeners: ListenerOrListeners<T>, fn: (c: ListenerContainer<T>) => void) => {
1128 if (listeners instanceof UniqueContainer) {
1129 fn(listeners);
1137 }
1138 };
1139 > event.ts
1140 > /**
1141 > * The Emitter can be used to expose an Event to the public
1142 > * to fire it from the insides.
1143 > * Sample:
1144 > class Document {
1145 >
1146 > private readonly _onDidChange = new Emitter<(value:string)=>any>();
1147 >
1148 > public onDidChange = this._onDidChange.event;
1149 >
1150 > // getter-style
1151 > // get onDidChange(): Event<(value:string)=>any> {
1152 > // return this._onDidChange.event;
1153 > // }
1154 >
1155 > private _doIt() {
1156 > //...
1157 > this._onDidChange.fire(value);
1158 > }
1159 > }
1160 > */
1161 > export class Emitter<T> {
1162 >
1163 > private readonly _options?: EmitterOptions;
1164 > private readonly _leakageMon?: LeakageMonitor;
1165 > private readonly _perfMon?: EventProfiling;
1166 > private _disposed?: true;
1167 > private _event?: Event<T>;
1168 >
1169 > /**
1170 > * A listener, or list of listeners. A single listener is the most common
1171 > * for event emitters (#185789), so we optimize that special case to avoid
1172 > * wrapping it in an array (just like Node.js itself.)
1173 > *
1174 > * A list of listeners never 'downgrades' back to a plain function if
1175 > * listeners are removed, for two reasons:
1176 > *
1177 > * 1. That's complicated (especially with the deliveryQueue)
1178 > * 2. A listener with >1 listener is likely to have >1 listener again at
1179 > * some point, and swapping between arrays and functions may[citation needed]
1180 > * introduce unnecessary work and garbage.
1181 > *
1182 > * The array listeners can be 'sparse', to avoid reallocating the array
1183 > * whenever any listener is added or removed. If more than `1 / compactionThreshold`
1184 > * of the array is empty, only then is it resized.
1185 > */
1186 > protected _listeners?: ListenerOrListeners<T>;
1187 >
1188 > /**
1189 > * Always to be defined if _listeners is an array. It's no longer a true
1190 > * queue, but holds the dispatching 'state'. If `fire()` is called on an
1191 > * emitter, any work left in the _deliveryQueue is finished first.
1192 > */
1193 > private _deliveryQueue?: EventDeliveryQueuePrivate;
1194 > protected _size = 0;
1195 >
1196 > constructor(options?: EmitterOptions) {
1197 > this._options = options; event.ts
1198 > this._leakageMon = (_globalLeakWarningThreshold > 0 || this._options?.leakWarningThreshold)
1199 ? new LeakageMonitor(options?.onListenerError ?? onUnexpectedError, this._options?.leakWarningThreshold ?? _globalLeakWarningThreshold, this._options?.leakWarningName) :
1200 > undefined; event.ts
1201 > this._perfMon = this._options?._profName ? new EventProfiling(this._options._profName) : undefined;
1202 > this._deliveryQueue = this._options?.deliveryQueue as EventDeliveryQueuePrivate | undefined;
1203 > }
1204 > event.ts
1205 > dispose() {
1206 if (!this._disposed) {
1207 this._disposed = true;
1235 }
1236 }
1237 > event.ts
1238 > /**
1239 > * For the public to allow to subscribe
1240 > * to events from this Emitter
1241 > */
1242 > get event(): Event<T> {
1243 > this._event ??= (callback: (e: T) => unknown, thisArgs?: any, disposables?: IDisposable[] | DisposableStore) => { event.ts
1244 > if (this._leakageMon && this._size > this._leakageMon.threshold ** 2) { 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/workbench/contrib/chat/common/chatSessionsService.ts 903 covered LOC · 12 ranges

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- sessionState.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > // Immutable state types for the sessions process protocol.
7 > // See protocol.md for the full design rationale.
8 > //
9 > // Most types are imported from the auto-generated protocol layer
10 > // (synced from the agent-host-protocol repo). This file adds VS Code-specific
11 > // helpers and re-exports.
12 >
13 > import { decodeBase64, encodeBase64, VSBuffer } from '../../../../base/common/buffer.js';
14 > import { hasKey, type Mutable } from '../../../../base/common/types.js';
15 > import { URI as ResourceURI } from '../../../../base/common/uri.js';
16 > import type { IProductService } from '../../../product/common/productService.js';
17 > import { readToolCallMeta } from '../meta/agentToolCallMeta.js';
18 > import {
19 > ResponsePartKind,
20 > SessionStatus,
21 > ToolCallStatus,
22 > SessionLifecycle,
23 > TerminalState,
24 > ToolResultContentType,
25 > ToolResultFileEditContent,
26 > ChatOriginKind,
27 > ChatInteractivity,
28 > type ActiveTurn,
29 > type ChangesetState,
30 > type ChatState,
31 > type ChatSummary,
32 > type PendingMessage,
33 > type Turn,
34 > type AnnotationsState,
35 > type URI as ProtocolURI,
36 > type RootState,
37 > type SessionState,
38 > type SessionSummary,
39 > type TextRange,
40 > type ToolCallCancelledState,
41 > type ToolCallCompletedState,
42 > type ToolCallResult,
43 > type ToolCallState,
44 > type ToolResultContent,
45 > type ToolResultSubagentContent,
46 > type ToolResultTextContent,
47 > type UsageInfo,
48 > type Message,
49 > } from './protocol/state.js';
50 >
51 > // Re-export everything from the protocol state module
52 > export {
53 > ChangesetOperationScope, ChangesetOperationStatus, ChangesetStatus, CustomizationLoadStatus,
54 > CustomizationType, MessageAttachmentKind, MessageKind,
55 > PendingMessageKind,
56 > PolicyState,
57 > ResponsePartKind,
58 > ChatInputAnswerState as SessionInputAnswerState,
59 > ChatInputAnswerValueKind as SessionInputAnswerValueKind,
60 > ChatInputQuestionKind as SessionInputQuestionKind,
61 > ChatInputResponseKind as SessionInputResponseKind,
62 > ChatInteractivity,
63 > ChatOriginKind,
64 > SessionLifecycle,
65 > SessionStatus, ToolCallCancellationReason, ToolCallConfirmationReason, ToolCallContributorKind, ToolCallRiskAssessmentKind, ToolCallRiskAssessmentStatus, ToolCallStatus,
66 > ToolResultContentType,
67 > TurnState, type ActiveTurn, type AgentCustomization, type AgentCapabilities, type AgentInfo, type AgentSelection, type Annotation, type AnnotationEntry, type AnnotationsState, type AnnotationsSummary, type Changeset, type ChangesetFile,
68 > type ChangesetOperation, type ChangesetState, type ChatState, type ChatSummary, type ChatOrigin, type ChildCustomization, type ClientPluginCustomization, type ConfigPropertySchema,
69 > type ConfigSchema,
70 > type ContentRef, type Customization, type CustomizationDegradedState,
71 > type CustomizationErrorState, type CustomizationLoadedState, type CustomizationLoadingState, type CustomizationLoadState, type DirectoryCustomization, type ErrorInfo, type HookCustomization, type FileEdit as ISessionFileDiff, type ToolResultEmbeddedResourceContent as IToolResultBinaryContent, type MarkdownResponsePart, type McpServerCustomization, type MessageAttachment,
72 > type MessageResourceAttachment, type MessageEmbeddedResourceAttachment, type MessageAnnotationsAttachment, type ModelSelection, type PendingMessage, type PluginCustomization, type ProjectInfo, type PromptCustomization, type ReasoningResponsePart,
73 > type ResponsePart,
74 > type RootState, type RuleCustomization, type SessionActiveClient,
75 > type SessionConfigState, type ChatInputAnswer as SessionInputAnswer,
76 > type ChatInputOption as SessionInputOption, type ChatInputQuestion as SessionInputQuestion, type ChatInputRequest as SessionInputRequest, type SessionModelInfo,
77 > type SessionState,
78 > type SessionSummary, type SkillCustomization, type Snapshot, type StringOrMarkdown, type TerminalState, type TextRange,
79 > type ToolAnnotations,
80 > type ToolCallCancelledState,
81 > type ToolCallCompletedState,
82 > type ToolCallPendingConfirmationState,
83 > type ToolCallPendingResultConfirmationState,
84 > type ToolCallResponsePart,
85 > type ToolCallResult,
86 > type ToolCallRiskAssessment,
87 > type ToolCallRiskAssessmentCompleteState,
88 > type ToolCallRiskAssessmentLoadingState,
89 > type ToolCallRunningState,
90 > type ToolCallState,
91 > type ToolCallStreamingState,
92 > type ToolCallContributor,
93 > type ToolDefinition, type ToolResultContent,
94 > type ToolResultFileEditContent,
95 > type TerminalCommandResult,
96 > type ToolResultSubagentContent,
97 > type ToolResultTerminalContent,
98 > type ToolResultTextContent,
99 > type Turn, type URI, type UsageInfo,
100 > type Message
101 > } from './protocol/state.js';
102 >
103 > /**
104 > * Well-known keys that may appear on {@link UsageInfo._meta}.
105 > * Clients MAY read these to provide enhanced UI (e.g. credit cost display).
106 > */
107 > export interface UsageInfoMeta {
108 > /** Per-turn credit cost reported by the backend. */
109 > cost?: number;
110 > /** The concrete model selected by Copilot Auto and the routing explanation. */
111 > autoModeResolved?: IAutoModeResolvedInfo;
112 > /** Copilot-specific usage breakdown, including nano-AIU totals. */
113 > copilotUsage?: {
114 > totalNanoAiu?: number;
115 > [key: string]: unknown;
116 > };
117 > /**
118 > * Per-category account quota snapshots reported by the backend on the
119 > * model-call usage event, keyed by quota type (e.g. `chat`,
120 > * `premium_interactions`). Clients MAY use these to keep the account quota
121 > * UI current without a separate quota fetch.
122 > */
123 > quotaSnapshots?: {
124 > [quotaType: string]: {
125 > readonly isUnlimitedEntitlement?: boolean;
126 > readonly entitlementRequests?: number;
127 > readonly usedRequests?: number;
128 > readonly remainingPercentage?: number;
129 > readonly overage?: number;
130 > readonly overageAllowedWithExhaustedQuota?: boolean;
131 > /** ISO 8601 date when the quota resets, if applicable. */
132 > readonly resetDate?: string;
133 > } | undefined;
134 > };
135 > /**
136 > * Per-source context-window attribution breakdown reported by the SDK's
137 > * `session.rpc.metadata.getContextAttribution()`. Populated asynchronously
138 > * after each usage event and piped to the context-usage widget as
139 > * `promptTokenDetails`.
140 > */
141 > contextAttribution?: IContextAttributionData;
142 > [key: string]: unknown;
143 > }
144 >
145 > export interface IAutoModeResolvedInfo {
146 > readonly chosenModel: string;
147 > readonly reasoningBucket?: 'low' | 'medium' | 'high';
148 > readonly categoryScores?: Readonly<Record<string, number | undefined>>;
149 > readonly predictedLabel?: string;
150 > readonly confidence?: number;
151 > readonly candidateModels?: readonly string[];
152 > }
153 >
154 > /**
155 > * Mirrors the SDK's `SessionContextAttribution` shape — a flat list of
156 > * per-source entries describing what occupies the session's context window.
157 > */
158 > export interface IContextAttributionData {
159 > readonly totalTokens: number;
160 > readonly entries: readonly IContextAttributionEntry[];
161 > readonly compactions: { readonly count: number };
162 > }
163 >
164 > export interface IContextAttributionEntry {
165 > readonly kind: string;
166 > readonly id: string;
167 > readonly label: string;
168 > readonly tokens: number;
169 > readonly parentId?: string;
170 > readonly attributes?: Readonly<Record<string, string | undefined>>;
171 > }
172 >
173 > type AccountQuotaSnapshot = NonNullable<NonNullable<UsageInfoMeta['quotaSnapshots']>[string]>;
174 >
175 function readAccountQuotaSnapshot(value: unknown): AccountQuotaSnapshot | undefined {
176 if (!value || typeof value !== 'object' || Array.isArray(value)) {
188 return snapshot;
189 }
191 > /**
192 > * Reads the well-known {@link UsageInfoMeta} keys from a usage report's open
193 > * `_meta` bag, ignoring unrelated provider-specific keys and validating each
194 > * field's type. Always read {@link UsageInfo._meta} through this helper rather
195 > * than casting the bag to {@link UsageInfoMeta}, so a malformed or partial bag
196 > * degrades to absent fields instead of producing values of the wrong runtime
197 > * type. Returns an empty object when the bag is absent.
198 > */
199 > export function readUsageInfoMeta(usage: UsageInfo | undefined): UsageInfoMeta {
200 const meta = usage?._meta;
201 if (!meta) {
227 return result;
228 }
230 function readAutoModeResolvedInfo(value: unknown): IAutoModeResolvedInfo | undefined {
231 if (!value || typeof value !== 'object' || Array.isArray(value)) {
258 return result;
259 }
261 function readContextAttribution(value: unknown): IContextAttributionData | undefined {
262 if (!value || typeof value !== 'object' || Array.isArray(value)) {
295 return { totalTokens: raw['totalTokens'] as number, entries, compactions };
296 }
298 function filterStringAttributes(raw: Record<string, unknown>): Record<string, string | undefined> {
299 const result: Record<string, string | undefined> = {};
305 return result;
306 }
308 > export {
309 > ChangesetOperationTargetKind, type ChangesetOperationFollowUp, type ChangesetOperationTarget
310 > } from './protocol/commands.js';
311 >
312 > // Canonical chat-input type names (the protocol renamed the former
313 > // `SessionInput*` types to `ChatInput*` when input requests moved onto the
314 > // chat channel). Re-exported here so consumers can import them from the glue
315 > // layer alongside the legacy `SessionInput*` aliases above.
316 > export {
317 > ChatInputAnswerState,
318 > ChatInputAnswerValueKind,
319 > ChatInputQuestionKind,
320 > ChatInputResponseKind,
321 > type ChatInputAnswer,
322 > type ChatInputOption,
323 > type ChatInputQuestion,
324 > type ChatInputRequest,
325 > type InputRequestResponsePart,
326 > } from './protocol/state.js';
327 >
328 > // ---- File edit kind ---------------------------------------------------------
329 >
330 > /**
331 > * The kind of file edit operation. Derived from the presence/absence of
332 > * `before`/`after` in {@link ToolResultFileEditContent}.
333 > */
334 > export const enum FileEditKind {
335 > /** Content edit (same file URI, different content). */
336 > Edit = 'edit',
337 > /** File creation (no before state). */
338 > Create = 'create',
339 > /** File deletion (no after state). */
340 > Delete = 'delete',
341 > /** File rename/move (different before and after URIs). */
342 > Rename = 'rename',
343 > }
344 >
345 > // ---- Well-known URIs --------------------------------------------------------
346 >
347 > /** URI for the root state subscription. */
348 > export const ROOT_STATE_URI = 'ahp-root://';
349 >
350 > /** Scheme used by {@link ROOT_STATE_URI}. */
351 > export const AHP_ROOT_SCHEME = 'ahp-root';
352 >
353 > /** Scheme used by resource-watch channel URIs (`ahp-resource-watch:/<encoded>`). */
354 > export const AHP_RESOURCE_WATCH_SCHEME = 'ahp-resource-watch';
355 >
356 > /**
357 > * Encode a resource-watch descriptor into its canonical channel URI. The
358 > * descriptor is serialised into the URI path so the receiver can recover
359 > * the watch parameters without any server-side bookkeeping — subscribe is
360 > * the only point where state is materialised (an `IFileService` watcher
361 > * is attached on the first subscriber and held through a grace window
362 > * after the last drops).
363 > */
364 > export function buildResourceWatchChannelUri(descriptor: {
365 readonly root: string;
366 readonly recursive?: boolean;
380 return `${AHP_RESOURCE_WATCH_SCHEME}://r/${json}`;
381 }
383 > /**
384 > * Inverse of {@link buildResourceWatchChannelUri}. Returns `undefined` if
385 > * `uri` is not a well-formed `ahp-resource-watch:` URI — callers should
386 > * surface that as a not-found error to the client.
387 > */
388 > export function parseResourceWatchChannelUri(uri: string): {
389 root: string;
390 recursive: boolean;
421 }
422 }
424 > /** Returns `true` when `uri` identifies a resource-watch channel. */
425 > export function isAhpResourceWatchChannel(uri: string): boolean {
426 try {
427 return ResourceURI.parse(uri).scheme === AHP_RESOURCE_WATCH_SCHEME;
430 }
431 }
433 > /**
434 > * Returns `true` when `uri` identifies the root channel, regardless of
435 > * whether the caller passes the canonical wire form (`'ahp-root://'`) or a
436 > * variant that has been round-tripped through the workbench {@link URI} class
437 > * (which normalizes the authority-less form to `'ahp-root:'`). Always prefer
438 > * this helper over a direct `=== ROOT_STATE_URI` comparison so the two
439 > * spellings stay interchangeable.
440 > */
441 > export function isAhpRootChannel(uri: string): boolean {
442 if (uri === ROOT_STATE_URI) {
443 return true;
449 }
450 }
452 > /**
453 > * Mints a session-unique opaque id for a customization, derived from its
454 > * source URI and (when present) its `range` within the source. Plugins MAY
455 > * declare multiple children (e.g. MCP servers, hooks) inside the same
456 > * manifest file; including the range disambiguates them without an extra
457 > * mapping table.
458 > *
459 > * The range is appended as a reserved `#range=` query-style suffix; any
460 > * existing `#` in the URI is percent-encoded first so a source URI that
461 > * already contains a fragment cannot collide with a ranged id.
462 > */
463 > export function customizationId(uri: string, range?: TextRange): string {
464 if (!range) {
465 return uri;
468 return `${safeUri}#range=${range.start.line}:${range.start.character}-${range.end.line}:${range.end.character}`;
469 }
471 > // ---- VS Code-specific derived types -----------------------------------------
472 >
473 > /**
474 > * A tool call in a terminal state, stored in completed turns.
475 > */
476 > export type ICompletedToolCall = ToolCallCompletedState | ToolCallCancelledState;
477 >
478 > /**
479 > * Derived status type for the tool call lifecycle.
480 > */
481 > export type ToolCallStatusString = ToolCallState['status'];
482 >
483 > // ---- Tool output helper -----------------------------------------------------
484 >
485 > /**
486 > * Extracts a plain-text tool output string from a tool call result's `content`
487 > * array. Joins all text-type content parts into a single string.
488 > *
489 > * Returns `undefined` if there are no text content parts.
490 > */
491 > export function getToolOutputText(result: ToolCallResult): string | undefined {
492 if (!result.content || result.content.length === 0) {
493 return undefined;
504 return textParts.map(p => p.text).join('\n');
505 }
507 > /**
508 > * Extracts file edit content entries from a tool call result's `content` array.
509 > * Returns an empty array if there are no file edit content parts.
510 > */
511 > export function getToolFileEdits(result: ToolCallResult): ToolResultFileEditContent[] {
512 if (!result.content || result.content.length === 0) {
513 return [];
521 return edits;
522 }
524 > /**
525 > * Extracts the first subagent content entry from a tool call's `content` array.
526 > * Works with both completed tool call results and running tool call states.
527 > * Returns `undefined` if there are no subagent content parts.
528 > */
529 > export function getToolSubagentContent(result: { content?: readonly ToolResultContent[] }): ToolResultSubagentContent | undefined {
530 if (!result.content || result.content.length === 0) {
531 return undefined;
538 return undefined;
539 }
541 > // ---- Subagent URI helpers ---------------------------------------------------
542 >
543 > const SUBAGENT_URI_SEGMENT = 'subagent';
544 > const SUBAGENT_URI_MARKER = `/${SUBAGENT_URI_SEGMENT}/`;
545 > const SUBAGENT_URI_PATH_REGEX = /^(?<parentPath>.+)\/subagent\/(?<toolCallId>.+)$/;
546 >
547 function asResourceUri(uri: ProtocolURI | ResourceURI): ResourceURI {
548 return typeof uri === 'string' ? ResourceURI.parse(uri) : uri;
549 }
551 function getSubagentBasePath(parentSession: ProtocolURI | ResourceURI): { parent: ResourceURI; path: string } {
552 const parent = asResourceUri(parentSession);
554 return { parent, path: `${parentPath}${SUBAGENT_URI_MARKER}` };
555 }
557 > /**
558 > * Builds a subagent session URI from a parent session URI and tool call ID.
559 > * Convention: `{parentSessionUri}/subagent/{toolCallId}`
560 > */
561 > export function buildSubagentSessionUri(parentSession: ProtocolURI | ResourceURI, toolCallId: string): string {
562 const { parent, path } = getSubagentBasePath(parentSession);
563 return parent.with({ path: `${path}${toolCallId}` }).toString();
564 }
566 > /**
567 > * Parses a subagent session URI into its parent session URI and tool call ID.
568 > * Returns `undefined` if the URI does not follow the subagent convention.
569 > */
570 > export function parseSubagentSessionUri(uri: ProtocolURI | ResourceURI): { parentSession: ResourceURI; toolCallId: string } | undefined {
571 const resource = asResourceUri(uri);
572 const match = SUBAGENT_URI_PATH_REGEX.exec(resource.path);
579 };
580 }
582 > /**
583 > * Returns whether a session URI represents a subagent session.
584 > */
585 > export function isSubagentSession(uri: ProtocolURI | ResourceURI): boolean {
586 return parseSubagentSessionUri(uri) !== undefined;
587 }
589 > /**
590 > * Builds the string prefix used by the state manager for cached subagent sessions.
591 > */
592 > export function buildSubagentSessionUriPrefix(parentSession: ProtocolURI | ResourceURI): string {
593 const { parent, path } = getSubagentBasePath(parentSession);
594 return parent.with({ path }).toString();
595 }
597 > // ---- Factory helpers --------------------------------------------------------
598 >
599 > export function createRootState(): RootState {
600 return {
601 agents: [],
603 };
604 }
606 > /**
607 > * Creates the initial flat {@link SessionState} for a session from its
608 > * root-channel {@link SessionSummary} catalog entry. Session metadata
609 > * ({@link SessionMetadata}) — and the shared `_meta` bag — are inlined directly
610 > * onto the state.
611 > */
612 > export function createSessionState(summary: SessionSummary): SessionState {
613 const state: SessionState = {
614 provider: summary.provider,
627 return state;
628 }
630 > /**
631 > * Creates an empty {@link ChatState} for a chat. The summary fields are
632 > * denormalized onto the chat state per the protocol contract; callers pass
633 > * the chat's catalog summary and this seeds an empty conversation.
634 > */
635 > export function createChatState(summary: ChatSummary): ChatState {
636 return {
637 resource: summary.resource,
648 };
649 }
651 > /**
652 > * Derives the default-chat {@link ChatSummary} for a session from its
653 > * {@link SessionSummary}. The default chat inherits the session's title,
654 > * status, activity and working directory, and is marked as a
655 > * {@link ChatOriginKind.User | user-originated} chat. Both the session and
656 > * chat `modifiedAt` are ISO-8601 strings, so it is carried over directly.
657 > */
658 > export function createDefaultChatSummary(session: SessionSummary, chatUri: ProtocolURI): ChatSummary {
659 const summary: ChatSummary = {
660 resource: chatUri,
675 return summary;
676 }
678 > /** Activity bits (0-4) of {@link SessionStatus}; the high bits carry orthogonal flags (IsRead / IsArchived). */
679 > const STATUS_ACTIVITY_MASK = (1 << 5) - 1;
680 >
681 > /** Whether the active turn has a `PendingConfirmation` tool call auto-approved by the session's bypass setting. */
682 function hasAutoApprovedPendingConfirmation(state: ChatState): boolean {
683 return !!state.activeTurn?.responseParts.some(part =>
687 );
688 }
690 > /** Whether the chat is genuinely blocked on user input (an open input request, an auth-required tool, or a non-auto-approved confirmation gate). */
691 function chatAwaitsUserInput(state: ChatState): boolean {
692 return !!state.activeTurn?.responseParts.some(part => {
708 });
709 }
711 > /**
712 > * Projects a chat's status for session-summary aggregation, demoting an
713 > * `InputNeeded` back to `InProgress` only when it is caused solely by an
714 > * auto-approved confirmation — otherwise a session with bypass approvals flashes
715 > * "input needed" in the sessions list while an auto-approved tool runs.
716 > */
717 function chatSummaryStatus(state: ChatState): SessionStatus {
718 const status = state.status;
728 return status;
729 }
731 > /**
732 > * Derives a {@link ChatSummary} from a fully-populated {@link ChatState} by
733 > * projecting out the denormalized summary fields. Used to keep the parent
734 > * session's `chats` catalog in sync with a chat's denormalized state.
735 > */
736 > export function chatSummaryFromState(state: ChatState): ChatSummary {
737 const summary: ChatSummary = {
738 resource: state.resource,
748 return summary;
749 }
751 > /**
752 > * The effective interactivity of a chat given its session's archived state.
753 > *
754 > * `interactivity` is the general read-only mechanism (e.g. subagent worker
755 > * chats are `ReadOnly`). An archived session is read-only too, so its
756 > * interactive chats are downgraded to `ReadOnly`. `Hidden` chats stay hidden —
757 > * archiving only downgrades `Full` chats. Absent interactivity defaults to
758 > * `Full` for backward compatibility.
759 > *
760 > * The host uses this to enforce read-only turns off a single signal
761 > * ({@link isChatReadOnly}) rather than special-casing archived; the same rule
762 > * is mirrored client-side to hide the composer.
763 > */
764 > export function effectiveChatInteractivity(interactivity: ChatInteractivity | undefined, sessionArchived: boolean): ChatInteractivity {
765 if (interactivity === ChatInteractivity.Hidden) {
766 return ChatInteractivity.Hidden;
771 return interactivity ?? ChatInteractivity.Full;
772 }
774 > /**
775 > * Whether a chat rejects user-dispatched turns, given its own interactivity and
776 > * its session's archived state. `true` for `ReadOnly` chats (including archived
777 > * sessions' interactive chats). See {@link effectiveChatInteractivity}.
778 > */
779 > export function isChatReadOnly(interactivity: ChatInteractivity | undefined, sessionArchived: boolean): boolean {
780 return effectiveChatInteractivity(interactivity, sessionArchived) === ChatInteractivity.ReadOnly;
781 }
783 > export function createActiveTurn(id: string, message: Message, startedAt: string): ActiveTurn {
784 return {
785 id,
790 };
791 }
793 > export const enum StateComponents {
794 > Root,
795 > Session,
796 > Chat,
797 > Terminal,
798 > Changeset,
799 > Annotations,
800 > }
801 >
802 > export type ComponentToState = {
803 > [StateComponents.Root]: RootState;
804 > [StateComponents.Session]: SessionState;
805 > [StateComponents.Chat]: ChatState;
806 > [StateComponents.Terminal]: TerminalState;
807 > [StateComponents.Changeset]: ChangesetState;
808 > [StateComponents.Annotations]: AnnotationsState;
809 > };
810 >
811 > // ---- Default chat URI helpers ----------------------------------------------
812 >
813 > /** Scheme used by chat channel URIs (`ahp-chat://...`). */
814 > export const AHP_CHAT_SCHEME = 'ahp-chat';
815 >
816 > /** Chat id of the default chat that every session owns. */
817 > export const DEFAULT_CHAT_ID = 'default';
818 >
819 > /**
820 > * Derives the deterministic channel URI for a chat within a session. Every chat
821 > * — the default chat and any additional peer chats — encodes its owning session
822 > * URI into the path so producers and consumers can recover the session without a
823 > * lookup table (see {@link parseChatUri}). The chat id is carried in the URI
824 > * authority.
825 > *
826 > * `ahp-chat://<chatId>/<base64(sessionUri)>`
827 > */
828 > export function buildChatUri(sessionUri: ProtocolURI | ResourceURI, chatId: string): string {
829 const session = typeof sessionUri === 'string' ? sessionUri : sessionUri.toString();
830 const encoded = encodeBase64(VSBuffer.fromString(session), false, true);
831 return `${AHP_CHAT_SCHEME}://${chatId}/${encoded}`;
832 }
834 > /**
835 > * Derives the deterministic default-chat channel URI for a session. While the
836 > * protocol allows a session to contain many chats, every session always owns a
837 > * default chat whose URI is derived from the owning session URI so producers and
838 > * consumers can compute it without a lookup table.
839 > *
840 > * The session URI is encoded into the path so {@link parseChatUri} can recover
841 > * it.
842 > */
843 > export function buildDefaultChatUri(sessionUri: ProtocolURI | ResourceURI): string {
844 return buildChatUri(sessionUri, DEFAULT_CHAT_ID);
845 }
847 > const SUBAGENT_CHAT_ID = 'subagent';
848 >
849 > export function isSubagentChatUri(uri: ProtocolURI | ResourceURI): boolean {
850 const parsed = typeof uri === 'string' ? ResourceURI.parse(uri) : uri;
851 return parsed.scheme === AHP_CHAT_SCHEME && parsed.authority === SUBAGENT_CHAT_ID;
852 }
854 > export function buildSubagentChatUri(sessionUri: ProtocolURI | ResourceURI, toolCallId: string): string {
855 const session = typeof sessionUri === 'string' ? sessionUri : sessionUri.toString();
856 const encoded = encodeBase64(VSBuffer.fromString(session), false, true);
857 return `${AHP_CHAT_SCHEME}://${SUBAGENT_CHAT_ID}/${encoded}/${encodeURIComponent(toolCallId)}`;
858 }
860 > /**
861 > * Inverse of {@link buildChatUri}: recovers the owning session URI and chat id
862 > * from any chat channel URI. Returns `undefined` when `uri` is not a well-formed
863 > * chat URI.
864 > */
865 > export function parseChatUri(uri: ProtocolURI | ResourceURI): { session: string; chatId: string } | undefined {
866 let parsed: ResourceURI;
867 try {
891 }
892 }
894 > /**
895 > * Inverse of {@link buildDefaultChatUri}: recovers the owning session URI from a
896 > * chat channel URI. Returns `undefined` when `uri` is not a well-formed chat URI.
897 > * Accepts any chat URI (default or additional) so callers that only need the
898 > * parent session can use it uniformly.
899 > */
900 > export function parseDefaultChatUri(uri: ProtocolURI | ResourceURI): string | undefined {
901 return parseChatUri(uri)?.session;
902 }
904 > export function parseRequiredSessionUriFromChatUri(uri: ProtocolURI | ResourceURI): string {
905 const session = parseDefaultChatUri(uri);
906 if (session === undefined) {
909 return session;
910 }
912 > /** Returns `true` when `uri` is the default chat of its session. */
913 > export function isDefaultChatUri(uri: ProtocolURI | ResourceURI): boolean {
914 return parseChatUri(uri)?.chatId === DEFAULT_CHAT_ID;
915 }
917 > /**
918 > * Resolves a feature-level `(session, chat)` pair to the single chat URI used by
919 > * the agent session/chat surface. A session always owns a DEFAULT chat addressed
920 > * by the session URI itself; additional (peer) chats are addressed by their own
921 > * chat channel URIs. This is the one place default-chat resolution lives so
922 > * agents never re-derive "is this the default chat?".
923 > */
924 > export function resolveChatUri(session: ResourceURI, chat: ResourceURI): ResourceURI {
925 return isDefaultChatUri(chat) ? session : chat;
926 }
928 > /** Returns `true` when `uri` identifies a chat channel. */
929 > export function isAhpChatChannel(uri: string): boolean {
930 try {
931 return ResourceURI.parse(uri).scheme === AHP_CHAT_SCHEME;
934 }
935 }
937 > // ---- Session + default-chat composite --------------------------------------
938 >
939 > /**
940 > * A single chat's effective session context: the shared {@link SessionState}
941 > * (working directories, active clients, config, customizations/MCP scope, …)
942 > * resolved for one chat and merged with that chat's conversation contents.
943 > *
944 > * The protocol moved turns and pending state off the session and onto a
945 > * per-chat channel, and lets a chat override the session's working directories
946 > * with a subset (e.g. {@link ChatState.workingDirectories}) and carry its own
947 > * read-only {@link ChatState.primaryWorkingDirectory | primary} (fixed at chat
948 > * creation — the session has no primary). This composite recombines the session
949 > * with one of its chats — default or peer — so consumers read the chat's
950 > * effective context and conversation through one object without walking back to
951 > * the session to re-derive shared state. The {@link ISessionWithDefaultChat.workingDirectories}
952 > * carry the chat's *effective* working directories (its own subset override when
953 > * present, else the session's full set); {@link ISessionWithDefaultChat.primaryWorkingDirectory}
954 > * is the chat's own primary.
955 > */
956 > export interface ISessionWithDefaultChat extends SessionState {
957 > /** The chat's read-only primary working directory (fixed at chat creation). */
958 > primaryWorkingDirectory?: ProtocolURI;
959 > /** Completed turns of this chat. */
960 > turns: Turn[];
961 > /** Currently in-progress turn of this chat. */
962 > activeTurn?: ActiveTurn;
963 > /** Steering message pending on this chat. */
964 > steeringMessage?: PendingMessage;
965 > /** Queued messages pending on this chat. */
966 > queuedMessages?: PendingMessage[];
967 > /** Draft input of this chat. */
968 > draft?: Message;
969 > }
970 >
971 > /**
972 > * Projects a {@link SessionState} and one of its {@link ChatState | chats}
973 > * (default or peer) into that chat's {@link ISessionWithDefaultChat | effective
974 > * session context}. Per-chat overrides (the working-directories subset and the
975 > * chat's own primary) are layered over the session defaults, and the
976 > * conversation fields are taken from the chat. When the chat state is absent
977 > * (e.g. not yet hydrated) the conversation fields default to empty and the
978 > * session defaults apply.
979 > */
980 > export function mergeSessionWithDefaultChat(session: SessionState, chat: ChatState | undefined): ISessionWithDefaultChat {
981 return {
982 ...session,
990 };
991 }
993 > /**
994 > * Resolves the active turn of a session's default chat, if any.
995 > */
996 > export function getActiveTurn(chat: ChatState | undefined): ActiveTurn | undefined {
997 return chat?.activeTurn;
998 }
1000 > /**
1001 > * Resolves the default chat's catalog summary from a session, if present.
1002 > */
1003 > export function getDefaultChat(session: SessionState): ChatSummary | undefined {
1004 if (session.defaultChat !== undefined) {
1005 const match = session.chats.find(c => c.resource === session.defaultChat);
1010 return session.chats[0];
1011 }
1013 > // ---- SessionMeta accessors -------------------------------------------------
1014 >
1015 > /**
1016 > * VS Code-side alias for the protocol's open `_meta` property bag on
1017 > * {@link SessionState}. Keys SHOULD be namespaced (e.g. `git`, `vscode.foo`)
1018 > * to avoid collisions; values MUST be JSON-serializable.
1019 > */
1020 > export type SessionMeta = Record<string, unknown>;
1021 >
1022 > /**
1023 > * VS Code-side alias for the protocol's open `_meta` property bag on
1024 > * {@link SessionSummary}. Keys SHOULD be namespaced (e.g. `git`, `vscode.foo`)
1025 > * to avoid collisions; values MUST be JSON-serializable.
1026 > */
1027 > export type SessionSummaryMeta = Record<string, unknown>;
1028 >
1029 > /**
1030 > * Reserved key under {@link SessionMeta} for the well-known git-state
1031 > * payload. Value at this key, when present, MUST be shaped like
1032 > * {@link ISessionGitState}. This is a VS Code-specific convention layered
1033 > * on top of the protocol's generic `_meta` bag — the protocol itself does
1034 > * not know about git state.
1035 > */
1036 > export const SESSION_META_GIT_KEY = 'git';
1037 >
1038 > /**
1039 > * Reserved key under {@link SessionMeta} for the well-known GitHub-state
1040 > * payload. Value at this key, when present, MUST be shaped like
1041 > * {@link ISessionGitHubState}. This is a VS Code-specific convention layered
1042 > * on top of the protocol's generic `_meta` bag — the protocol itself does
1043 > * not know about GitHub state.
1044 > */
1045 > export const SESSION_META_GITHUB_KEY = 'github';
1046 >
1047 > export const SESSION_META_PROMPT_CACHE_KEY = 'vscode.promptCache';
1048 >
1049 > /** Latest known prompt-cache state for the model active in an agent session. */
1050 > export interface ISessionPromptCacheState {
1051 > readonly modelId: string;
1052 > readonly cacheExpiresAt: string;
1053 > }
1054 >
1055 > /** Reads the latest known prompt-cache state from session metadata. */
1056 > export function readSessionPromptCacheState(meta: SessionMeta | undefined): ISessionPromptCacheState | undefined {
1057 const value = meta?.[SESSION_META_PROMPT_CACHE_KEY];
1058 if (!value || typeof value !== 'object' || Array.isArray(value)) {
1064 : undefined;
1065 }
1067 > /** Returns session metadata with the prompt-cache slot updated or removed. */
1068 > export function withSessionPromptCacheState(meta: SessionMeta | undefined, promptCache: ISessionPromptCacheState | undefined): SessionMeta | undefined {
1069 const next: SessionMeta = { ...meta };
1070 if (promptCache) {
1075 return Object.keys(next).length > 0 ? next : undefined;
1076 }
1078 > /**
1079 > * Git state of a session's working directory, carried under
1080 > * {@link SessionMeta} at {@link SESSION_META_GIT_KEY}. Used by clients to
1081 > * drive source-control affordances (e.g. PR/merge buttons in the Agents
1082 > * app).
1083 > *
1084 > * All fields are optional — agents that do not track a particular field
1085 > * should omit it rather than send a placeholder, so clients can distinguish
1086 > * "unknown" from "known to be zero".
1087 > */
1088 > export interface ISessionGitState {
1089 > /** Whether the working directory has a `github.com` git remote. */
1090 > readonly hasGitHubRemote?: boolean;
1091 > /** Current branch name. */
1092 > readonly branchName?: string;
1093 > /** Base branch the work targets (e.g. `main`). */
1094 > readonly baseBranchName?: string;
1095 > /** Upstream tracking branch (e.g. `origin/feature`). */
1096 > readonly upstreamBranchName?: string;
1097 > /** Number of commits the upstream branch has ahead of the local branch. */
1098 > readonly incomingChanges?: number;
1099 > /** Number of commits the local branch has ahead of the upstream branch. */
1100 > readonly outgoingChanges?: number;
1101 > /** Number of files with uncommitted changes. */
1102 > readonly uncommittedChanges?: number;
1103 > /** GitHub repository owner parsed from the working copy's GitHub remote (preferring `origin`, falling back to the first GitHub remote). */
1104 > readonly githubOwner?: string;
1105 > /** GitHub repository name parsed from the working copy's GitHub remote (preferring `origin`, falling back to the first GitHub remote). */
1106 > readonly githubRepo?: string;
1107 > }
1108 >
1109 > /**
1110 > * GitHub state of a session, carried under {@link SessionMeta} at
1111 > * {@link SESSION_META_GITHUB_KEY}. Used by clients to drive GitHub-specific
1112 > * affordances (e.g. PR/merge buttons in the Agents app).
1113 > *
1114 > * All fields are optional — agents that do not track a particular field
1115 > * should omit it rather than send a placeholder, so clients can distinguish
1116 > * "unknown" from "known to be zero".
1117 > */
1118 > export interface ISessionGitHubState {
1119 > /** The owner of the GitHub repository. */
1120 > readonly owner?: string;
1121 > /** The name of the GitHub repository. */
1122 > readonly repo?: string;
1123 > /** The URL of the GitHub pull request. */
1124 > readonly pullRequestUrl?: string;
1125 > }
1126 >
1127 > /**
1128 > * Reads the well-known git-state payload from {@link SessionMeta}, if
1129 > * present. Returns `undefined` when the meta bag is absent or the value at
1130 > * the git key is not a plain object (e.g. an array or a primitive).
1131 > * Individual fields with wrong types are silently dropped so partial state
1132 > * still propagates.
1133 > *
1134 > * Unlike the other typed readers, this takes the raw {@link SessionMeta} value
1135 > * rather than its parent {@link SessionState}: the sessions provider stores and
1136 > * reads a detached meta snapshot without retaining the owning state.
1137 > */
1138 > export function readSessionGitState(meta: SessionMeta | undefined): ISessionGitState | undefined {
1139 const value = meta?.[SESSION_META_GIT_KEY];
1140 if (!value || typeof value !== 'object' || Array.isArray(value)) {
1164 return result;
1165 }
1167 > /**
1168 > * Returns a new {@link SessionMeta} with the git-state payload set to
1169 > * `gitState`, or with the git slot removed if `gitState` is `undefined`.
1170 > * Returns `undefined` if the result would be empty.
1171 > */
1172 > export function withSessionGitState(meta: SessionMeta | undefined, gitState: ISessionGitState | undefined): SessionMeta | undefined {
1173 const next: { [key: string]: unknown } = { ...meta };
1174 if (gitState !== undefined) {
1179 return Object.keys(next).length > 0 ? next : undefined;
1180 }
1182 > /**
1183 > * Reads the well-known GitHub state payload from {@link SessionSummaryMeta}, if
1184 > * present. Returns `undefined` when the meta bag is absent or the value at the
1185 > * GitHub key is not a plain object (e.g. an array or a primitive).
1186 > * Individual fields with wrong types are silently dropped so partial state
1187 > * still propagates.
1188 > *
1189 > * Unlike the other typed readers, this takes the raw {@link SessionSummaryMeta}
1190 > * value rather than its parent {@link SessionState}: the sessions provider stores and
1191 > * reads a detached meta snapshot without retaining the owning state.
1192 > */
1193 > export function readSessionGitHubState(meta: SessionSummaryMeta | undefined): ISessionGitHubState | undefined {
1194 const value = meta?.[SESSION_META_GITHUB_KEY];
1195 if (!value || typeof value !== 'object' || Array.isArray(value)) {
1208 return result;
1209 }
1211 > /**
1212 > * Returns a new {@link SessionSummaryMeta} with the GitHub-state payload set to
1213 > * `gitHubState`, or with the GitHub slot removed if `gitHubState` is `undefined`.
1214 > * Returns `undefined` if the result would be empty.
1215 > */
1216 > export function withSessionGitHubState(meta: SessionSummaryMeta | undefined, gitHubState: ISessionGitHubState | undefined): SessionSummaryMeta | undefined {
1217 const next: { [key: string]: unknown } = { ...meta };
1218 if (gitHubState !== undefined) {
1223 return Object.keys(next).length > 0 ? next : undefined;
1224 }
1226 > /**
1227 > * Reserved key under {@link SessionSummaryMeta} recording how deeply a session
1228 > * was spawned via the `create_session` host tool (0 for a top-level, user-created
1229 > * session). Used to bound recursive session creation. VS Code-specific convention
1230 > * layered on top of the protocol's generic `_meta` bag.
1231 > */
1232 > export const SESSION_META_SPAWN_DEPTH_KEY = 'agentHost/sessionSpawnDepth';
1233 >
1234 > /**
1235 > * Reads the `create_session` spawn depth from a {@link SessionSummaryMeta} bag,
1236 > * returning `0` when the key is absent or not a finite number.
1237 > */
1238 > export function readSessionSpawnDepth(meta: SessionSummaryMeta | undefined): number {
1239 const value = meta?.[SESSION_META_SPAWN_DEPTH_KEY];
1240 return typeof value === 'number' && Number.isFinite(value) ? value : 0;
1241 }
1243 > /**
1244 > * Returns a new {@link SessionSummaryMeta} with the `create_session` spawn depth
1245 > * set to `depth`, preserving any other keys in the bag.
1246 > */
1247 > export function withSessionSpawnDepth(meta: SessionSummaryMeta | undefined, depth: number): SessionSummaryMeta {
1248 return { ...meta, [SESSION_META_SPAWN_DEPTH_KEY]: depth };
1249 }
1251 > /**
1252 > * Reserved key under {@link SessionSummaryMeta} marking a session as
1253 > * workspace-less: a session with no workspace/folder binding (surfaced in the
1254 > * UI as a "Quick Chat"). Carried on the summary bag (not the full state) so
1255 > * clients can group/style such sessions in session lists without subscribing to
1256 > * full session state. VS Code-specific convention layered on the protocol's
1257 > * generic `_meta` bag.
1258 > */
1259 > export const SESSION_META_WORKSPACELESS_KEY = 'workspaceless';
1260 >
1261 > /**
1262 > * Session-database metadata key recording whether a session is workspace-less (a
1263 > * workspace-less chat). Owned by the AH service: `AgentService` writes it centrally at
1264 > * create/materialize and overlays it onto every agent's summary `_meta` in
1265 > * `listSessions`; agents only read it (e.g. to pick the workspace-less system prompt
1266 > * on resume) and never persist it themselves.
1267 > */
1268 > export const AH_META_WORKSPACELESS_DB_KEY = 'agentHost.workspaceless';
1269 >
1270 > /**
1271 > * Session-database metadata key recording whether a session is archived. Written by
1272 > * the AH orchestrator (`AgentSideEffects` on `SessionIsArchivedChanged`) and read by
1273 > * both the orchestrator (`AgentService` restore/list) and agents (e.g. `CopilotAgent`
1274 > * decides whether to recreate a missing worktree vs. resume read-only for history).
1275 > * {@link AH_META_IS_DONE_DB_KEY} is the legacy name kept for sessions persisted before
1276 > * the rename; readers fall back to it when {@link AH_META_IS_ARCHIVED_DB_KEY} is absent.
1277 > */
1278 > export const AH_META_IS_ARCHIVED_DB_KEY = 'isArchived';
1279 >
1280 > /** Legacy metadata key for the archived flag; see {@link AH_META_IS_ARCHIVED_DB_KEY}. */
1281 > export const AH_META_IS_DONE_DB_KEY = 'isDone';
1282 >
1283 > /**
1284 > * Reads the workspace-less marker from {@link SessionSummaryMeta}. Returns
1285 > * `true` only when the well-known key is present and set to boolean `true`.
1286 > */
1287 > export function readSessionWorkspaceless(meta: SessionSummaryMeta | undefined): boolean {
1288 return meta?.[SESSION_META_WORKSPACELESS_KEY] === true;
1289 }
1291 > /**
1292 > * Returns a new {@link SessionSummaryMeta} with the workspace-less marker set,
1293 > * or with the slot removed when `workspaceless` is `false`. Returns `undefined`
1294 > * if the result would be empty.
1295 > */
1296 > export function withSessionWorkspaceless(meta: SessionSummaryMeta | undefined, workspaceless: boolean): SessionSummaryMeta | undefined {
1297 const next: { [key: string]: unknown } = { ...meta };
1298 if (workspaceless) {
1303 return Object.keys(next).length > 0 ? next : undefined;
1304 }
1306 > // ---- RootState _meta accessors ---------------------------------------------
1307 >
1308 > /**
1309 > * VS Code-side alias for the protocol's open `_meta` property bag on
1310 > * {@link RootState}. Keys SHOULD be namespaced to avoid collisions; values MUST
1311 > * be JSON-serializable.
1312 > */
1313 > export type RootMeta = Record<string, unknown>;
1314 >
1315 > /**
1316 > * Reserved key under {@link RootMeta} for the well-known host-build payload.
1317 > * Value at this key, when present, MUST be shaped like {@link IHostBuildInfo}.
1318 > * This is a VS Code-specific convention layered on top of the protocol's
1319 > * generic `_meta` bag — the protocol itself does not know about build info.
1320 > */
1321 > export const ROOT_META_HOST_BUILD_KEY = 'hostBuild';
1322 >
1323 > /**
1324 > * Build information about the program hosting the agent host (the VS Code CLI),
1325 > * carried under {@link RootMeta} at {@link ROOT_META_HOST_BUILD_KEY}. Lets a
1326 > * client see which build is hosting it — useful when inspecting the output of a
1327 > * remote agent host.
1328 > *
1329 > * All fields except {@link version} are optional — a build that does not track
1330 > * a particular field should omit it.
1331 > */
1332 > export interface IHostBuildInfo {
1333 > /** Product version (e.g. `1.96.0`). */
1334 > readonly version: string;
1335 > /** Commit SHA of the build, if known. */
1336 > readonly commit?: string;
1337 > /** Build date (ISO 8601), if known. */
1338 > readonly date?: string;
1339 > /** Release quality (e.g. `stable`, `insider`), if known. */
1340 > readonly quality?: string;
1341 > }
1342 >
1343 > /**
1344 > * Derives {@link IHostBuildInfo} from the host's {@link IProductService}.
1345 > */
1346 > export function hostBuildInfoFromProduct(productService: IProductService): IHostBuildInfo {
1347 return {
1348 version: productService.version,
1352 };
1353 }
1355 > /**
1356 > * Reads the well-known host-build payload from {@link RootMeta}, if present.
1357 > * Returns `undefined` when the meta bag is absent or the value at the host-build
1358 > * key is not a plain object with a string `version`. Optional fields with wrong
1359 > * types are silently dropped.
1360 > */
1361 > export function readHostBuildInfo(state: RootState | undefined): IHostBuildInfo | undefined {
1362 const meta = state?._meta;
1363 const value = meta?.[ROOT_META_HOST_BUILD_KEY];
1377 return result;
1378 }
1380 > /**
1381 > * Returns a new {@link RootMeta} with the host-build payload set to
1382 > * `buildInfo`, or with the slot removed if `buildInfo` is `undefined`. Returns
1383 > * `undefined` if the result would be empty.
1384 > */
1385 > export function withHostBuildInfo(meta: RootMeta | undefined, buildInfo: IHostBuildInfo | undefined): RootMeta | undefined {
1386 const next: { [key: string]: unknown } = { ...meta };
1387 if (buildInfo !== undefined) {
1392 return Object.keys(next).length > 0 ? next : undefined;
1393 }
1395 > /**
1396 > * Formats {@link IHostBuildInfo} as a short single-line human-readable string,
1397 > * e.g. `1.96.0 (commit abc1234, 2024-01-02T03:04:05Z, insider)`.
1398 > */
1399 > export function formatHostBuildInfo(info: IHostBuildInfo): string {
1400 const details: string[] = [];
1401 if (info.commit) { details.push(`commit ${info.commit}`); }
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/workbench/contrib/testing/common/testTypes.ts 755 covered LOC · 45 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- testTypes.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IMarkdownString } from '../../../../base/common/htmlContent.js';
7 > import { MarshalledId } from '../../../../base/common/marshallingIds.js';
8 > import { URI, UriComponents } from '../../../../base/common/uri.js';
9 > import { IPosition, Position } from '../../../../editor/common/core/position.js';
10 > import { IRange, Range } from '../../../../editor/common/core/range.js';
11 > import { localize } from '../../../../nls.js';
12 > import { TestId } from './testId.js';
13 >
14 > export const enum TestResultState {
15 > Unset = 0,
16 > Queued = 1,
17 > Running = 2,
18 > Passed = 3,
19 > Failed = 4,
20 > Skipped = 5,
21 > Errored = 6
22 > }
23 >
24 > export const testResultStateToContextValues: { [K in TestResultState]: string } = {
25 > [TestResultState.Unset]: 'unset',
26 > [TestResultState.Queued]: 'queued',
27 > [TestResultState.Running]: 'running',
28 > [TestResultState.Passed]: 'passed',
29 > [TestResultState.Failed]: 'failed',
30 > [TestResultState.Skipped]: 'skipped',
31 > [TestResultState.Errored]: 'errored',
32 > };
33 >
34 > /** note: keep in sync with TestRunProfileKind in vscode.d.ts */
35 > export const enum ExtTestRunProfileKind {
36 > Run = 1,
37 > Debug = 2,
38 > Coverage = 3,
39 > }
40 >
41 > export const enum TestControllerCapability {
42 > Refresh = 1 << 1,
43 > CodeRelatedToTest = 1 << 2,
44 > TestRelatedToCode = 1 << 3,
45 > }
46 >
47 > export const enum TestRunProfileBitset {
48 > Run = 1 << 1,
49 > Debug = 1 << 2,
50 > Coverage = 1 << 3,
51 > HasNonDefaultProfile = 1 << 4,
52 > HasConfigurable = 1 << 5,
53 > SupportsContinuousRun = 1 << 6,
54 > }
55 >
56 > export const testProfileBitset = {
57 > [TestRunProfileBitset.Run]: localize('testing.runProfileBitset.run', 'Run'),
58 > [TestRunProfileBitset.Debug]: localize('testing.runProfileBitset.debug', 'Debug'),
59 > [TestRunProfileBitset.Coverage]: localize('testing.runProfileBitset.coverage', 'Coverage'),
60 > };
61 >
62 > /**
63 > * List of all test run profile bitset values.
64 > */
65 > export const testRunProfileBitsetList = [
66 > TestRunProfileBitset.Run,
67 > TestRunProfileBitset.Debug,
68 > TestRunProfileBitset.Coverage,
69 > TestRunProfileBitset.HasNonDefaultProfile,
70 > TestRunProfileBitset.HasConfigurable,
71 > TestRunProfileBitset.SupportsContinuousRun,
72 > ];
73 >
74 > /**
75 > * DTO for a controller's run profiles.
76 > */
77 > export interface ITestRunProfile {
78 > controllerId: string;
79 > profileId: number;
80 > label: string;
81 > group: TestRunProfileBitset;
82 > isDefault: boolean;
83 > tag: string | null;
84 > hasConfigurationHandler: boolean;
85 > supportsContinuousRun: boolean;
86 > }
87 >
88 > export interface ITestRunProfileReference {
89 > controllerId: string;
90 > profileId: number;
91 > group: TestRunProfileBitset;
92 > }
93 >
94 > /**
95 > * A fully-resolved request to run tests, passsed between the main thread
96 > * and extension host.
97 > */
98 > export interface ResolvedTestRunRequest {
99 > group: TestRunProfileBitset;
100 > targets: {
101 > testIds: string[];
102 > controllerId: string;
103 > profileId: number;
104 > }[];
105 > exclude?: string[];
106 > /** Whether this is a continuous test run */
107 > continuous?: boolean;
108 > /** Whether this was trigged by a user action in UI. Default=true */
109 > preserveFocus?: boolean;
110 > }
111 >
112 > /**
113 > * Request to the main thread to run a set of tests.
114 > */
115 > export interface ExtensionRunTestsRequest {
116 > id: string;
117 > include: string[];
118 > exclude: string[];
119 > controllerId: string;
120 > profile?: { group: TestRunProfileBitset; id: number };
121 > persist: boolean;
122 > preserveFocus: boolean;
123 > /** Whether this is a result of a continuous test run request */
124 > continuous: boolean;
125 > }
126 >
127 > /**
128 > * Request parameters a controller run handler. This is different than
129 > * {@link IStartControllerTests}. The latter is used to ask for one or more test
130 > * runs tracked directly by the renderer.
131 > *
132 > * This alone can be used to start an autorun, without a specific associated runId.
133 > */
134 > export interface ICallProfileRunHandler {
135 > controllerId: string;
136 > profileId: number;
137 > excludeExtIds: string[];
138 > testIds: string[];
139 > }
140 >
141 > export const isStartControllerTests = (t: ICallProfileRunHandler | IStartControllerTests): t is IStartControllerTests => ('runId' as keyof IStartControllerTests) in t;
142 >
143 > /**
144 > * Request from the main thread to run tests for a single controller.
145 > */
146 > export interface IStartControllerTests extends ICallProfileRunHandler {
147 > runId: string;
148 > }
149 >
150 > export interface IStartControllerTestsResult {
151 > error?: string;
152 > }
153 >
154 > /**
155 > * Location with a fully-instantiated Range and URI.
156 > */
157 > export interface IRichLocation {
158 > range: Range;
159 > uri: URI;
160 > }
161 >
162 > /** Subset of the IUriIdentityService */
163 > export interface ITestUriCanonicalizer {
164 > /** @link import('vs/platform/uriIdentity/common/uriIdentity').IUriIdentityService */
165 > asCanonicalUri(uri: URI): URI;
166 > }
167 >
168 > export namespace IRichLocation {
169 > export interface Serialize {
170 > range: IRange;
171 > uri: UriComponents;
172 > }
173 >
174 > export const serialize = (location: Readonly<IRichLocation>): Serialize => ({
175 range: location.range.toJSON(),
176 uri: location.uri.toJSON(),
177 });
178 > testTypes.ts
179 > export const deserialize = (uriIdentity: ITestUriCanonicalizer, location: Serialize): IRichLocation => ({
180 range: Range.lift(location.range),
181 uri: uriIdentity.asCanonicalUri(URI.revive(location.uri)),
182 });
183 > } testTypes.ts
184 >
185 > export const enum TestMessageType {
186 > Error,
187 > Output
188 > }
189 >
190 > export interface ITestMessageStackFrame {
191 > label: string;
192 > uri: URI | undefined;
193 > position: Position | undefined;
194 > }
195 >
196 > export namespace ITestMessageStackFrame {
197 > export interface Serialized {
198 > label: string;
199 > uri: UriComponents | undefined;
200 > position: IPosition | undefined;
201 > }
202 >
203 > export const serialize = (stack: Readonly<ITestMessageStackFrame>): Serialized => ({
204 label: stack.label,
205 uri: stack.uri?.toJSON(),
206 position: stack.position?.toJSON(),
207 });
208 > testTypes.ts
209 > export const deserialize = (uriIdentity: ITestUriCanonicalizer, stack: Serialized): ITestMessageStackFrame => ({
210 label: stack.label,
211 uri: stack.uri ? uriIdentity.asCanonicalUri(URI.revive(stack.uri)) : undefined,
212 position: stack.position ? Position.lift(stack.position) : undefined,
213 });
214 > } testTypes.ts
215 >
216 > export interface ITestErrorMessage {
217 > message: string | IMarkdownString;
218 > type: TestMessageType.Error;
219 > expected: string | undefined;
220 > actual: string | undefined;
221 > contextValue: string | undefined;
222 > location: IRichLocation | undefined;
223 > stackTrace: undefined | ITestMessageStackFrame[];
224 > }
225 >
226 > export namespace ITestErrorMessage {
227 > export interface Serialized {
228 > message: string | IMarkdownString;
229 > type: TestMessageType.Error;
230 > expected: string | undefined;
231 > actual: string | undefined;
232 > contextValue: string | undefined;
233 > location: IRichLocation.Serialize | undefined;
234 > stackTrace: undefined | ITestMessageStackFrame.Serialized[];
235 > }
236 >
237 > export const serialize = (message: Readonly<ITestErrorMessage>): Serialized => ({
238 message: message.message,
239 type: TestMessageType.Error,
244 stackTrace: message.stackTrace?.map(ITestMessageStackFrame.serialize),
245 });
246 > testTypes.ts
247 > export const deserialize = (uriIdentity: ITestUriCanonicalizer, message: Serialized): ITestErrorMessage => ({
248 message: message.message,
249 type: TestMessageType.Error,
254 stackTrace: message.stackTrace && message.stackTrace.map(s => ITestMessageStackFrame.deserialize(uriIdentity, s)),
255 });
256 > } testTypes.ts
257 >
258 > export interface ITestOutputMessage {
259 > message: string;
260 > type: TestMessageType.Output;
261 > offset: number;
262 > length: number;
263 > marker?: number;
264 > location: IRichLocation | undefined;
265 > }
266 >
267 > /**
268 > * Gets the TTY marker ID for either starting or ending
269 > * an ITestOutputMessage.marker of the given ID.
270 > */
271 > export const getMarkId = (marker: number, start: boolean) => `${start ? 's' : 'e'}${marker}`;
272 >
273 > export namespace ITestOutputMessage {
274 > export interface Serialized {
275 > message: string;
276 > offset: number;
277 > length: number;
278 > type: TestMessageType.Output;
279 > location: IRichLocation.Serialize | undefined;
280 > }
281 >
282 > export const serialize = (message: Readonly<ITestOutputMessage>): Serialized => ({
283 message: message.message,
284 type: TestMessageType.Output,
287 location: message.location && IRichLocation.serialize(message.location),
288 });
289 > testTypes.ts
290 > export const deserialize = (uriIdentity: ITestUriCanonicalizer, message: Serialized): ITestOutputMessage => ({
291 message: message.message,
292 type: TestMessageType.Output,
295 location: message.location && IRichLocation.deserialize(uriIdentity, message.location),
296 });
297 > } testTypes.ts
298 >
299 > export type ITestMessage = ITestErrorMessage | ITestOutputMessage;
300 >
301 > export namespace ITestMessage {
302 > export type Serialized = ITestErrorMessage.Serialized | ITestOutputMessage.Serialized;
303 >
304 > export const serialize = (message: Readonly<ITestMessage>): Serialized =>
305 message.type === TestMessageType.Error ? ITestErrorMessage.serialize(message) : ITestOutputMessage.serialize(message);
306 > testTypes.ts
307 > export const deserialize = (uriIdentity: ITestUriCanonicalizer, message: Serialized): ITestMessage =>
308 message.type === TestMessageType.Error ? ITestErrorMessage.deserialize(uriIdentity, message) : ITestOutputMessage.deserialize(uriIdentity, message);
309 > testTypes.ts
310 > export const isDiffable = (message: ITestMessage): message is ITestErrorMessage & { actual: string; expected: string } =>
311 message.type === TestMessageType.Error && message.actual !== undefined && message.expected !== undefined;
312 > } testTypes.ts
313 >
314 > export interface ITestTaskState {
315 > state: TestResultState;
316 > duration: number | undefined;
317 > messages: ITestMessage[];
318 > }
319 >
320 > export namespace ITestTaskState {
321 > export interface Serialized {
322 > state: TestResultState;
323 > duration: number | undefined;
324 > messages: ITestMessage.Serialized[];
325 > }
326 >
327 > export const serializeWithoutMessages = (state: ITestTaskState): Serialized => ({
328 state: state.state,
329 duration: state.duration,
330 messages: [],
331 });
332 > testTypes.ts
333 > export const serialize = (state: Readonly<ITestTaskState>): Serialized => ({
334 state: state.state,
335 duration: state.duration,
336 messages: state.messages.map(ITestMessage.serialize),
337 });
338 > testTypes.ts
339 > export const deserialize = (uriIdentity: ITestUriCanonicalizer, state: Serialized): ITestTaskState => ({
340 state: state.state,
341 duration: state.duration,
342 messages: state.messages.map(m => ITestMessage.deserialize(uriIdentity, m)),
343 });
344 > } testTypes.ts
345 >
346 > export interface ITestRunTask {
347 > id: string;
348 > name: string;
349 > running: boolean;
350 > ctrlId: string;
351 > }
352 >
353 > export interface ITestTag {
354 > readonly id: string;
355 > }
356 >
357 > const testTagDelimiter = '\0';
358 >
359 > export const namespaceTestTag =
360 > (ctrlId: string, tagId: string) => ctrlId + testTagDelimiter + tagId;
361 >
362 > export const denamespaceTestTag = (namespaced: string) => {
363 const index = namespaced.indexOf(testTagDelimiter);
364 return { ctrlId: namespaced.slice(0, index), tagId: namespaced.slice(index + 1) };
365 };
366 > testTypes.ts
367 > export interface ITestTagDisplayInfo {
368 > id: string;
369 > }
370 >
371 > /**
372 > * The TestItem from .d.ts, as a plain object without children.
373 > */
374 > export interface ITestItem {
375 > /** ID of the test given by the test controller */
376 > extId: string;
377 > label: string;
378 > tags: string[];
379 > busy: boolean;
380 > children?: never;
381 > uri: URI | undefined;
382 > range: Range | null;
383 > description: string | null;
384 > error: string | IMarkdownString | null;
385 > sortText: string | null;
386 > }
387 >
388 > export namespace ITestItem {
389 > export interface Serialized {
390 > extId: string;
391 > label: string;
392 > tags: string[];
393 > busy: boolean;
394 > children?: never;
395 > uri: UriComponents | undefined;
396 > range: IRange | null;
397 > description: string | null;
398 > error: string | IMarkdownString | null;
399 > sortText: string | null;
400 > }
401 >
402 > export const serialize = (item: Readonly<ITestItem>): Serialized => ({
403 extId: item.extId,
404 label: item.label,
412 sortText: item.sortText
413 });
414 > testTypes.ts
415 > export const deserialize = (uriIdentity: ITestUriCanonicalizer, serialized: Serialized): ITestItem => ({
416 extId: serialized.extId,
417 label: serialized.label,
425 sortText: serialized.sortText
426 });
427 > } testTypes.ts
428 >
429 > export const enum TestItemExpandState {
430 > NotExpandable,
431 > Expandable,
432 > BusyExpanding,
433 > Expanded,
434 > }
435 >
436 > /**
437 > * TestItem-like shape, but with an ID and children as strings.
438 > */
439 > export interface InternalTestItem {
440 > /** Controller ID from whence this test came */
441 > controllerId: string;
442 > /** Expandability state */
443 > expand: TestItemExpandState;
444 > /** Raw test item properties */
445 > item: ITestItem;
446 > }
447 >
448 > export namespace InternalTestItem {
449 > export interface Serialized {
450 > expand: TestItemExpandState;
451 > item: ITestItem.Serialized;
452 > }
453 >
454 > export const serialize = (item: Readonly<InternalTestItem>): Serialized => ({
455 expand: item.expand,
456 item: ITestItem.serialize(item.item)
457 });
458 > testTypes.ts
459 > export const deserialize = (uriIdentity: ITestUriCanonicalizer, serialized: Serialized): InternalTestItem => ({
460 // the `controllerId` is derived from the test.item.extId. It's redundant
461 // in the non-serialized InternalTestItem too, but there just because it's
465 item: ITestItem.deserialize(uriIdentity, serialized.item)
466 });
467 > } testTypes.ts
468 >
469 > /**
470 > * A partial update made to an existing InternalTestItem.
471 > */
472 > export interface ITestItemUpdate {
473 > extId: string;
474 > expand?: TestItemExpandState;
475 > item?: Partial<ITestItem>;
476 > }
477 >
478 > export namespace ITestItemUpdate {
479 > export interface Serialized {
480 > extId: string;
481 > expand?: TestItemExpandState;
482 > item?: Partial<ITestItem.Serialized>;
483 > }
484 >
485 > export const serialize = (u: Readonly<ITestItemUpdate>): Serialized => {
486 let item: Partial<ITestItem.Serialized> | undefined;
487 if (u.item) {
499 return { extId: u.extId, expand: u.expand, item };
500 };
501 > testTypes.ts
502 > export const deserialize = (u: Serialized): ITestItemUpdate => {
503 let item: Partial<ITestItem> | undefined;
504 if (u.item) {
515 return { extId: u.extId, expand: u.expand, item };
516 };
517 > testTypes.ts
518 > }
519 >
520 > export const applyTestItemUpdate = (internal: InternalTestItem | ITestItemUpdate, patch: ITestItemUpdate) => {
521 if (patch.expand !== undefined) {
522 internal.expand = patch.expand;
526 }
527 };
528 > testTypes.ts
529 > /** Request to an ext host to get followup messages for a test failure. */
530 > export interface TestMessageFollowupRequest {
531 > resultId: string;
532 > extId: string;
533 > taskIndex: number;
534 > messageIndex: number;
535 > }
536 >
537 > /** Request to an ext host to get followup messages for a test failure. */
538 > export interface TestMessageFollowupResponse {
539 > id: number;
540 > title: string;
541 > }
542 >
543 > /**
544 > * Test result item used in the main thread.
545 > */
546 > export interface TestResultItem extends InternalTestItem {
547 > /** State of this test in various tasks */
548 > tasks: ITestTaskState[];
549 > /** State of this test as a computation of its tasks */
550 > ownComputedState: TestResultState;
551 > /** Computed state based on children */
552 > computedState: TestResultState;
553 > /** Max duration of the item's tasks (if run directly) */
554 > ownDuration?: number;
555 > /** Whether this test item is outdated */
556 > retired?: boolean;
557 > }
558 >
559 > export namespace TestResultItem {
560 > /**
561 > * Serialized version of the TestResultItem. Note that 'retired' is not
562 > * included since all hydrated items are automatically retired.
563 > */
564 > export interface Serialized extends InternalTestItem.Serialized {
565 > tasks: ITestTaskState.Serialized[];
566 > ownComputedState: TestResultState;
567 > computedState: TestResultState;
568 > }
569 >
570 > export const serializeWithoutMessages = (original: TestResultItem): Serialized => ({
571 ...InternalTestItem.serialize(original),
572 ownComputedState: original.ownComputedState,
574 tasks: original.tasks.map(ITestTaskState.serializeWithoutMessages),
575 });
576 > testTypes.ts
577 > export const serialize = (original: Readonly<TestResultItem>): Serialized => ({
578 ...InternalTestItem.serialize(original),
579 ownComputedState: original.ownComputedState,
581 tasks: original.tasks.map(ITestTaskState.serialize),
582 });
583 > testTypes.ts
584 > export const deserialize = (uriIdentity: ITestUriCanonicalizer, serialized: Serialized): TestResultItem => ({
585 ...InternalTestItem.deserialize(uriIdentity, serialized),
586 ownComputedState: serialized.ownComputedState,
589 retired: true,
590 });
591 > } testTypes.ts
592 >
593 > export interface ISerializedTestResults {
594 > /** ID of these test results */
595 > id: string;
596 > /** Time the results were compelted */
597 > completedAt: number;
598 > /** Subset of test result items */
599 > items: TestResultItem.Serialized[];
600 > /** Tasks involved in the run. */
601 > tasks: { id: string; name: string | undefined; ctrlId: string; hasCoverage: boolean }[];
602 > /** Human-readable name of the test run. */
603 > name: string;
604 > /** Test trigger informaton */
605 > request: ResolvedTestRunRequest;
606 > }
607 >
608 > export interface ITestCoverage {
609 > files: IFileCoverage[];
610 > }
611 >
612 > export interface ICoverageCount {
613 > covered: number;
614 > total: number;
615 > }
616 >
617 > export namespace ICoverageCount {
618 > export const empty = (): ICoverageCount => ({ covered: 0, total: 0 });
619 > export const sum = (target: ICoverageCount, src: Readonly<ICoverageCount>) => {
620 target.covered += src.covered;
621 target.total += src.total;
622 };
623 > } testTypes.ts
624 >
625 > export interface IFileCoverage {
626 > id: string;
627 > uri: URI;
628 > testIds?: string[];
629 > statement: ICoverageCount;
630 > branch?: ICoverageCount;
631 > declaration?: ICoverageCount;
632 > }
633 >
634 > export namespace IFileCoverage {
635 > export interface Serialized {
636 > id: string;
637 > uri: UriComponents;
638 > testIds: string[] | undefined;
639 > statement: ICoverageCount;
640 > branch?: ICoverageCount;
641 > declaration?: ICoverageCount;
642 > }
643 >
644 > export const serialize = (original: Readonly<IFileCoverage>): Serialized => ({
645 id: original.id,
646 statement: original.statement,
650 uri: original.uri.toJSON(),
651 });
652 > testTypes.ts
653 > export const deserialize = (uriIdentity: ITestUriCanonicalizer, serialized: Serialized): IFileCoverage => ({
654 id: serialized.id,
655 statement: serialized.statement,
659 uri: uriIdentity.asCanonicalUri(URI.revive(serialized.uri)),
660 });
661 > testTypes.ts
662 > export const empty = (id: string, uri: URI): IFileCoverage => ({
663 id,
664 uri,
665 statement: ICoverageCount.empty(),
666 });
667 > } testTypes.ts
668 >
669 function serializeThingWithLocation<T extends { location?: Range | Position }>(serialized: T): T & { location?: IRange | IPosition } {
670 return {
673 };
674 }
675 > testTypes.ts
676 function deserializeThingWithLocation<T extends { location?: IRange | IPosition }>(serialized: T): T & { location?: Range | Position } {
677 serialized.location = serialized.location ? (Position.isIPosition(serialized.location) ? Position.lift(serialized.location) : Range.lift(serialized.location)) : undefined;
678 return serialized as T & { location?: Range | Position };
679 }
680 > testTypes.ts
681 > /** Number of recent runs in which coverage reports should be retained. */
682 > export const KEEP_N_LAST_COVERAGE_REPORTS = 3;
683 >
684 > export const enum DetailType {
685 > Declaration,
686 > Statement,
687 > Branch,
688 > }
689 >
690 > export type CoverageDetails = IDeclarationCoverage | IStatementCoverage;
691 >
692 > export namespace CoverageDetails {
693 > export type Serialized = IDeclarationCoverage.Serialized | IStatementCoverage.Serialized;
694 >
695 > export const serialize = (original: Readonly<CoverageDetails>): Serialized =>
696 original.type === DetailType.Declaration ? IDeclarationCoverage.serialize(original) : IStatementCoverage.serialize(original);
697 > testTypes.ts
698 > export const deserialize = (serialized: Serialized): CoverageDetails =>
699 serialized.type === DetailType.Declaration ? IDeclarationCoverage.deserialize(serialized) : IStatementCoverage.deserialize(serialized);
700 > } testTypes.ts
701 >
702 > export interface IBranchCoverage {
703 > count: number | boolean;
704 > label?: string;
705 > location?: Range | Position;
706 > }
707 >
708 > export namespace IBranchCoverage {
709 > export interface Serialized {
710 > count: number | boolean;
711 > label?: string;
712 > location?: IRange | IPosition;
713 > }
714 >
715 > export const serialize: (original: IBranchCoverage) => Serialized = serializeThingWithLocation;
716 > export const deserialize: (original: Serialized) => IBranchCoverage = deserializeThingWithLocation;
717 > }
718 >
719 > export interface IDeclarationCoverage {
720 > type: DetailType.Declaration;
721 > name: string;
722 > count: number | boolean;
723 > location: Range | Position;
724 > }
725 >
726 > export namespace IDeclarationCoverage {
727 > export interface Serialized {
728 > type: DetailType.Declaration;
729 > name: string;
730 > count: number | boolean;
731 > location: IRange | IPosition;
732 > }
733 >
734 > export const serialize: (original: IDeclarationCoverage) => Serialized = serializeThingWithLocation;
735 > export const deserialize: (original: Serialized) => IDeclarationCoverage = deserializeThingWithLocation;
736 > }
737 >
738 > export interface IStatementCoverage {
739 > type: DetailType.Statement;
740 > count: number | boolean;
741 > location: Range | Position;
742 > branches?: IBranchCoverage[];
743 > }
744 >
745 > export namespace IStatementCoverage {
746 > export interface Serialized {
747 > type: DetailType.Statement;
748 > count: number | boolean;
749 > location: IRange | IPosition;
750 > branches?: IBranchCoverage.Serialized[];
751 > }
752 >
753 > export const serialize = (original: Readonly<IStatementCoverage>): Serialized => ({
754 ...serializeThingWithLocation(original),
755 branches: original.branches?.map(IBranchCoverage.serialize),
756 });
757 > testTypes.ts
758 > export const deserialize = (serialized: Serialized): IStatementCoverage => ({
759 ...deserializeThingWithLocation(serialized),
760 branches: serialized.branches?.map(IBranchCoverage.deserialize),
761 });
762 > } testTypes.ts
763 >
764 > export const enum TestDiffOpType {
765 > /** Adds a new test (with children) */
766 > Add,
767 > /** Shallow-updates an existing test */
768 > Update,
769 > /** Ranges of some tests in a document were synced, so it should be considered up-to-date */
770 > DocumentSynced,
771 > /** Removes a test (and all its children) */
772 > Remove,
773 > /** Changes the number of controllers who are yet to publish their collection roots. */
774 > IncrementPendingExtHosts,
775 > /** Retires a test/result */
776 > Retire,
777 > /** Add a new test tag */
778 > AddTag,
779 > /** Remove a test tag */
780 > RemoveTag,
781 > }
782 >
783 > export type TestsDiffOp =
784 > | { op: TestDiffOpType.Add; item: InternalTestItem }
785 > | { op: TestDiffOpType.Update; item: ITestItemUpdate }
786 > | { op: TestDiffOpType.Remove; itemId: string }
787 > | { op: TestDiffOpType.Retire; itemId: string }
788 > | { op: TestDiffOpType.IncrementPendingExtHosts; amount: number }
789 > | { op: TestDiffOpType.AddTag; tag: ITestTagDisplayInfo }
790 > | { op: TestDiffOpType.RemoveTag; id: string }
791 > | { op: TestDiffOpType.DocumentSynced; uri: URI; docv?: number };
792 >
793 > export namespace TestsDiffOp {
794 > export type Serialized =
795 > | { op: TestDiffOpType.Add; item: InternalTestItem.Serialized }
796 > | { op: TestDiffOpType.Update; item: ITestItemUpdate.Serialized }
797 > | { op: TestDiffOpType.Remove; itemId: string }
798 > | { op: TestDiffOpType.Retire; itemId: string }
799 > | { op: TestDiffOpType.IncrementPendingExtHosts; amount: number }
800 > | { op: TestDiffOpType.AddTag; tag: ITestTagDisplayInfo }
801 > | { op: TestDiffOpType.RemoveTag; id: string }
802 > | { op: TestDiffOpType.DocumentSynced; uri: UriComponents; docv?: number };
803 >
804 > export const deserialize = (uriIdentity: ITestUriCanonicalizer, u: Serialized): TestsDiffOp => {
805 if (u.op === TestDiffOpType.Add) {
806 return { op: u.op, item: InternalTestItem.deserialize(uriIdentity, u.item) };
813 }
814 };
815 > testTypes.ts
816 > export const serialize = (u: Readonly<TestsDiffOp>): Serialized => {
817 if (u.op === TestDiffOpType.Add) {
818 return { op: u.op, item: InternalTestItem.serialize(u.item) };
823 }
824 };
825 > } testTypes.ts
826 >
827 > /**
828 > * Context for actions taken in the test explorer view.
829 > */
830 > export interface ITestItemContext {
831 > /** Marshalling marker */
832 > $mid: MarshalledId.TestItemContext;
833 > /** Tests and parents from the root to the current items */
834 > tests: InternalTestItem.Serialized[];
835 > }
836 >
837 > /**
838 > * Context for actions taken in the test explorer view.
839 > */
840 > export interface ITestMessageMenuArgs {
841 > /** Marshalling marker */
842 > $mid: MarshalledId.TestMessageMenuArgs;
843 > /** Tests ext ID */
844 > test: InternalTestItem.Serialized;
845 > /** Serialized test message */
846 > message: ITestMessage.Serialized;
847 > }
848 >
849 > /**
850 > * Request from the ext host or main thread to indicate that tests have
851 > * changed. It's assumed that any item upserted *must* have its children
852 > * previously also upserted, or upserted as part of the same operation.
853 > * Children that no longer exist in an upserted item will be removed.
854 > */
855 > export type TestsDiff = TestsDiffOp[];
856 >
857 > /**
858 > * @private
859 > */
860 > export interface IncrementalTestCollectionItem extends InternalTestItem {
861 > children: Set<string>;
862 > }
863 >
864 > /**
865 > * The IncrementalChangeCollector is used in the IncrementalTestCollection
866 > * and called with diff changes as they're applied. This is used in the
867 > * ext host to create a cohesive change event from a diff.
868 > */
869 > export interface IncrementalChangeCollector<T> {
870 > /**
871 > * A node was added.
872 > */
873 > add?(node: T): void;
874 >
875 > /**
876 > * A node in the collection was updated.
877 > */
878 > update?(node: T): void;
879 >
880 > /**
881 > * A node was removed.
882 > */
883 > remove?(node: T, isNestedOperation: boolean): void;
884 >
885 > /**
886 > * Called when the diff has been applied.
887 > */
888 > complete?(): void;
889 > }
890 >
891 > /**
892 > * Maintains tests in this extension host sent from the main thread.
893 > */
894 > export abstract class AbstractIncrementalTestCollection<T extends IncrementalTestCollectionItem> {
895 > private readonly _tags = new Map<string, ITestTagDisplayInfo>();
896 >
897 > /**
898 > * Map of item IDs to test item objects.
899 > */
900 > protected readonly items = new Map<string, T>();
901 >
902 > /**
903 > * ID of test root items.
904 > */
905 > protected readonly roots = new Set<T>();
906 >
907 > /**
908 > * Number of 'busy' controllers.
909 > */
910 > protected busyControllerCount = 0;
911 >
912 > /**
913 > * Number of pending roots.
914 > */
915 > protected pendingRootCount = 0;
916 >
917 > /**
918 > * Known test tags.
919 > */
920 > public readonly tags: ReadonlyMap<string, ITestTagDisplayInfo> = this._tags;
921 >
922 > constructor(private readonly uriIdentity: ITestUriCanonicalizer) { }
923 >
924 > /**
925 > * Applies the diff to the collection.
926 > */
927 > public apply(diff: TestsDiff) {
928 const changes = this.createChangeCollector();
929
962 changes.complete?.();
963 }
964 > testTypes.ts
965 > protected add(item: InternalTestItem, changes: IncrementalChangeCollector<T>
966 ) {
967 const parentId = TestId.parentId(item.item.extId)?.toString();
988 return created;
989 }
990 > testTypes.ts
991 > protected update(patch: ITestItemUpdate, changes: IncrementalChangeCollector<T>
992 ) {
993 const existing = this.items.get(patch.extId);
1009 return existing;
1010 }
1011 > testTypes.ts
1012 > protected remove(itemId: string, changes: IncrementalChangeCollector<T>) {
1013 const toRemove = this.items.get(itemId);
1014 if (!toRemove) {
1040 }
1041 }
1042 > testTypes.ts
1043 > /**
1044 > * Called when the extension signals a test result should be retired.
1045 > */
1046 > protected retireTest(testId: string) {
1047 // no-op
1048 }
1049 > testTypes.ts
1050 > /**
1051 > * Updates the number of test root sources who are yet to report. When
1052 > * the total pending test roots reaches 0, the roots for all controllers
1053 > * will exist in the collection.
1054 > */
1055 > public updatePendingRoots(delta: number) {
1056 this.pendingRootCount += delta;
1057 }
1058 > testTypes.ts
1059 > /**
1060 > * Called before a diff is applied to create a new change collector.
1061 > */
1062 > protected createChangeCollector(): IncrementalChangeCollector<T> {
1063 return {};
1064 }
1065 > testTypes.ts
1066 > /**
1067 > * Creates a new item for the collection from the internal test item.
1068 > */
1069 > protected abstract createItem(internal: InternalTestItem, parent?: T): T;
1070 > }
src/vs/platform/extensionManagement/common/extensionManagement.ts 660 covered LOC · 10 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extensionManagement.ts
2 > * Copyright (c) Microsoft 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 { IStringDictionary } from '../../../base/common/collections.js';
8 > import { Event } from '../../../base/common/event.js';
9 > import { IMarkdownString } from '../../../base/common/htmlContent.js';
10 > import { IPager } from '../../../base/common/paging.js';
11 > import { Platform } from '../../../base/common/platform.js';
12 > import { PolicyCategory } from '../../../base/common/policy.js';
13 > import { URI } from '../../../base/common/uri.js';
14 > import { localize, localize2 } from '../../../nls.js';
15 > import { ConfigurationScope, Extensions, IConfigurationRegistry } from '../../configuration/common/configurationRegistry.js';
16 > import { ExtensionType, IExtension, IExtensionManifest, TargetPlatform } from '../../extensions/common/extensions.js';
17 > import { FileOperationError, FileOperationResult, IFileService, IFileStat } from '../../files/common/files.js';
18 > import { createDecorator } from '../../instantiation/common/instantiation.js';
19 > import { Registry } from '../../registry/common/platform.js';
20 > import { IExtensionGalleryManifest } from './extensionGalleryManifest.js';
21 >
22 > export const EXTENSION_IDENTIFIER_PATTERN = '^([a-z0-9A-Z][a-z0-9-A-Z]*)\\.([a-z0-9A-Z][a-z0-9-A-Z]*)$';
23 > export const EXTENSION_IDENTIFIER_REGEX = new RegExp(EXTENSION_IDENTIFIER_PATTERN);
24 > export const WEB_EXTENSION_TAG = '__web_extension';
25 > export const LANGUAGE_MODEL_CHAT_PROVIDER_EXTENSION_TAG = 'language-models';
26 > export const EXTENSION_INSTALL_SKIP_WALKTHROUGH_CONTEXT = 'skipWalkthrough';
27 > export const EXTENSION_INSTALL_SKIP_PUBLISHER_TRUST_CONTEXT = 'skipPublisherTrust';
28 > export const EXTENSION_INSTALL_SOURCE_CONTEXT = 'extensionInstallSource';
29 > export const EXTENSION_INSTALL_DEP_PACK_CONTEXT = 'dependecyOrPackExtensionInstall';
30 > export const EXTENSION_INSTALL_CLIENT_TARGET_PLATFORM_CONTEXT = 'clientTargetPlatform';
31 >
32 > export const enum ExtensionInstallSource {
33 > COMMAND = 'command',
34 > SETTINGS_SYNC = 'settingsSync',
35 > }
36 >
37 > export interface IProductVersion {
38 > readonly version: string;
39 > readonly date?: string;
40 > }
41 >
42 > export function TargetPlatformToString(targetPlatform: TargetPlatform) {
43 switch (targetPlatform) {
44 case TargetPlatform.WIN32_X64: return 'Windows 64 bit';
62 }
63 }
65 > export function toTargetPlatform(targetPlatform: string): TargetPlatform {
66 switch (targetPlatform) {
67 case TargetPlatform.WIN32_X64: return TargetPlatform.WIN32_X64;
84 }
85 }
87 > export function getTargetPlatform(platform: Platform | 'alpine', arch: string | undefined): TargetPlatform {
88 switch (platform) {
89 case Platform.Windows:
129 }
130 }
132 > export function isNotWebExtensionInWebTargetPlatform(allTargetPlatforms: TargetPlatform[], productTargetPlatform: TargetPlatform): boolean {
133 // Not a web extension in web target platform
134 return productTargetPlatform === TargetPlatform.WEB && !allTargetPlatforms.includes(TargetPlatform.WEB);
135 }
137 > export function isTargetPlatformCompatible(extensionTargetPlatform: TargetPlatform, allTargetPlatforms: TargetPlatform[], productTargetPlatform: TargetPlatform): boolean {
138 // Not compatible when extension is not a web extension in web target platform
139 if (isNotWebExtensionInWebTargetPlatform(allTargetPlatforms, productTargetPlatform)) {
163 return false;
164 }
166 > export interface IGalleryExtensionProperties {
167 > dependencies?: string[];
168 > extensionPack?: string[];
169 > engine?: string;
170 > enabledApiProposals?: string[];
171 > localizedLanguages?: string[];
172 > targetPlatform: TargetPlatform;
173 > isPreReleaseVersion: boolean;
174 > executesCode?: boolean;
175 > }
176 >
177 > export interface IGalleryExtensionAsset {
178 > uri: string;
179 > fallbackUri: string;
180 > }
181 >
182 > export interface IGalleryExtensionAssets {
183 > manifest: IGalleryExtensionAsset | null;
184 > readme: IGalleryExtensionAsset | null;
185 > changelog: IGalleryExtensionAsset | null;
186 > license: IGalleryExtensionAsset | null;
187 > repository: IGalleryExtensionAsset | null;
188 > download: IGalleryExtensionAsset;
189 > icon: IGalleryExtensionAsset | null;
190 > signature: IGalleryExtensionAsset | null;
191 > coreTranslations: [string, IGalleryExtensionAsset][];
192 > }
193 >
194 > export function isIExtensionIdentifier(obj: unknown): obj is IExtensionIdentifier {
195 const thing = obj as IExtensionIdentifier | undefined;
196 return !!thing
199 && (!thing.uuid || typeof thing.uuid === 'string');
200 }
202 > export interface IExtensionIdentifier {
203 > id: string;
204 > uuid?: string;
205 > }
206 >
207 > export interface IGalleryExtensionIdentifier extends IExtensionIdentifier {
208 > uuid: string;
209 > }
210 >
211 > export interface IGalleryExtensionVersion {
212 > version: string;
213 > date: string;
214 > isPreReleaseVersion: boolean;
215 > targetPlatforms: TargetPlatform[];
216 > }
217 >
218 > export interface IGalleryExtension {
219 > type: 'gallery';
220 > name: string;
221 > identifier: IGalleryExtensionIdentifier;
222 > version: string;
223 > displayName: string;
224 > publisherId: string;
225 > publisher: string;
226 > publisherDisplayName: string;
227 > publisherDomain?: { link: string; verified: boolean };
228 > publisherLink?: string;
229 > publisherSponsorLink?: string;
230 > description: string;
231 > installCount: number;
232 > rating: number;
233 > ratingCount: number;
234 > categories: readonly string[];
235 > tags: readonly string[];
236 > releaseDate: number;
237 > lastUpdated: number;
238 > preview: boolean;
239 > private: boolean;
240 > hasPreReleaseVersion: boolean;
241 > hasReleaseVersion: boolean;
242 > isSigned: boolean;
243 > allTargetPlatforms: TargetPlatform[];
244 > assets: IGalleryExtensionAssets;
245 > properties: IGalleryExtensionProperties;
246 > detailsLink?: string;
247 > ratingLink?: string;
248 > supportLink?: string;
249 > telemetryData?: IStringDictionary<unknown>;
250 > queryContext?: IStringDictionary<unknown>;
251 > }
252 >
253 > export type InstallSource = 'gallery' | 'vsix' | 'resource';
254 >
255 > export interface IGalleryMetadata {
256 > id: string;
257 > publisherId: string;
258 > private: boolean;
259 > publisherDisplayName: string;
260 > isPreReleaseVersion: boolean;
261 > targetPlatform?: TargetPlatform;
262 > }
263 >
264 > export type Metadata = Partial<IGalleryMetadata & {
265 > isApplicationScoped: boolean;
266 > isMachineScoped: boolean;
267 > isBuiltin: boolean;
268 > isSystem: boolean;
269 > updated: boolean;
270 > preRelease: boolean;
271 > hasPreReleaseVersion: boolean;
272 > installedTimestamp: number;
273 > pinned: boolean;
274 > source: InstallSource;
275 > size: number;
276 > }>;
277 >
278 > export interface ILocalExtension extends IExtension {
279 > isWorkspaceScoped: boolean;
280 > isMachineScoped: boolean;
281 > isApplicationScoped: boolean;
282 > publisherId: string | null;
283 > installedTimestamp?: number;
284 > isPreReleaseVersion: boolean;
285 > hasPreReleaseVersion: boolean;
286 > private: boolean;
287 > preRelease: boolean;
288 > updated: boolean;
289 > pinned: boolean;
290 > forceAutoUpdate: boolean;
291 > source: InstallSource;
292 > size: number;
293 > }
294 >
295 > export const enum SortBy {
296 > NoneOrRelevance = 'NoneOrRelevance',
297 > LastUpdatedDate = 'LastUpdatedDate',
298 > Title = 'Title',
299 > PublisherName = 'PublisherName',
300 > InstallCount = 'InstallCount',
301 > PublishedDate = 'PublishedDate',
302 > AverageRating = 'AverageRating',
303 > WeightedRating = 'WeightedRating'
304 > }
305 >
306 > export const enum SortOrder {
307 > Default = 0,
308 > Ascending = 1,
309 > Descending = 2
310 > }
311 >
312 > export const enum FilterType {
313 > Category = 'Category',
314 > ExtensionId = 'ExtensionId',
315 > ExtensionName = 'ExtensionName',
316 > ExcludeWithFlags = 'ExcludeWithFlags',
317 > Featured = 'Featured',
318 > SearchText = 'SearchText',
319 > Tag = 'Tag',
320 > Target = 'Target',
321 > }
322 >
323 > export interface IQueryOptions {
324 > text?: string;
325 > exclude?: string[];
326 > pageSize?: number;
327 > sortBy?: SortBy;
328 > sortOrder?: SortOrder;
329 > source?: string;
330 > includePreRelease?: boolean;
331 > productVersion?: IProductVersion;
332 > }
333 >
334 > export const enum StatisticType {
335 > Install = 'install',
336 > Uninstall = 'uninstall'
337 > }
338 >
339 > export interface IDeprecationInfo {
340 > readonly disallowInstall?: boolean;
341 > readonly extension?: {
342 > readonly id: string;
343 > readonly displayName: string;
344 > readonly autoMigrate?: {
345 > readonly storage: boolean;
346 > readonly donotDisable?: boolean;
347 > };
348 > readonly preRelease?: boolean;
349 > };
350 > readonly settings?: readonly string[];
351 > readonly additionalInfo?: string;
352 > }
353 >
354 > export interface ISearchPrefferedResults {
355 > readonly query?: string;
356 > readonly preferredResults?: string[];
357 > }
358 >
359 > export type MaliciousExtensionInfo = {
360 > readonly extensionOrPublisher: IExtensionIdentifier | string;
361 > readonly learnMoreLink?: string;
362 > };
363 >
364 > export interface IExtensionsControlManifest {
365 > readonly malicious: ReadonlyArray<MaliciousExtensionInfo>;
366 > readonly deprecated: IStringDictionary<IDeprecationInfo>;
367 > readonly search: ISearchPrefferedResults[];
368 > readonly autoUpdate?: IStringDictionary<string>;
369 > }
370 >
371 > export const enum InstallOperation {
372 > None = 1,
373 > Install,
374 > Update,
375 > Migrate,
376 > }
377 >
378 > export interface ITranslation {
379 > contents: { [key: string]: {} };
380 > }
381 >
382 > export interface IExtensionInfo extends IExtensionIdentifier {
383 > version?: string;
384 > preRelease?: boolean;
385 > hasPreRelease?: boolean;
386 > currentVersion?: string;
387 > }
388 >
389 > export interface IExtensionQueryOptions {
390 > targetPlatform?: TargetPlatform;
391 > productVersion?: IProductVersion;
392 > compatible?: boolean;
393 > queryAllVersions?: boolean;
394 > source?: string;
395 > }
396 >
397 > export interface IExtensionGalleryCapabilities {
398 > readonly query: {
399 > readonly sortBy: readonly SortBy[];
400 > readonly filters: readonly FilterType[];
401 > };
402 > readonly allRepositorySigned: boolean;
403 > }
404 >
405 > export const IExtensionGalleryService = createDecorator<IExtensionGalleryService>('extensionGalleryService');
406 >
407 > /**
408 > * Service to interact with the Visual Studio Code Marketplace to get extensions.
409 > * @throws Error if the Marketplace is not enabled or not reachable.
410 > */
411 > export interface IExtensionGalleryService {
412 > readonly _serviceBrand: undefined;
413 > isEnabled(): boolean;
414 > query(options: IQueryOptions, token: CancellationToken): Promise<IPager<IGalleryExtension>>;
415 > getExtensions(extensionInfos: ReadonlyArray<IExtensionInfo>, token: CancellationToken): Promise<IGalleryExtension[]>;
416 > getExtensions(extensionInfos: ReadonlyArray<IExtensionInfo>, options: IExtensionQueryOptions, token: CancellationToken): Promise<IGalleryExtension[]>;
417 > isExtensionCompatible(extension: IGalleryExtension, includePreRelease: boolean, targetPlatform: TargetPlatform, productVersion?: IProductVersion): Promise<boolean>;
418 > getCompatibleExtension(extension: IGalleryExtension, includePreRelease: boolean, targetPlatform: TargetPlatform, productVersion?: IProductVersion): Promise<IGalleryExtension | null>;
419 > getAllCompatibleVersions(extensionIdentifier: IExtensionIdentifier, includePreRelease: boolean, targetPlatform: TargetPlatform): Promise<IGalleryExtensionVersion[]>;
420 > getAllVersions(extensionIdentifier: IExtensionIdentifier): Promise<IGalleryExtensionVersion[]>;
421 > download(extension: IGalleryExtension, location: URI, operation: InstallOperation): Promise<void>;
422 > downloadSignatureArchive(extension: IGalleryExtension, location: URI): Promise<void>;
423 > reportStatistic(publisher: string, name: string, version: string, type: StatisticType): Promise<void>;
424 > getReadme(extension: IGalleryExtension, token: CancellationToken): Promise<string>;
425 > getManifest(extension: IGalleryExtension, token: CancellationToken): Promise<IExtensionManifest | null>;
426 > getChangelog(extension: IGalleryExtension, token: CancellationToken): Promise<string>;
427 > getCoreTranslation(extension: IGalleryExtension, languageId: string): Promise<ITranslation | null>;
428 > getExtensionsControlManifest(): Promise<IExtensionsControlManifest>;
429 > }
430 >
431 > export interface InstallExtensionEvent {
432 > readonly identifier: IExtensionIdentifier;
433 > readonly source: URI | IGalleryExtension;
434 > readonly profileLocation: URI;
435 > readonly applicationScoped?: boolean;
436 > readonly workspaceScoped?: boolean;
437 > }
438 >
439 > export interface InstallExtensionResult {
440 > readonly identifier: IExtensionIdentifier;
441 > readonly operation: InstallOperation;
442 > readonly source?: URI | IGalleryExtension;
443 > readonly local?: ILocalExtension;
444 > readonly error?: Error;
445 > readonly context?: IStringDictionary<unknown>;
446 > readonly profileLocation: URI;
447 > readonly applicationScoped?: boolean;
448 > readonly workspaceScoped?: boolean;
449 > }
450 >
451 > export interface UninstallExtensionEvent {
452 > readonly identifier: IExtensionIdentifier;
453 > readonly profileLocation: URI;
454 > readonly applicationScoped?: boolean;
455 > readonly workspaceScoped?: boolean;
456 > }
457 >
458 > export interface DidUninstallExtensionEvent {
459 > readonly identifier: IExtensionIdentifier;
460 > readonly error?: string;
461 > readonly profileLocation: URI;
462 > readonly applicationScoped?: boolean;
463 > readonly workspaceScoped?: boolean;
464 > }
465 >
466 > export interface DidUpdateExtensionMetadata {
467 > readonly profileLocation: URI;
468 > readonly local: ILocalExtension;
469 > }
470 >
471 > export const enum ExtensionGalleryErrorCode {
472 > Timeout = 'Timeout',
473 > Cancelled = 'Cancelled',
474 > ClientError = 'ClientError',
475 > ServerError = 'ServerError',
476 > Failed = 'Failed',
477 > DownloadFailedWriting = 'DownloadFailedWriting',
478 > Offline = 'Offline',
479 > }
480 >
481 > export class ExtensionGalleryError extends Error {
482 > constructor(message: string, readonly code: ExtensionGalleryErrorCode) {
483 super(message);
484 this.name = code;
485 }
487 >
488 > export const enum ExtensionManagementErrorCode {
489 > NotFound = 'NotFound',
490 > Unsupported = 'Unsupported',
491 > Deprecated = 'Deprecated',
492 > Malicious = 'Malicious',
493 > Incompatible = 'Incompatible',
494 > IncompatibleApi = 'IncompatibleApi',
495 > IncompatibleTargetPlatform = 'IncompatibleTargetPlatform',
496 > ReleaseVersionNotFound = 'ReleaseVersionNotFound',
497 > Invalid = 'Invalid',
498 > Download = 'Download',
499 > DownloadSignature = 'DownloadSignature',
500 > DownloadFailedWriting = ExtensionGalleryErrorCode.DownloadFailedWriting,
501 > UpdateMetadata = 'UpdateMetadata',
502 > Extract = 'Extract',
503 > Scanning = 'Scanning',
504 > ScanningExtension = 'ScanningExtension',
505 > ReadRemoved = 'ReadRemoved',
506 > UnsetRemoved = 'UnsetRemoved',
507 > Delete = 'Delete',
508 > Rename = 'Rename',
509 > IntializeDefaultProfile = 'IntializeDefaultProfile',
510 > AddToProfile = 'AddToProfile',
511 > InstalledExtensionNotFound = 'InstalledExtensionNotFound',
512 > PostInstall = 'PostInstall',
513 > CorruptZip = 'CorruptZip',
514 > IncompleteZip = 'IncompleteZip',
515 > PackageNotSigned = 'PackageNotSigned',
516 > SignatureVerificationInternal = 'SignatureVerificationInternal',
517 > SignatureVerificationFailed = 'SignatureVerificationFailed',
518 > NotAllowed = 'NotAllowed',
519 > Gallery = 'Gallery',
520 > Cancelled = 'Cancelled',
521 > Unknown = 'Unknown',
522 > Internal = 'Internal',
523 > }
524 >
525 > export enum ExtensionSignatureVerificationCode {
526 > 'NotSigned' = 'NotSigned',
527 > 'Success' = 'Success',
528 > 'RequiredArgumentMissing' = 'RequiredArgumentMissing', // A required argument is missing.
529 > 'InvalidArgument' = 'InvalidArgument', // An argument is invalid.
530 > 'PackageIsUnreadable' = 'PackageIsUnreadable', // The extension package is unreadable.
531 > 'UnhandledException' = 'UnhandledException', // An unhandled exception occurred.
532 > 'SignatureManifestIsMissing' = 'SignatureManifestIsMissing', // The extension is missing a signature manifest file (.signature.manifest).
533 > 'SignatureManifestIsUnreadable' = 'SignatureManifestIsUnreadable', // The signature manifest is unreadable.
534 > 'SignatureIsMissing' = 'SignatureIsMissing', // The extension is missing a signature file (.signature.p7s).
535 > 'SignatureIsUnreadable' = 'SignatureIsUnreadable', // The signature is unreadable.
536 > 'CertificateIsUnreadable' = 'CertificateIsUnreadable', // The certificate is unreadable.
537 > 'SignatureArchiveIsUnreadable' = 'SignatureArchiveIsUnreadable',
538 > 'FileAlreadyExists' = 'FileAlreadyExists', // The output file already exists.
539 > 'SignatureArchiveIsInvalidZip' = 'SignatureArchiveIsInvalidZip',
540 > 'SignatureArchiveHasSameSignatureFile' = 'SignatureArchiveHasSameSignatureFile', // The signature archive has the same signature file.
541 > 'PackageIntegrityCheckFailed' = 'PackageIntegrityCheckFailed', // The package integrity check failed.
542 > 'SignatureIsInvalid' = 'SignatureIsInvalid', // The extension has an invalid signature file (.signature.p7s).
543 > 'SignatureManifestIsInvalid' = 'SignatureManifestIsInvalid', // The extension has an invalid signature manifest file (.signature.manifest).
544 > 'SignatureIntegrityCheckFailed' = 'SignatureIntegrityCheckFailed', // The extension's signature integrity check failed. Extension integrity is suspect.
545 > 'EntryIsMissing' = 'EntryIsMissing', // An entry referenced in the signature manifest was not found in the extension.
546 > 'EntryIsTampered' = 'EntryIsTampered', // The integrity check for an entry referenced in the signature manifest failed.
547 > 'Untrusted' = 'Untrusted', // An X.509 certificate in the extension signature is untrusted.
548 > 'CertificateRevoked' = 'CertificateRevoked', // An X.509 certificate in the extension signature has been revoked.
549 > 'SignatureIsNotValid' = 'SignatureIsNotValid', // The extension signature is invalid.
550 > 'UnknownError' = 'UnknownError', // An unknown error occurred.
551 > 'PackageIsInvalidZip' = 'PackageIsInvalidZip', // The extension package is not valid ZIP format.
552 > 'SignatureArchiveHasTooManyEntries' = 'SignatureArchiveHasTooManyEntries', // The signature archive has too many entries.
553 > }
554 >
555 > export class ExtensionManagementError extends Error {
556 > constructor(message: string, readonly code: ExtensionManagementErrorCode) {
557 super(message);
558 this.name = code;
559 }
561 >
562 > export interface InstallExtensionSummary {
563 > failed: {
564 > id: string;
565 > installOptions: InstallOptions;
566 > }[];
567 > }
568 >
569 > export type InstallOptions = {
570 > isBuiltin?: boolean;
571 > isWorkspaceScoped?: boolean;
572 > isMachineScoped?: boolean;
573 > isApplicationScoped?: boolean;
574 > pinned?: boolean;
575 > donotIncludePackAndDependencies?: boolean;
576 > installGivenVersion?: boolean;
577 > preRelease?: boolean;
578 > installPreReleaseVersion?: boolean;
579 > donotVerifySignature?: boolean;
580 > operation?: InstallOperation;
581 > profileLocation?: URI;
582 > productVersion?: IProductVersion;
583 > keepExisting?: boolean;
584 > downloadExtensionsLocally?: boolean;
585 > /**
586 > * Context passed through to InstallExtensionResult
587 > */
588 > context?: IStringDictionary<unknown>;
589 > };
590 >
591 > export type UninstallOptions = {
592 > readonly profileLocation?: URI;
593 > readonly donotIncludePack?: boolean;
594 > readonly donotCheckDependents?: boolean;
595 > readonly versionOnly?: boolean;
596 > readonly remove?: boolean;
597 > };
598 >
599 > export interface IExtensionManagementParticipant {
600 > postInstall(local: ILocalExtension, source: URI | IGalleryExtension, options: InstallOptions, token: CancellationToken): Promise<void>;
601 > postUninstall(local: ILocalExtension, options: UninstallOptions, token: CancellationToken): Promise<void>;
602 > }
603 >
604 > export type InstallExtensionInfo = { readonly extension: IGalleryExtension; readonly options: InstallOptions };
605 > export type UninstallExtensionInfo = { readonly extension: ILocalExtension; readonly options?: UninstallOptions };
606 >
607 > export const IExtensionManagementService = createDecorator<IExtensionManagementService>('extensionManagementService');
608 > export interface IExtensionManagementService {
609 > readonly _serviceBrand: undefined;
610 >
611 > readonly preferPreReleases: boolean;
612 >
613 > onInstallExtension: Event<InstallExtensionEvent>;
614 > onDidInstallExtensions: Event<readonly InstallExtensionResult[]>;
615 > onUninstallExtension: Event<UninstallExtensionEvent>;
616 > onDidUninstallExtension: Event<DidUninstallExtensionEvent>;
617 > onDidUpdateExtensionMetadata: Event<DidUpdateExtensionMetadata>;
618 >
619 > zip(extension: ILocalExtension): Promise<URI>;
620 > getManifest(vsix: URI): Promise<IExtensionManifest>;
621 > install(vsix: URI, options?: InstallOptions): Promise<ILocalExtension>;
622 > canInstall(extension: IGalleryExtension): Promise<true | IMarkdownString>;
623 > installFromGallery(extension: IGalleryExtension, options?: InstallOptions): Promise<ILocalExtension>;
624 > installGalleryExtensions(extensions: InstallExtensionInfo[]): Promise<InstallExtensionResult[]>;
625 > installFromLocation(location: URI, profileLocation: URI): Promise<ILocalExtension>;
626 > installExtensionsFromProfile(extensions: IExtensionIdentifier[], fromProfileLocation: URI, toProfileLocation: URI): Promise<ILocalExtension[]>;
627 > uninstall(extension: ILocalExtension, options?: UninstallOptions): Promise<void>;
628 > uninstallExtensions(extensions: UninstallExtensionInfo[]): Promise<void>;
629 > toggleApplicationScope(extension: ILocalExtension, fromProfileLocation: URI): Promise<ILocalExtension>;
630 > getInstalled(type?: ExtensionType, profileLocation?: URI, productVersion?: IProductVersion, language?: string): Promise<ILocalExtension[]>;
631 > getExtensionsControlManifest(): Promise<IExtensionsControlManifest>;
632 > copyExtensions(fromProfileLocation: URI, toProfileLocation: URI): Promise<void>;
633 > updateMetadata(local: ILocalExtension, metadata: Partial<Metadata>, profileLocation: URI): Promise<ILocalExtension>;
634 > resetPinnedStateForAllUserExtensions(pinned: boolean): Promise<void>;
635 >
636 > download(extension: IGalleryExtension, operation: InstallOperation, donotVerifySignature: boolean): Promise<URI>;
637 >
638 > registerParticipant(pariticipant: IExtensionManagementParticipant): void;
639 > getTargetPlatform(): Promise<TargetPlatform>;
640 >
641 > cleanUp(): Promise<void>;
642 > }
643 >
644 > export const DISABLED_EXTENSIONS_STORAGE_PATH = 'extensionsIdentifiers/disabled';
645 > export const ENABLED_EXTENSIONS_STORAGE_PATH = 'extensionsIdentifiers/enabled';
646 > export const IGlobalExtensionEnablementService = createDecorator<IGlobalExtensionEnablementService>('IGlobalExtensionEnablementService');
647 >
648 > export interface IGlobalExtensionEnablementService {
649 > readonly _serviceBrand: undefined;
650 > readonly onDidChangeEnablement: Event<{ readonly extensions: IExtensionIdentifier[]; readonly source?: string }>;
651 >
652 > getDisabledExtensions(): IExtensionIdentifier[];
653 > enableExtension(extension: IExtensionIdentifier, source?: string): Promise<boolean>;
654 > disableExtension(extension: IExtensionIdentifier, source?: string): Promise<boolean>;
655 >
656 > }
657 >
658 > export type IConfigBasedExtensionTip = {
659 > readonly extensionId: string;
660 > readonly extensionName: string;
661 > readonly isExtensionPack: boolean;
662 > readonly configName: string;
663 > readonly important: boolean;
664 > readonly whenNotInstalled?: string[];
665 > };
666 >
667 > export type IExecutableBasedExtensionTip = {
668 > readonly extensionId: string;
669 > readonly extensionName: string;
670 > readonly isExtensionPack: boolean;
671 > readonly exeName: string;
672 > readonly exeFriendlyName: string;
673 > readonly windowsPath?: string;
674 > readonly whenNotInstalled?: string[];
675 > };
676 >
677 > export const IExtensionTipsService = createDecorator<IExtensionTipsService>('IExtensionTipsService');
678 > export interface IExtensionTipsService {
679 > readonly _serviceBrand: undefined;
680 >
681 > getConfigBasedTips(folder: URI): Promise<IConfigBasedExtensionTip[]>;
682 > getImportantExecutableBasedTips(): Promise<IExecutableBasedExtensionTip[]>;
683 > getOtherExecutableBasedTips(): Promise<IExecutableBasedExtensionTip[]>;
684 > }
685 >
686 > export type AllowedExtensionsConfigValueType = IStringDictionary<boolean | string | string[]>;
687 >
688 > export const IAllowedExtensionsService = createDecorator<IAllowedExtensionsService>('IAllowedExtensionsService');
689 > export interface IAllowedExtensionsService {
690 > readonly _serviceBrand: undefined;
691 >
692 > readonly allowedExtensionsConfigValue: AllowedExtensionsConfigValueType | undefined;
693 > readonly onDidChangeAllowedExtensionsConfigValue: Event<void>;
694 >
695 > isAllowed(extension: IGalleryExtension | IExtension): true | IMarkdownString;
696 > isAllowed(extension: { id: string; publisherDisplayName: string | undefined; version?: string; prerelease?: boolean; targetPlatform?: TargetPlatform }): true | IMarkdownString;
697 > }
698 >
699 export async function computeSize(location: URI, fileService: IFileService): Promise<number> {
700 let stat: IFileStat;
713 return stat.size ?? 0;
714 }
716 > export const ExtensionsLocalizedLabel = localize2('extensions', "Extensions");
717 > export const PreferencesLocalizedLabel = localize2('preferences', 'Preferences');
718 > export const AllowedExtensionsConfigKey = 'extensions.allowed';
719 > export const VerifyExtensionSignatureConfigKey = 'extensions.verifySignature';
720 > export const ExtensionRequestsTimeoutConfigKey = 'extensions.requestTimeout';
721 >
722 > Registry.as<IConfigurationRegistry>(Extensions.Configuration)
723 > .registerConfiguration({
724 > id: 'extensions',
725 > order: 30,
726 > title: localize('extensionsConfigurationTitle', "Extensions"),
727 > type: 'object',
728 > properties: {
729 > [AllowedExtensionsConfigKey]: {
730 > // Note: Type is set only to object because to support policies generation during build time, where single type is expected.
731 > type: 'object',
732 > markdownDescription: localize('extensions.allowed', "Specify a list of extensions that are allowed to use. This helps maintain a secure and consistent development environment by restricting the use of unauthorized extensions. For more information on how to configure this setting, please visit the [Configure Allowed Extensions](https://aka.ms/vscode/enterprise/extensions/allowed) section."),
733 > default: '*',
734 > defaultSnippets: [{
735 > body: {},
736 > description: localize('extensions.allowed.none', "No extensions are allowed."),
737 > }, {
738 > body: {
739 > '*': true
740 > },
741 > description: localize('extensions.allowed.all', "All extensions are allowed."),
742 > }],
743 > scope: ConfigurationScope.APPLICATION,
744 > policy: {
745 > name: 'AllowedExtensions',
746 > category: PolicyCategory.Extensions,
747 > minimumVersion: '1.96',
748 > localization: {
749 > description: {
750 > key: 'extensions.allowed.policy',
751 > value: localize('extensions.allowed.policy', "Specify a list of extensions that are allowed to use. This helps maintain a secure and consistent development environment by restricting the use of unauthorized extensions. More information: https://aka.ms/vscode/enterprise/extensions/allowed"),
752 > }
753 > }
754 > },
755 > additionalProperties: false,
756 > patternProperties: {
757 > '([a-z0-9A-Z][a-z0-9-A-Z]*)\\.([a-z0-9A-Z][a-z0-9-A-Z]*)$': {
758 > anyOf: [
759 > {
760 > type: ['boolean', 'string'],
761 > enum: [true, false, 'stable'],
762 > description: localize('extensions.allow.description', "Allow or disallow the extension."),
763 > enumDescriptions: [
764 > localize('extensions.allowed.enable.desc', "Extension is allowed."),
765 > localize('extensions.allowed.disable.desc', "Extension is not allowed."),
766 > localize('extensions.allowed.disable.stable.desc', "Allow only stable versions of the extension."),
767 > ],
768 > },
769 > {
770 > type: 'array',
771 > items: {
772 > type: 'string',
773 > },
774 > description: localize('extensions.allow.version.description', "Allow or disallow specific versions of the extension. To specifcy a platform specific version, use the format `[email protected]`, e.g. `[email protected]`. Supported platforms are `win32-x64`, `win32-arm64`, `linux-x64`, `linux-arm64`, `linux-armhf`, `alpine-x64`, `alpine-arm64`, `darwin-x64`, `darwin-arm64`"),
775 > },
776 > ]
777 > },
778 > '([a-z0-9A-Z][a-z0-9-A-Z]*)$': {
779 > type: ['boolean', 'string'],
780 > enum: [true, false, 'stable'],
781 > description: localize('extension.publisher.allow.description', "Allow or disallow all extensions from the publisher."),
782 > enumDescriptions: [
783 > localize('extensions.publisher.allowed.enable.desc', "All extensions from the publisher are allowed."),
784 > localize('extensions.publisher.allowed.disable.desc', "All extensions from the publisher are not allowed."),
785 > localize('extensions.publisher.allowed.disable.stable.desc', "Allow only stable versions of the extensions from the publisher."),
786 > ],
787 > },
788 > '\\*': {
789 > type: 'boolean',
790 > enum: [true, false],
791 > description: localize('extensions.allow.all.description', "Allow or disallow all extensions."),
792 > enumDescriptions: [
793 > localize('extensions.allow.all.enable', "Allow all extensions."),
794 > localize('extensions.allow.all.disable', "Disallow all extensions.")
795 > ],
796 > }
797 > }
798 > }
799 > }
800 > });
801 >
802 > export function shouldRequireRepositorySignatureFor(isPrivate: boolean, galleryManifest: IExtensionGalleryManifest | null): boolean {
803 if (isPrivate) {
804 return galleryManifest?.capabilities.signing?.allPrivateRepositorySigned === true;
src/vs/workbench/services/chat/common/chatEntitlementService.ts 651 covered LOC · 52 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- chatEntitlementService.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import product from '../../../../platform/product/common/product.js';
7 > import { Barrier } from '../../../../base/common/async.js';
8 > import { CancellationToken, CancellationTokenSource } from '../../../../base/common/cancellation.js';
9 > import { Emitter, Event } from '../../../../base/common/event.js';
10 > import { Lazy } from '../../../../base/common/lazy.js';
11 > import { Disposable, MutableDisposable } from '../../../../base/common/lifecycle.js';
12 > import { IRequestContext } from '../../../../base/parts/request/common/request.js';
13 > import { localize } from '../../../../nls.js';
14 > import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
15 > import { IContextKey, IContextKeyService, RawContextKey } from '../../../../platform/contextkey/common/contextkey.js';
16 > import { IDialogService } from '../../../../platform/dialogs/common/dialogs.js';
17 > import { createDecorator, IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
18 > import { ILogService, LogLevel } from '../../../../platform/log/common/log.js';
19 > import { IProductService } from '../../../../platform/product/common/productService.js';
20 > import { asText, IRequestService } from '../../../../platform/request/common/request.js';
21 > import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js';
22 > import { ITelemetryService, TelemetryLevel } from '../../../../platform/telemetry/common/telemetry.js';
23 > import { AuthenticationSession, IAuthenticationService } from '../../authentication/common/authentication.js';
24 > import { IOpenerService } from '../../../../platform/opener/common/opener.js';
25 > import { URI } from '../../../../base/common/uri.js';
26 > import Severity from '../../../../base/common/severity.js';
27 > import { IWorkbenchEnvironmentService } from '../../environment/common/environmentService.js';
28 > import { isWeb } from '../../../../base/common/platform.js';
29 > import { ILifecycleService } from '../../lifecycle/common/lifecycle.js';
30 > import { Mutable } from '../../../../base/common/types.js';
31 > import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';
32 > import { IObservable, observableFromEvent } from '../../../../base/common/observable.js';
33 > import { IDefaultAccountService } from '../../../../platform/defaultAccount/common/defaultAccount.js';
34 > import { IDefaultAccount, IEntitlementsData } from '../../../../base/common/defaultAccount.js';
35 >
36 > export namespace ChatEntitlementContextKeys {
37 >
38 > export const Setup = {
39 > hidden: new RawContextKey<boolean>('chatSetupHidden', false, true), // True when chat setup is explicitly hidden.
40 > installed: new RawContextKey<boolean>('chatSetupInstalled', false, true), // True when the chat extension is installed and enabled.
41 > disabled: new RawContextKey<boolean>('chatSetupDisabled', false, true), // True when the chat extension is disabled due to any other reason than workspace trust.
42 > disabledInWorkspace: new RawContextKey<boolean>('chatSetupDisabledInWorkspace', false, true), // True when chat is disabled at the workspace level via settings.
43 > untrusted: new RawContextKey<boolean>('chatSetupUntrusted', false, true), // True when the chat extension is disabled due to workspace trust.
44 > later: new RawContextKey<boolean>('chatSetupLater', false, true), // True when the user wants to finish setup later.
45 > registered: new RawContextKey<boolean>('chatSetupRegistered', false, true), // True when the user has registered as Free or Pro user.
46 > completed: new RawContextKey<boolean>('chatSetupCompleted', false, true) // True when the user has completed the setup flow, regardless of the outcome.
47 > };
48 >
49 > export const Entitlement = {
50 > signedOut: new RawContextKey<boolean>('chatEntitlementSignedOut', false, true), // True when user is signed out.
51 > canSignUp: new RawContextKey<boolean>('chatPlanCanSignUp', false, true), // True when user can sign up to be a chat free user.
52 >
53 > planFree: new RawContextKey<boolean>('chatPlanFree', false, true), // True when user is a chat free user.
54 > planPro: new RawContextKey<boolean>('chatPlanPro', false, true), // True when user is a chat pro user.
55 > planEdu: new RawContextKey<boolean>('chatPlanEdu', false, true), // True when user is a chat edu user.
56 > planProPlus: new RawContextKey<boolean>('chatPlanProPlus', false, true), // True when user is a chat pro plus user.
57 > planMax: new RawContextKey<boolean>('chatPlanMax', false, true), // True when user is a chat max user.
58 > planBusiness: new RawContextKey<boolean>('chatPlanBusiness', false, true), // True when user is a chat business user.
59 > planEnterprise: new RawContextKey<boolean>('chatPlanEnterprise', false, true), // True when user is a chat enterprise user.
60 >
61 > organisations: new RawContextKey<string[]>('chatEntitlementOrganisations', undefined, true), // The organizations the user belongs to.
62 > internal: new RawContextKey<boolean>('chatEntitlementInternal', false, true), // True when user belongs to internal organisation.
63 > sku: new RawContextKey<string>('chatEntitlementSku', undefined, true), // The SKU of the user.
64 > };
65 >
66 > export const chatQuotaExceeded = new RawContextKey<boolean>('chatQuotaExceeded', false, true);
67 > export const completionsQuotaExceeded = new RawContextKey<boolean>('completionsQuotaExceeded', false, true);
68 >
69 > export const chatAnonymous = new RawContextKey<boolean>('chatAnonymous', false, true);
70 >
71 > export const clientByokEnabled = new RawContextKey<boolean>('github.copilot.clientByokEnabled', true, true);
72 >
73 > export const hasByokModels = new RawContextKey<boolean>('github.copilot.hasByokModels', false, true);
74 > }
75 >
76 > export const IChatEntitlementService = createDecorator<IChatEntitlementService>('chatEntitlementService');
77 >
78 > export enum ChatEntitlement {
79 > /** Signed out */
80 > Unknown = 1,
81 > /** Signed in but not yet resolved */
82 > Unresolved = 2,
83 > /** Signed in and entitled to Free */
84 > Available = 3,
85 > /** Signed in but not entitled to Free */
86 > Unavailable = 4,
87 > /** Signed-up to Free */
88 > Free = 5,
89 > /** Signed-up to EDU */
90 > EDU = 10,
91 > /** Signed-up to Pro */
92 > Pro = 6,
93 > /** Signed-up to Pro Plus */
94 > ProPlus = 7,
95 > /** Signed-up to Business */
96 > Business = 8,
97 > /** Signed-up to Enterprise */
98 > Enterprise = 9,
99 > /** Signed-up to Max */
100 > Max = 11,
101 > }
102 >
103 > export interface IChatSentiment {
104 >
105 > /**
106 > * Whether the user has completed the setup flow or not, regardless of the outcome
107 > */
108 > completed?: boolean;
109 >
110 > /**
111 > * User has Chat installed.
112 > */
113 > installed?: boolean;
114 >
115 > /**
116 > * User signals no intent in using Chat.
117 > *
118 > * Note: in contrast to `disabled`, this should not only disable
119 > * Chat but also hide all of its UI.
120 > */
121 > hidden?: boolean;
122 >
123 > /**
124 > * User signals intent to disable Chat.
125 > *
126 > * Note: in contrast to `hidden`, this should not hide
127 > * Chat but but disable its functionality.
128 > */
129 > disabled?: boolean;
130 >
131 > /**
132 > * Chat is disabled at the workspace level
133 > *
134 > * Note: in contrast to `hidden` (which hides all UI globally),
135 > * this only disables Chat in the current workspace while
136 > * keeping its UI visible so the user can re-enable it.
137 > */
138 > disabledInWorkspace?: boolean;
139 >
140 > /**
141 > * Chat is disabled due to missing workspace trust.
142 > *
143 > * Note: even though this disables Chat, we want to treat it
144 > * different from the `disabled` state that is by explicit
145 > * user choice.
146 > */
147 > untrusted?: boolean;
148 >
149 > /**
150 > * User signals intent to use Chat later.
151 > */
152 > later?: boolean;
153 >
154 > /**
155 > * User has registered as Free or Pro user.
156 > */
157 > registered?: boolean;
158 > }
159 >
160 > /**
161 > * The inputs needed to decide whether Chat still requires the user to run setup
162 > * (sign in / sign up / trust / enable) before it can service a request.
163 > */
164 > export interface IChatSetupRequirement {
165 > /** Whether the setup flow has been completed (any outcome). */
166 > readonly completed: boolean;
167 > /** Whether the chat extension is disabled for a reason other than trust. */
168 > readonly disabled: boolean;
169 > /** Whether the chat extension is disabled because the workspace is untrusted. */
170 > readonly untrusted: boolean;
171 > /** The user's last known or resolved entitlement. */
172 > readonly entitlement: ChatEntitlement;
173 > /** Whether anonymous (signed-out) Chat access is enabled. */
174 > readonly anonymous: boolean;
175 > /** Whether BYOK models are available. */
176 > readonly hasByokModels: boolean;
177 > }
178 >
179 > /**
180 > * Single source of truth for whether Chat still requires setup before it can
181 > * service a request. Shared by the setup agent (which routes a sent message
182 > * through setup) and the model picker (which surfaces a "Sign in to use Copilot"
183 > * state instead of a misleading lone "Auto"). BYOK models and anonymous access
184 > * intentionally satisfy the entitlement-based checks so those flows keep working.
185 > */
186 > export function chatRequiresSetup(context: IChatSetupRequirement): boolean {
187 return (
188 (!context.completed && !context.hasByokModels) || // Setup not completed (unless BYOK models are available)
197 );
198 }
200 > export interface IChatEntitlementService {
201 >
202 > _serviceBrand: undefined;
203 >
204 > readonly onDidChangeEntitlement: Event<void>;
205 >
206 > readonly entitlement: ChatEntitlement;
207 > readonly entitlementObs: IObservable<ChatEntitlement>;
208 >
209 > readonly clientByokEnabled: boolean;
210 > readonly hasByokModels: boolean;
211 >
212 > readonly organisations: string[] | undefined;
213 > readonly isInternal: boolean;
214 > readonly sku: string | undefined;
215 > readonly copilotTrackingId: string | undefined;
216 >
217 > readonly onDidChangeQuotaExceeded: Event<void>;
218 > readonly onDidChangeQuotaRemaining: Event<void>;
219 > readonly onDidChangeUsageBasedBilling: Event<void>;
220 >
221 > readonly quotas: IQuotas;
222 >
223 > readonly onDidChangeSentiment: Event<void>;
224 >
225 > readonly sentiment: IChatSentiment;
226 > readonly sentimentObs: IObservable<IChatSentiment>;
227 >
228 > // TODO@bpasero eventually this will become enabled by default
229 > // and in that case we only need to check on entitlements change
230 > // between `unknown` and any other entitlement.
231 > readonly onDidChangeAnonymous: Event<void>;
232 > readonly anonymous: boolean;
233 > readonly anonymousObs: IObservable<boolean>;
234 >
235 > acceptQuotas(quotas: IQuotas): void;
236 >
237 > /**
238 > * Clear all quota state.
239 > */
240 > clearQuotas(): void;
241 >
242 > markAnonymousRateLimited(): void;
243 >
244 > /**
245 > * Mark the chat setup flow as completed.
246 > */
247 > markSetupCompleted(): void;
248 >
249 > /**
250 > * Force the hidden state on or off, overriding the normal entitlement logic.
251 > * Used by the account policy gate to hide all AI features when the gate is
252 > * active and unsatisfied.
253 > */
254 > setForceHidden(hidden: boolean): void;
255 >
256 > update(token: CancellationToken): Promise<void>;
257 > }
258 >
259 > //#region Helper Functions
260 >
261 > /**
262 > * Checks the chat entitlements to see if the user falls into the paid category
263 > * @param chatEntitlement The chat entitlement to check
264 > * @returns Whether or not they are a paid user
265 > */
266 > export function isProUser(chatEntitlement: ChatEntitlement): boolean {
267 return chatEntitlement === ChatEntitlement.EDU ||
268 chatEntitlement === ChatEntitlement.Pro ||
272 chatEntitlement === ChatEntitlement.Enterprise;
273 }
275 > /**
276 > * Gets the full plan name for the given chat entitlement
277 > * @param chatEntitlement The chat entitlement to get the plan name for
278 > * @returns The localized full plan name (e.g., "Copilot Pro", "Copilot Free")
279 > */
280 > export function getChatPlanName(chatEntitlement: ChatEntitlement): string {
281 switch (chatEntitlement) {
282 case ChatEntitlement.EDU:
296 }
297 }
299 > //#region Service Implementation
300 >
301 > const defaultChatAgent = {
302 > upgradePlanUrl: product.defaultChatAgent?.upgradePlanUrl ?? '',
303 > providerUriSetting: product.defaultChatAgent?.providerUriSetting ?? '',
304 > entitlementSignupLimitedUrl: product.defaultChatAgent?.entitlementSignupLimitedUrl ?? '',
305 > chatQuotaExceededContext: product.defaultChatAgent?.chatQuotaExceededContext ?? '',
306 > completionsQuotaExceededContext: product.defaultChatAgent?.completionsQuotaExceededContext ?? ''
307 > };
308 >
309 > interface IChatQuotasAccessor {
310 > clearQuotas(): void;
311 > acceptQuotas(quotas: IQuotas): void;
312 > }
313 >
314 > const CHAT_ALLOW_ANONYMOUS_CONFIGURATION_KEY = 'chat.allowAnonymousAccess';
315 >
316 function isAnonymous(configurationService: IConfigurationService, entitlement: ChatEntitlement, sentiment: IChatSentiment): boolean {
317 if (configurationService.getValue(CHAT_ALLOW_ANONYMOUS_CONFIGURATION_KEY) !== true) {
329 return true;
330 }
332 > type ChatEntitlementClassification = {
333 > owner: 'bpasero';
334 > comment: 'Provides insight into chat entitlements.';
335 > chatHidden: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether chat is hidden or not.' };
336 > chatEntitlement: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The current chat entitlement of the user.' };
337 > chatAnonymous: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether the user is anonymously using chat.' };
338 > chatRegistered: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether the user is registered for chat.' };
339 > chatDisabled: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether chat is disabled or not.' };
340 > };
341 > type ChatEntitlementEvent = {
342 > chatHidden: boolean;
343 > chatEntitlement: ChatEntitlement;
344 > chatAnonymous: boolean;
345 > chatRegistered: boolean;
346 > chatDisabled: boolean;
347 > };
348 >
349 function logChatEntitlements(state: IChatEntitlementContextState, configurationService: IConfigurationService, telemetryService: ITelemetryService): void {
350 telemetryService.publicLog2<ChatEntitlementEvent, ChatEntitlementClassification>('chatEntitlements', {
356 });
357 }
359 > type ChatAdditionalSpendConfigurationClassification = {
360 > owner: 'pwang347';
361 > comment: 'Tracks when a user enables or disables additional spend.';
362 > enabled: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether additional spend is now enabled or disabled.' };
363 > entitlement: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The current chat entitlement of the user.' };
364 > };
365 > type ChatAdditionalSpendConfigurationEvent = {
366 > enabled: boolean;
367 > entitlement: ChatEntitlement;
368 > };
369 >
370 > type ChatAdditionalSpendActiveClassification = {
371 > owner: 'pwang347';
372 > comment: 'Tracks when a user enters additional spend (included quota exhausted while additional spend is enabled).';
373 > entitlement: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The current chat entitlement of the user.' };
374 > additionalUsageCount: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'The number of additional spend interactions used so far.' };
375 > };
376 > type ChatAdditionalSpendActiveEvent = {
377 > entitlement: ChatEntitlement;
378 > additionalUsageCount: number;
379 > };
380 >
381 > export class ChatEntitlementService extends Disposable implements IChatEntitlementService {
382 >
383 > declare _serviceBrand: undefined;
384 >
385 > private static readonly CACHED_UBB_STORAGE_KEY = 'chat.usageBasedBilling';
386 >
387 > readonly context: Lazy<ChatEntitlementContext> | undefined;
388 > readonly requests: Lazy<ChatEntitlementRequests> | undefined;
389 >
390 > constructor(
391 @IInstantiationService instantiationService: IInstantiationService,
392 @IProductService productService: IProductService,
467 this.registerListeners();
468 }
470 > //#region --- Entitlements
471 >
472 > readonly onDidChangeEntitlement: Event<void>;
473 > readonly entitlementObs: IObservable<ChatEntitlement>;
474 >
475 > get entitlement(): ChatEntitlement {
476 if (this.contextKeyService.getContextKeyValue<boolean>(ChatEntitlementContextKeys.Entitlement.planEdu.key) === true) {
477 return ChatEntitlement.EDU;
496 return ChatEntitlement.Unresolved;
497 }
499 > get isInternal(): boolean {
500 return this.contextKeyService.getContextKeyValue<boolean>(ChatEntitlementContextKeys.Entitlement.internal.key) === true;
501 }
503 > get organisations(): string[] | undefined {
504 return this.contextKeyService.getContextKeyValue<string[]>(ChatEntitlementContextKeys.Entitlement.organisations.key);
505 }
507 > get sku(): string | undefined {
508 return this.contextKeyService.getContextKeyValue<string>(ChatEntitlementContextKeys.Entitlement.sku.key);
509 }
511 > get copilotTrackingId(): string | undefined {
512 return this.context?.value.state.copilotTrackingId;
513 }
515 > get clientByokEnabled(): boolean {
516 return this.contextKeyService.getContextKeyValue<boolean>('github.copilot.clientByokEnabled') === true;
517 }
519 > get hasByokModels(): boolean {
520 return this.contextKeyService.getContextKeyValue<boolean>('github.copilot.hasByokModels') === true;
521 }
523 > //#endregion
524 >
525 > //#region --- Quotas
526 >
527 > private readonly _onDidChangeQuotaExceeded = this._register(new Emitter<void>());
528 > readonly onDidChangeQuotaExceeded = this._onDidChangeQuotaExceeded.event;
529 >
530 > private readonly _onDidChangeQuotaRemaining = this._register(new Emitter<void>());
531 > readonly onDidChangeQuotaRemaining = this._onDidChangeQuotaRemaining.event;
532 >
533 > private readonly _onDidChangeUsageBasedBilling = this._register(new Emitter<void>());
534 > readonly onDidChangeUsageBasedBilling = this._onDidChangeUsageBasedBilling.event;
535 >
536 > private _quotas: IQuotas;
537 > private quotaCopilotTrackingId: string | undefined;
538 > get quotas() { return this._quotas; }
539 >
540 > private readonly chatQuotaExceededContextKey: IContextKey<boolean>;
541 > private readonly completionsQuotaExceededContextKey: IContextKey<boolean>;
542 >
543 > private ExtensionQuotaContextKeys = {
544 > chatQuotaExceeded: defaultChatAgent.chatQuotaExceededContext,
545 > completionsQuotaExceeded: defaultChatAgent.completionsQuotaExceededContext,
546 > };
547 >
548 > private registerListeners(): void {
549 const quotaExceededSet = new Set([this.ExtensionQuotaContextKeys.chatQuotaExceeded, this.ExtensionQuotaContextKeys.completionsQuotaExceeded]);
550
585 this._register(this.onDidChangeSentiment(() => updateAnonymousUsage()));
586 }
588 > acceptQuotas(incomingQuotas: IQuotas): void {
589 const oldQuota = this._quotas;
590 const cachedQuota = this.quotaCopilotTrackingId === this.copilotTrackingId ? oldQuota : {};
649 }
650 }
652 > private compareQuotas(oldQuota: IQuotaSnapshot | undefined, newQuota: IQuotaSnapshot | undefined): { changed: { exceeded: boolean; remaining: boolean } } {
653 return {
654 changed: {
659 };
660 }
662 > clearQuotas(): void {
663 this.acceptQuotas({});
664 }
666 > private updateContextKeys(): void {
667 const chatExhausted = this._quotas.chat?.percentRemaining === 0;
668 const premiumChatExhausted = this._quotas.premiumChat?.unlimited
677 this.completionsQuotaExceededContextKey.set(this._quotas.completions?.percentRemaining === 0);
678 }
680 > //#endregion
681 >
682 > //#region --- Sentiment
683 >
684 > readonly onDidChangeSentiment: Event<void>;
685 > readonly sentimentObs: IObservable<IChatSentiment>;
686 >
687 > get sentiment(): IChatSentiment {
688 return {
689 completed: this.contextKeyService.getContextKeyValue<boolean>(ChatEntitlementContextKeys.Setup.completed.key) === true,
697 };
698 }
700 > //#endregion
701 >
702 > //region --- Anonymous
703 >
704 > private readonly anonymousContextKey: IContextKey<boolean>;
705 >
706 > private readonly _onDidChangeAnonymous = this._register(new Emitter<void>());
707 > readonly onDidChangeAnonymous = this._onDidChangeAnonymous.event;
708 >
709 > readonly anonymousObs = observableFromEvent(this.onDidChangeAnonymous, () => this.anonymous);
710 >
711 > get anonymous(): boolean {
712 return isAnonymous(this.configurationService, this.entitlement, this.sentiment);
713 }
715 > //#endregion
716 >
717 > markAnonymousRateLimited(): void {
718 if (!this.anonymous) {
719 return;
723 this._onDidChangeQuotaExceeded.fire();
724 }
726 > markSetupCompleted(): void {
727 this.context?.value.update({ completed: true });
728 }
730 > setForceHidden(hidden: boolean): void {
731 if (this.context) {
732 this.context.value.setForceHidden(hidden);
737 }
738 }
740 > async update(token: CancellationToken): Promise<void> {
741 await this.requests?.value.forceResolveEntitlement(token);
742 }
744 >
745 > //#endregion
746 >
747 > //#region Chat Entitlement Request Service
748 >
749 > type EntitlementClassification = {
750 > tid: { classification: 'EndUserPseudonymizedInformation'; purpose: 'BusinessInsight'; comment: 'The anonymized analytics id returned by the service'; endpoint: 'GoogleAnalyticsId' };
751 > entitlement: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Flag indicating the chat entitlement state' };
752 > sku: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The SKU of the chat entitlement' };
753 > quotaChatUnlimited: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether the user has unlimited chat requests' };
754 > quotaChatHasQuota: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether the user currently has chat quota available' };
755 > quotaChatEntitlement: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'The raw chat quota entitlement count' };
756 > quotaPremiumChat: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'The percentage of premium chat requests remaining for the user' };
757 > quotaPremiumChatUnlimited: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether the user has unlimited premium chat requests' };
758 > quotaPremiumChatHasQuota: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether the user currently has premium chat quota available' };
759 > quotaPremiumChatEntitlement: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'The raw premium chat quota entitlement count' };
760 > quotaCompletions: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'The percentage of completions remaining for the user' };
761 > quotaCompletionsUnlimited: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether the user has unlimited completions' };
762 > quotaCompletionsHasQuota: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether the user currently has completions quota available' };
763 > quotaCompletionsEntitlement: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'The raw completions quota entitlement count' };
764 > quotaResetDate: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The date the quota will reset' };
765 > usageBasedBilling: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether the user is on usage-based billing' };
766 > additionalUsageEnabled: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether overage / additional spend is enabled' };
767 > additionalUsageCount: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'The number of overage interactions used' };
768 > canUpgradePlan: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether the user is eligible to upgrade their plan' };
769 > owner: 'bpasero';
770 > comment: 'Reporting chat entitlements';
771 > };
772 >
773 > type EntitlementEvent = {
774 > entitlement: ChatEntitlement;
775 > tid: string;
776 > sku: string | undefined;
777 > quotaChatUnlimited: boolean | undefined;
778 > quotaChatHasQuota: boolean | undefined;
779 > quotaChatEntitlement: number | undefined;
780 > quotaPremiumChat: number | undefined;
781 > quotaPremiumChatUnlimited: boolean | undefined;
782 > quotaPremiumChatHasQuota: boolean | undefined;
783 > quotaPremiumChatEntitlement: number | undefined;
784 > quotaCompletions: number | undefined;
785 > quotaCompletionsUnlimited: boolean | undefined;
786 > quotaCompletionsHasQuota: boolean | undefined;
787 > quotaCompletionsEntitlement: number | undefined;
788 > quotaResetDate: string | undefined;
789 > usageBasedBilling: boolean | undefined;
790 > additionalUsageEnabled: boolean | undefined;
791 > additionalUsageCount: number | undefined;
792 > canUpgradePlan: boolean | undefined;
793 > };
794 >
795 > interface IEntitlements {
796 > readonly entitlement: ChatEntitlement;
797 > readonly organisations?: string[];
798 > readonly sku?: string;
799 > readonly copilotTrackingId?: string;
800 > readonly quotas?: IQuotas;
801 > }
802 >
803 > export interface IQuotaSnapshot {
804 > readonly percentRemaining: number;
805 > readonly unlimited: boolean;
806 > readonly hasQuota?: boolean;
807 > readonly resetAt?: number;
808 > readonly usageBasedBilling?: boolean;
809 > readonly entitlement?: number;
810 > readonly quotaRemaining?: number;
811 > readonly creditsUsed?: number;
812 > }
813 >
814 > export interface IRateLimitSnapshot {
815 > readonly percentRemaining: number;
816 > readonly unlimited: boolean;
817 > readonly resetDate?: string;
818 > }
819 >
820 > interface IQuotas {
821 > readonly resetDate?: string;
822 > readonly resetDateHasTime?: boolean;
823 >
824 > readonly usageBasedBilling?: boolean;
825 > readonly canUpgradePlan?: boolean;
826 >
827 > readonly chat?: IQuotaSnapshot;
828 > readonly completions?: IQuotaSnapshot;
829 > readonly premiumChat?: IQuotaSnapshot;
830 > readonly additionalUsageEnabled?: boolean;
831 > readonly additionalUsageCount?: number;
832 > readonly additionalUsageEntitlement?: number;
833 >
834 > readonly sessionRateLimit?: IRateLimitSnapshot;
835 > readonly weeklyRateLimit?: IRateLimitSnapshot;
836 > }
837 >
838 function mergeDefinedSnapshot<T extends object>(previous: T | undefined, current: T): T {
839 const result = { ...previous, ...current };
845 return result;
846 }
848 > export function parseQuotas(entitlementsData: IEntitlementsData): IQuotas {
849 const quotas: Mutable<IQuotas> = {
850 resetDate: entitlementsData.quota_reset_date_utc ?? entitlementsData.quota_reset_date ?? entitlementsData.limited_user_reset_date,
919 return quotas;
920 }
922 > export class ChatEntitlementRequests extends Disposable {
923 >
924 > private state: IEntitlements;
925 >
926 > private pendingResolveCts = new CancellationTokenSource();
927 >
928 > constructor(
929 private readonly context: ChatEntitlementContext,
930 private readonly chatQuotasAccessor: IChatQuotasAccessor,
946 this.resolve();
947 }
949 > private registerListeners(): void {
950 this._register(this.defaultAccountService.onDidChangeDefaultAccount(() => this.resolve()));
951
959 }));
960 }
962 > private async resolve(): Promise<void> {
963 this.pendingResolveCts.dispose(true);
964 const cts = this.pendingResolveCts = new CancellationTokenSource();
989 }
990 }
992 > private async resolveEntitlement(defaultAccount: IDefaultAccount, token: CancellationToken): Promise<IEntitlements | undefined> {
993 const entitlements = await this.doResolveEntitlement(defaultAccount, token);
994 if (typeof entitlements?.entitlement === 'number' && !token.isCancellationRequested) {
997 return entitlements;
998 }
1000 > private async doResolveEntitlement(defaultAccount: IDefaultAccount, token: CancellationToken): Promise<IEntitlements | undefined> {
1001 if (token.isCancellationRequested) {
1002 return undefined;
1065 return entitlements;
1066 }
1068 > private toQuotas(entitlementsData: IEntitlementsData): IQuotas {
1069 return parseQuotas(entitlementsData);
1070 }
1072 > private async request(url: string, type: 'GET', body: undefined, sessions: AuthenticationSession[], token: CancellationToken, callSite: string): Promise<IRequestContext | undefined>;
1073 > private async request(url: string, type: 'POST', body: object, sessions: AuthenticationSession[], token: CancellationToken, callSite: string): Promise<IRequestContext | undefined>;
1074 > private async request(url: string, type: 'GET' | 'POST', body: object | undefined, sessions: AuthenticationSession[], token: CancellationToken, callSite: string): Promise<IRequestContext | undefined> {
1075 let lastRequest: IRequestContext | undefined;
1076
1108 return lastRequest;
1109 }
1111 > private update(state: IEntitlements): void {
1112 this.state = state;
1113
1118 }
1119 }
1121 > async forceResolveEntitlement(token = CancellationToken.None): Promise<IEntitlements | undefined> {
1122 const defaultAccount = await this.defaultAccountService.refresh({ forceRefresh: true });
1123 if (!defaultAccount) {
1127 return this.resolveEntitlement(defaultAccount, token);
1128 }
1130 > async signUpFree(): Promise<true /* signed up */ | false /* already signed up */ | { errorCode: number } /* error */ | undefined /* no session */> {
1131 const sessions = await this.getSessions();
1132 if (sessions.length === 0) {
1135 return this.doSignUpFree(sessions);
1136 }
1138 > private async doSignUpFree(sessions: AuthenticationSession[]): Promise<true /* signed up */ | false /* already signed up */ | { errorCode: number } /* error */> {
1139 const body = {
1140 restricted_telemetry: this.telemetryService.telemetryLevel === TelemetryLevel.NONE ? 'disabled' : 'enabled',
1194 return Boolean(parsedResult?.subscribed);
1195 }
1197 > private async getSessions(): Promise<AuthenticationSession[]> {
1198 const defaultAccount = await this.defaultAccountService.getDefaultAccount();
1199 if (defaultAccount) {
1206 return [...(await this.authenticationService.getSessions(this.defaultAccountService.getDefaultAccountAuthenticationProvider().id))];
1207 }
1209 > private async onUnknownSignUpError(detail: string, logMessage: string): Promise<boolean> {
1210 this.logService.error(logMessage);
1211
1223 return false;
1224 }
1226 > private onUnprocessableSignUpError(logMessage: string, logDetails: string): void {
1227 this.logService.error(logMessage);
1228
1245 }
1246 }
1248 > async signIn(options?: { useSocialProvider?: string; additionalScopes?: readonly string[] }): Promise<{ defaultAccount?: IDefaultAccount; entitlements?: IEntitlements }> {
1249 const defaultAccount = await this.defaultAccountService.signIn({
1250 additionalScopes: options?.additionalScopes,
1259 return { defaultAccount, entitlements };
1260 }
1262 > override dispose(): void {
1263 this.pendingResolveCts.dispose(true);
1264
1265 super.dispose();
1266 }
1268 >
1269 > //#endregion
1270 >
1271 > //#region Context
1272 >
1273 > export interface IChatEntitlementContextState extends IChatSentiment {
1274 >
1275 > /**
1276 > * Users last known or resolved entitlement.
1277 > */
1278 > entitlement: ChatEntitlement;
1279 >
1280 > /**
1281 > * User's last known or resolved raw SKU type.
1282 > */
1283 > sku: string | undefined;
1284 >
1285 > /**
1286 > * User's last known or resolved organisations.
1287 > */
1288 > organisations: string[] | undefined;
1289 >
1290 > /**
1291 > * User's Copilot tracking ID from the entitlement API.
1292 > */
1293 > copilotTrackingId: string | undefined;
1294 > }
1295 >
1296 > export class ChatEntitlementContext extends Disposable {
1297 >
1298 > private static readonly CHAT_ENTITLEMENT_CONTEXT_STORAGE_KEY = 'chat.setupContext';
1299 > private static readonly CHAT_ENTITLEMENT_CONTEXT_MIGRATED_STORAGE_KEY = 'chat.setupContext.migrated.v1';
1300 >
1301 > private static readonly CHAT_DISABLED_CONFIGURATION_KEY = 'chat.disableAIFeatures';
1302 >
1303 > private readonly canSignUpContextKey: IContextKey<boolean>;
1304 > private readonly signedOutContextKey: IContextKey<boolean>;
1305 >
1306 > private readonly freeContextKey: IContextKey<boolean>;
1307 > private readonly eduContextKey: IContextKey<boolean>;
1308 > private readonly proContextKey: IContextKey<boolean>;
1309 > private readonly proPlusContextKey: IContextKey<boolean>;
1310 > private readonly maxContextKey: IContextKey<boolean>;
1311 > private readonly businessContextKey: IContextKey<boolean>;
1312 > private readonly enterpriseContextKey: IContextKey<boolean>;
1313 >
1314 > private readonly organisationsContextKey: IContextKey<string[] | undefined>;
1315 > private readonly isInternalContextKey: IContextKey<boolean>;
1316 > private readonly skuContextKey: IContextKey<string | undefined>;
1317 >
1318 > private readonly completedContext: IContextKey<boolean>;
1319 > private readonly hiddenContext: IContextKey<boolean>;
1320 > private readonly disabledInWorkspaceContext: IContextKey<boolean>;
1321 > private readonly laterContext: IContextKey<boolean>;
1322 > private readonly installedContext: IContextKey<boolean>;
1323 > private readonly disabledContext: IContextKey<boolean>;
1324 > private readonly untrustedContext: IContextKey<boolean>;
1325 > private readonly registeredContext: IContextKey<boolean>;
1326 >
1327 > private _state: IChatEntitlementContextState;
1328 > private suspendedState: IChatEntitlementContextState | undefined = undefined;
1329 > get state(): IChatEntitlementContextState { return this.withConfiguration(this.suspendedState ?? this._state); }
1330 >
1331 > private readonly _onDidChange = this._register(new Emitter<void>());
1332 > readonly onDidChange = this._onDidChange.event;
1333 >
1334 > private updateBarrier: Barrier | undefined = undefined;
1335 >
1336 > constructor(
1337 @IContextKeyService contextKeyService: IContextKeyService,
1338 @IStorageService private readonly storageService: IStorageService,
1387 this.registerListeners();
1388 }
1390 > private registerListeners(): void {
1391 this._register(this.configurationService.onDidChangeConfiguration(e => {
1392 if (e.affectsConfiguration(ChatEntitlementContext.CHAT_DISABLED_CONFIGURATION_KEY)) {
1395 }));
1396 }
1398 > private _forceHidden = false;
1399 >
1400 > private withConfiguration(state: IChatEntitlementContextState): IChatEntitlementContextState {
1401 if (this._forceHidden || this.configurationService.getValue(ChatEntitlementContext.CHAT_DISABLED_CONFIGURATION_KEY) === true) {
1402 return {
1408 return state;
1409 }
1411 > setForceHidden(hidden: boolean): void {
1412 if (this._forceHidden !== hidden) {
1413 this._forceHidden = hidden;
1415 }
1416 }
1418 > update(context: { installed: boolean; disabled: boolean; untrusted: boolean; disabledInWorkspace: boolean }): Promise<void>;
1419 > update(context: { completed: true }): Promise<void>;
1420 > update(context: { hidden: false }): Promise<void>; // legacy UI state from before we had a setting to hide, keep around to still support users who used this
1421 > update(context: { later: boolean }): Promise<void>;
1422 > update(context: { entitlement: ChatEntitlement; organisations: string[] | undefined; sku: string | undefined; copilotTrackingId: string | undefined }): Promise<void>;
1423 > async update(context: { completed?: boolean; installed?: boolean; disabled?: boolean; untrusted?: boolean; disabledInWorkspace?: boolean; hidden?: false; later?: boolean; entitlement?: ChatEntitlement; organisations?: string[]; sku?: string; copilotTrackingId?: string }): Promise<void> {
1424 this.logService.trace(`[chat entitlement context] update(): ${JSON.stringify(context)}`);
1425
1477 return this.updateContext();
1478 }
1480 > private async updateContext(): Promise<void> {
1481 await this.updateBarrier?.wait();
1482
1483 this.updateContextSync();
1484 }
1486 > private updateContextSync(): void {
1487 const state = this.withConfiguration(this._state);
1488
1516 this._onDidChange.fire();
1517 }
1519 > suspend(): void {
1520 this.suspendedState = { ...this._state };
1521 this.updateBarrier = new Barrier();
1522 }
1524 > resume(): void {
1525 this.suspendedState = undefined;
1526 this.updateBarrier?.open();
1527 this.updateBarrier = undefined;
1528 }
1530 >
1531 > //#endregion
1532 >
1533 > registerSingleton(IChatEntitlementService, ChatEntitlementService, InstantiationType.Eager /* To ensure context keys are set asap */);
src/vs/workbench/services/extensions/common/extensionsRegistry.ts 641 covered LOC · 19 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extensionsRegistry.ts
2 > * Copyright (c) Microsoft 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 { IJSONSchema } from '../../../../base/common/jsonSchema.js';
9 > import Severity from '../../../../base/common/severity.js';
10 > import { EXTENSION_IDENTIFIER_PATTERN } from '../../../../platform/extensionManagement/common/extensionManagement.js';
11 > import { Extensions, IJSONContributionRegistry } from '../../../../platform/jsonschemas/common/jsonContributionRegistry.js';
12 > import { Registry } from '../../../../platform/registry/common/platform.js';
13 > import { IMessage } from './extensions.js';
14 > import { IExtensionDescription, EXTENSION_CATEGORIES, ExtensionIdentifierSet } from '../../../../platform/extensions/common/extensions.js';
15 > import { ExtensionKind } from '../../../../platform/environment/common/environment.js';
16 > import { productSchemaId } from '../../../../platform/product/common/productService.js';
17 > import { ImplicitActivationEvents, IActivationEventsGenerator } from '../../../../platform/extensionManagement/common/implicitActivationEvents.js';
18 > import { IDisposable } from '../../../../base/common/lifecycle.js';
19 > import { allApiProposals } from '../../../../platform/extensions/common/extensionsApiProposals.js';
20 >
21 > const schemaRegistry = Registry.as<IJSONContributionRegistry>(Extensions.JSONContribution);
22 >
23 > export class ExtensionMessageCollector {
24 >
25 > private readonly _messageHandler: (msg: IMessage) => void;
26 > private readonly _extension: IExtensionDescription;
27 > private readonly _extensionPointId: string;
28 >
29 > constructor(
30 messageHandler: (msg: IMessage) => void,
31 extension: IExtensionDescription,
36 this._extensionPointId = extensionPointId;
37 }
39 > private _msg(type: Severity, message: string): void {
40 this._messageHandler({
41 type: type,
45 });
46 }
48 > public error(message: string): void {
49 this._msg(Severity.Error, message);
50 }
52 > public warn(message: string): void {
53 this._msg(Severity.Warning, message);
54 }
56 > public info(message: string): void {
57 this._msg(Severity.Info, message);
58 }
60 >
61 > export interface IExtensionPointUser<T> {
62 > description: IExtensionDescription;
63 > value: T;
64 > collector: ExtensionMessageCollector;
65 > }
66 >
67 > export type IExtensionPointHandler<T> = (extensions: readonly IExtensionPointUser<T>[], delta: ExtensionPointUserDelta<T>) => void;
68 >
69 > export interface IExtensionPoint<T> {
70 > readonly name: string;
71 > setHandler(handler: IExtensionPointHandler<T>): IDisposable;
72 > readonly defaultExtensionKind: ExtensionKind[] | undefined;
73 > readonly canHandleResolver?: boolean;
74 > }
75 >
76 > export class ExtensionPointUserDelta<T> {
77 >
78 > private static _toSet<T>(arr: readonly IExtensionPointUser<T>[]): ExtensionIdentifierSet {
79 > const result = new ExtensionIdentifierSet();
80 > for (let i = 0, len = arr.length; i < len; i++) {
81 > result.add(arr[i].description.identifier);
82 > }
83 > return result;
84 > }
85 >
86 > public static compute<T>(previous: readonly IExtensionPointUser<T>[] | null, current: readonly IExtensionPointUser<T>[]): ExtensionPointUserDelta<T> {
87 if (!previous || !previous.length) {
88 return new ExtensionPointUserDelta<T>(current, []);
100 return new ExtensionPointUserDelta<T>(added, removed);
101 }
103 > constructor(
104 public readonly added: readonly IExtensionPointUser<T>[],
105 public readonly removed: readonly IExtensionPointUser<T>[],
106 ) { }
108 >
109 > export class ExtensionPoint<T> implements IExtensionPoint<T> {
110 >
111 > public readonly name: string;
112 > public readonly defaultExtensionKind: ExtensionKind[] | undefined;
113 > public readonly canHandleResolver?: boolean;
114 >
115 > private _handler: IExtensionPointHandler<T> | null;
116 > private _users: IExtensionPointUser<T>[] | null;
117 > private _delta: ExtensionPointUserDelta<T> | null;
118 >
119 > constructor(name: string, defaultExtensionKind: ExtensionKind[] | undefined, canHandleResolver?: boolean) {
120 > this.name = name; extensionsRegistry.ts
121 > this.defaultExtensionKind = defaultExtensionKind;
122 > this.canHandleResolver = canHandleResolver;
123 > this._handler = null;
124 > this._users = null;
125 > this._delta = null;
126 > }
128 > setHandler(handler: IExtensionPointHandler<T>): IDisposable {
129 if (this._handler !== null) {
130 throw new Error('Handler already set!');
139 };
140 }
142 > acceptUsers(users: IExtensionPointUser<T>[]): void {
143 this._delta = ExtensionPointUserDelta.compute(this._users, users);
144 this._users = users;
145 this._handle();
146 }
148 > private _handle(): void {
149 if (this._handler === null || this._users === null || this._delta === null) {
150 return;
157 }
158 }
160 >
161 > const extensionKindSchema: IJSONSchema = {
162 > type: 'string',
163 > enum: [
164 > 'ui',
165 > 'workspace'
166 > ],
167 > enumDescriptions: [
168 > nls.localize('ui', "UI extension kind. In a remote window, such extensions are enabled only when available on the local machine."),
169 > nls.localize('workspace', "Workspace extension kind. In a remote window, such extensions are enabled only when available on the remote."),
170 > ],
171 > };
172 >
173 > const schemaId = 'vscode://schemas/vscode-extensions';
174 > export const schema: IJSONSchema = {
175 > properties: {
176 > engines: {
177 > type: 'object',
178 > description: nls.localize('vscode.extension.engines', "Engine compatibility."),
179 > properties: {
180 > 'vscode': {
181 > type: 'string',
182 > description: nls.localize('vscode.extension.engines.vscode', 'For VS Code extensions, specifies the VS Code version that the extension is compatible with. Cannot be *. For example: ^1.105.0 indicates compatibility with a minimum VS Code version of 1.105.0.'),
183 > default: '^1.105.0',
184 > }
185 > }
186 > },
187 > publisher: {
188 > description: nls.localize('vscode.extension.publisher', 'The publisher of the VS Code extension.'),
189 > type: 'string'
190 > },
191 > displayName: {
192 > description: nls.localize('vscode.extension.displayName', 'The display name for the extension used in the VS Code gallery.'),
193 > type: 'string'
194 > },
195 > categories: {
196 > description: nls.localize('vscode.extension.categories', 'The categories used by the VS Code gallery to categorize the extension.'),
197 > type: 'array',
198 > uniqueItems: true,
199 > items: {
200 > oneOf: [{
201 > type: 'string',
202 > enum: EXTENSION_CATEGORIES,
203 > },
204 > {
205 > type: 'string',
206 > const: 'Languages',
207 > deprecationMessage: nls.localize('vscode.extension.category.languages.deprecated', 'Use \'Programming Languages\' instead'),
208 > }]
209 > }
210 > },
211 > galleryBanner: {
212 > type: 'object',
213 > description: nls.localize('vscode.extension.galleryBanner', 'Banner used in the VS Code marketplace.'),
214 > properties: {
215 > color: {
216 > description: nls.localize('vscode.extension.galleryBanner.color', 'The banner color on the VS Code marketplace page header.'),
217 > type: 'string'
218 > },
219 > theme: {
220 > description: nls.localize('vscode.extension.galleryBanner.theme', 'The color theme for the font used in the banner.'),
221 > type: 'string',
222 > enum: ['dark', 'light']
223 > }
224 > }
225 > },
226 > contributes: {
227 > description: nls.localize('vscode.extension.contributes', 'All contributions of the VS Code extension represented by this package.'),
228 > type: 'object',
229 > // eslint-disable-next-line local/code-no-any-casts
230 > properties: {
231 > // extensions will fill in
232 > } as any as { [key: string]: any },
233 > default: {}
234 > },
235 > preview: {
236 > type: 'boolean',
237 > description: nls.localize('vscode.extension.preview', 'Sets the extension to be flagged as a Preview in the Marketplace.'),
238 > },
239 > enableProposedApi: {
240 > type: 'boolean',
241 > deprecationMessage: nls.localize('vscode.extension.enableProposedApi.deprecated', 'Use `enabledApiProposals` instead.'),
242 > },
243 > enabledApiProposals: {
244 > markdownDescription: nls.localize('vscode.extension.enabledApiProposals', 'Enable API proposals to try them out. Only valid **during development**. Extensions **cannot be published** with this property. For more details visit: https://code.visualstudio.com/api/advanced-topics/using-proposed-api'),
245 > type: 'array',
246 > uniqueItems: true,
247 > items: {
248 > type: 'string',
249 > enum: Object.keys(allApiProposals).map(proposalName => proposalName),
250 > markdownEnumDescriptions: Object.values(allApiProposals).map(value => value.proposal)
251 > }
252 > },
253 > api: {
254 > markdownDescription: nls.localize('vscode.extension.api', 'Describe the API provided by this extension. For more details visit: https://code.visualstudio.com/api/advanced-topics/remote-extensions#handling-dependencies-with-remote-extensions'),
255 > type: 'string',
256 > enum: ['none'],
257 > enumDescriptions: [
258 > nls.localize('vscode.extension.api.none', "Give up entirely the ability to export any APIs. This allows other extensions that depend on this extension to run in a separate extension host process or in a remote machine.")
259 > ]
260 > },
261 > activationEvents: {
262 > description: nls.localize('vscode.extension.activationEvents', 'Activation events for the VS Code extension.'),
263 > type: 'array',
264 > items: {
265 > type: 'string',
266 > defaultSnippets: [
267 > {
268 > label: 'onWebviewPanel',
269 > description: nls.localize('vscode.extension.activationEvents.onWebviewPanel', 'An activation event emitted when a webview is loaded of a certain viewType'),
270 > body: 'onWebviewPanel:viewType'
271 > },
272 > {
273 > label: 'onLanguage',
274 > description: nls.localize('vscode.extension.activationEvents.onLanguage', 'An activation event emitted whenever a file that resolves to the specified language gets opened.'),
275 > body: 'onLanguage:${1:languageId}'
276 > },
277 > {
278 > label: 'onCommand',
279 > description: nls.localize('vscode.extension.activationEvents.onCommand', 'An activation event emitted whenever the specified command gets invoked.'),
280 > body: 'onCommand:${2:commandId}'
281 > },
282 > {
283 > label: 'onDebug',
284 > description: nls.localize('vscode.extension.activationEvents.onDebug', 'An activation event emitted whenever a user is about to start debugging or about to setup debug configurations.'),
285 > body: 'onDebug'
286 > },
287 > {
288 > label: 'onDebugInitialConfigurations',
289 > description: nls.localize('vscode.extension.activationEvents.onDebugInitialConfigurations', 'An activation event emitted whenever a "launch.json" needs to be created (and all provideDebugConfigurations methods need to be called).'),
290 > body: 'onDebugInitialConfigurations'
291 > },
292 > {
293 > label: 'onDebugDynamicConfigurations',
294 > description: nls.localize('vscode.extension.activationEvents.onDebugDynamicConfigurations', 'An activation event emitted whenever a list of all debug configurations needs to be created (and all provideDebugConfigurations methods for the "dynamic" scope need to be called).'),
295 > body: 'onDebugDynamicConfigurations'
296 > },
297 > {
298 > label: 'onDebugResolve',
299 > description: nls.localize('vscode.extension.activationEvents.onDebugResolve', 'An activation event emitted whenever a debug session with the specific type is about to be launched (and a corresponding resolveDebugConfiguration method needs to be called).'),
300 > body: 'onDebugResolve:${6:type}'
301 > },
302 > {
303 > label: 'onDebugAdapterProtocolTracker',
304 > description: nls.localize('vscode.extension.activationEvents.onDebugAdapterProtocolTracker', 'An activation event emitted whenever a debug session with the specific type is about to be launched and a debug protocol tracker might be needed.'),
305 > body: 'onDebugAdapterProtocolTracker:${6:type}'
306 > },
307 > {
308 > label: 'workspaceContains',
309 > description: nls.localize('vscode.extension.activationEvents.workspaceContains', 'An activation event emitted whenever a folder is opened that contains at least a file matching the specified glob pattern.'),
310 > body: 'workspaceContains:${4:filePattern}'
311 > },
312 > {
313 > label: 'onStartupFinished',
314 > description: nls.localize('vscode.extension.activationEvents.onStartupFinished', 'An activation event emitted after the start-up finished (after all `*` activated extensions have finished activating).'),
315 > body: 'onStartupFinished'
316 > },
317 > {
318 > label: 'onTaskType',
319 > description: nls.localize('vscode.extension.activationEvents.onTaskType', 'An activation event emitted whenever tasks of a certain type need to be listed or resolved.'),
320 > body: 'onTaskType:${1:taskType}'
321 > },
322 > {
323 > label: 'onFileSystem',
324 > description: nls.localize('vscode.extension.activationEvents.onFileSystem', 'An activation event emitted whenever a file or folder is accessed with the given scheme.'),
325 > body: 'onFileSystem:${1:scheme}'
326 > },
327 > {
328 > label: 'onEditSession',
329 > description: nls.localize('vscode.extension.activationEvents.onEditSession', 'An activation event emitted whenever an edit session is accessed with the given scheme.'),
330 > body: 'onEditSession:${1:scheme}'
331 > },
332 > {
333 > label: 'onSearch',
334 > description: nls.localize('vscode.extension.activationEvents.onSearch', 'An activation event emitted whenever a search is started in the folder with the given scheme.'),
335 > body: 'onSearch:${7:scheme}'
336 > },
337 > {
338 > label: 'onView',
339 > body: 'onView:${5:viewId}',
340 > description: nls.localize('vscode.extension.activationEvents.onView', 'An activation event emitted whenever the specified view is expanded.'),
341 > },
342 > {
343 > label: 'onUri',
344 > body: 'onUri',
345 > description: nls.localize('vscode.extension.activationEvents.onUri', 'An activation event emitted whenever a system-wide Uri directed towards this extension is open.'),
346 > },
347 > {
348 > label: 'onOpenExternalUri',
349 > body: 'onOpenExternalUri',
350 > description: nls.localize('vscode.extension.activationEvents.onOpenExternalUri', 'An activation event emitted whenever a external uri (such as an http or https link) is being opened.'),
351 > },
352 > {
353 > label: 'onCustomEditor',
354 > body: 'onCustomEditor:${9:viewType}',
355 > description: nls.localize('vscode.extension.activationEvents.onCustomEditor', 'An activation event emitted whenever the specified custom editor becomes visible.'),
356 > },
357 > {
358 > label: 'onNotebook',
359 > body: 'onNotebook:${1:type}',
360 > description: nls.localize('vscode.extension.activationEvents.onNotebook', 'An activation event emitted whenever the specified notebook document is opened.'),
361 > },
362 > {
363 > label: 'onAuthenticationRequest',
364 > body: 'onAuthenticationRequest:${11:authenticationProviderId}',
365 > description: nls.localize('vscode.extension.activationEvents.onAuthenticationRequest', 'An activation event emitted whenever sessions are requested from the specified authentication provider.')
366 > },
367 > {
368 > label: 'onRenderer',
369 > description: nls.localize('vscode.extension.activationEvents.onRenderer', 'An activation event emitted whenever a notebook output renderer is used.'),
370 > body: 'onRenderer:${11:rendererId}'
371 > },
372 > {
373 > label: 'onTerminalProfile',
374 > body: 'onTerminalProfile:${1:terminalId}',
375 > description: nls.localize('vscode.extension.activationEvents.onTerminalProfile', 'An activation event emitted when a specific terminal profile is launched.'),
376 > },
377 > {
378 > label: 'onTerminalQuickFixRequest',
379 > body: 'onTerminalQuickFixRequest:${1:quickFixId}',
380 > description: nls.localize('vscode.extension.activationEvents.onTerminalQuickFixRequest', 'An activation event emitted when a command matches the selector associated with this ID'),
381 > },
382 > {
383 > label: 'onWalkthrough',
384 > body: 'onWalkthrough:${1:walkthroughID}',
385 > description: nls.localize('vscode.extension.activationEvents.onWalkthrough', 'An activation event emitted when a specified walkthrough is opened.'),
386 > },
387 > {
388 > label: 'onIssueReporterOpened',
389 > body: 'onIssueReporterOpened',
390 > description: nls.localize('vscode.extension.activationEvents.onIssueReporterOpened', 'An activation event emitted when the issue reporter is opened.'),
391 > },
392 > {
393 > label: 'onChatParticipant',
394 > body: 'onChatParticipant:${1:participantId}',
395 > description: nls.localize('vscode.extension.activationEvents.onChatParticipant', 'An activation event emitted when the specified chat participant is invoked.'),
396 > },
397 > {
398 > label: 'onChatContextProvider',
399 > body: 'onChatContextProvider:${1:contextProviderId}',
400 > description: nls.localize('vscode.extension.activationEvents.onChatContextProvider', 'An activation event emitted when the specified chat context provider is invoked.'),
401 > },
402 > {
403 > label: 'onLanguageModelChatProvider',
404 > body: 'onLanguageModelChatProvider:${1:vendor}',
405 > description: nls.localize('vscode.extension.activationEvents.onLanguageModelChatProvider', 'An activation event emitted when a chat model provider for the given vendor is requested.'),
406 > },
407 > {
408 > label: 'onLanguageModelTool',
409 > body: 'onLanguageModelTool:${1:toolId}',
410 > description: nls.localize('vscode.extension.activationEvents.onLanguageModelTool', 'An activation event emitted when the specified language model tool is invoked.'),
411 > },
412 > {
413 > label: 'onTerminal',
414 > body: 'onTerminal:{1:shellType}',
415 > description: nls.localize('vscode.extension.activationEvents.onTerminal', 'An activation event emitted when a terminal of the given shell type is opened.'),
416 > },
417 > {
418 > label: 'onTerminalShellIntegration',
419 > body: 'onTerminalShellIntegration:${1:shellType}',
420 > description: nls.localize('vscode.extension.activationEvents.onTerminalShellIntegration', 'An activation event emitted when terminal shell integration is activated for the given shell type.'),
421 > },
422 > {
423 > label: 'onMcpCollection',
424 > description: nls.localize('vscode.extension.activationEvents.onMcpCollection', 'An activation event emitted whenever a tool from the MCP server is requested.'),
425 > body: 'onMcpCollection:${2:collectionId}',
426 > },
427 > {
428 > label: '*',
429 > description: nls.localize('vscode.extension.activationEvents.star', 'An activation event emitted on VS Code startup. To ensure a great end user experience, please use this activation event in your extension only when no other activation events combination works in your use-case.'),
430 > body: '*'
431 > }
432 > ],
433 > }
434 > },
435 > badges: {
436 > type: 'array',
437 > description: nls.localize('vscode.extension.badges', 'Array of badges to display in the sidebar of the Marketplace\'s extension page.'),
438 > items: {
439 > type: 'object',
440 > required: ['url', 'href', 'description'],
441 > properties: {
442 > url: {
443 > type: 'string',
444 > description: nls.localize('vscode.extension.badges.url', 'Badge image URL.')
445 > },
446 > href: {
447 > type: 'string',
448 > description: nls.localize('vscode.extension.badges.href', 'Badge link.')
449 > },
450 > description: {
451 > type: 'string',
452 > description: nls.localize('vscode.extension.badges.description', 'Badge description.')
453 > }
454 > }
455 > }
456 > },
457 > markdown: {
458 > type: 'string',
459 > description: nls.localize('vscode.extension.markdown', "Controls the Markdown rendering engine used in the Marketplace. Either github (default) or standard."),
460 > enum: ['github', 'standard'],
461 > default: 'github'
462 > },
463 > qna: {
464 > default: 'marketplace',
465 > description: nls.localize('vscode.extension.qna', "Controls the Q&A link in the Marketplace. Set to marketplace to enable the default Marketplace Q & A site. Set to a string to provide the URL of a custom Q & A site. Set to false to disable Q & A altogether."),
466 > anyOf: [
467 > {
468 > type: ['string', 'boolean'],
469 > enum: ['marketplace', false]
470 > },
471 > {
472 > type: 'string'
473 > }
474 > ]
475 > },
476 > extensionDependencies: {
477 > description: nls.localize('vscode.extension.extensionDependencies', 'Dependencies to other extensions. The identifier of an extension is always ${publisher}.${name}. For example: vscode.csharp.'),
478 > type: 'array',
479 > uniqueItems: true,
480 > items: {
481 > type: 'string',
482 > pattern: EXTENSION_IDENTIFIER_PATTERN
483 > }
484 > },
485 > extensionAffinity: {
486 > description: nls.localize('vscode.extension.extensionAffinity', 'Extensions that this extension should be colocated with in the same extension host process if possible. The identifier of an extension is always ${publisher}.${name}. For example: vscode.git.'),
487 > type: 'array',
488 > uniqueItems: true,
489 > items: {
490 > type: 'string',
491 > pattern: EXTENSION_IDENTIFIER_PATTERN
492 > }
493 > },
494 > extensionPack: {
495 > description: nls.localize('vscode.extension.contributes.extensionPack', "A set of extensions that can be installed together. The identifier of an extension is always ${publisher}.${name}. For example: vscode.csharp."),
496 > type: 'array',
497 > uniqueItems: true,
498 > items: {
499 > type: 'string',
500 > pattern: EXTENSION_IDENTIFIER_PATTERN
501 > }
502 > },
503 > extensionKind: {
504 > description: nls.localize('extensionKind', "Define the kind of an extension. `ui` extensions are installed and run on the local machine while `workspace` extensions run on the remote."),
505 > type: 'array',
506 > items: extensionKindSchema,
507 > default: ['workspace'],
508 > defaultSnippets: [
509 > {
510 > body: ['ui'],
511 > description: nls.localize('extensionKind.ui', "Define an extension which can run only on the local machine when connected to remote window.")
512 > },
513 > {
514 > body: ['workspace'],
515 > description: nls.localize('extensionKind.workspace', "Define an extension which can run only on the remote machine when connected remote window.")
516 > },
517 > {
518 > body: ['ui', 'workspace'],
519 > description: nls.localize('extensionKind.ui-workspace', "Define an extension which can run on either side, with a preference towards running on the local machine.")
520 > },
521 > {
522 > body: ['workspace', 'ui'],
523 > description: nls.localize('extensionKind.workspace-ui', "Define an extension which can run on either side, with a preference towards running on the remote machine.")
524 > },
525 > {
526 > body: [],
527 > description: nls.localize('extensionKind.empty', "Define an extension which cannot run in a remote context, neither on the local, nor on the remote machine.")
528 > }
529 > ]
530 > },
531 > capabilities: {
532 > description: nls.localize('vscode.extension.capabilities', "Declare the set of supported capabilities by the extension."),
533 > type: 'object',
534 > properties: {
535 > virtualWorkspaces: {
536 > description: nls.localize('vscode.extension.capabilities.virtualWorkspaces', "Declares whether the extension should be enabled in virtual workspaces. A virtual workspace is a workspace which is not backed by any on-disk resources. When false, this extension will be automatically disabled in virtual workspaces. Default is true."),
537 > type: ['boolean', 'object'],
538 > defaultSnippets: [
539 > { label: 'limited', body: { supported: '${1:limited}', description: '${2}' } },
540 > { label: 'false', body: { supported: false, description: '${2}' } },
541 > ],
542 > default: true.valueOf,
543 > properties: {
544 > supported: {
545 > markdownDescription: nls.localize('vscode.extension.capabilities.virtualWorkspaces.supported', "Declares the level of support for virtual workspaces by the extension."),
546 > type: ['string', 'boolean'],
547 > enum: ['limited', true, false],
548 > enumDescriptions: [
549 > nls.localize('vscode.extension.capabilities.virtualWorkspaces.supported.limited', "The extension will be enabled in virtual workspaces with some functionality disabled."),
550 > nls.localize('vscode.extension.capabilities.virtualWorkspaces.supported.true', "The extension will be enabled in virtual workspaces with all functionality enabled."),
551 > nls.localize('vscode.extension.capabilities.virtualWorkspaces.supported.false', "The extension will not be enabled in virtual workspaces."),
552 > ]
553 > },
554 > description: {
555 > type: 'string',
556 > markdownDescription: nls.localize('vscode.extension.capabilities.virtualWorkspaces.description', "A description of how virtual workspaces affects the extensions behavior and why it is needed. This only applies when `supported` is not `true`."),
557 > }
558 > }
559 > },
560 > untrustedWorkspaces: {
561 > description: nls.localize('vscode.extension.capabilities.untrustedWorkspaces', 'Declares how the extension should be handled in untrusted workspaces.'),
562 > type: 'object',
563 > required: ['supported'],
564 > defaultSnippets: [
565 > { body: { supported: '${1:limited}', description: '${2}' } },
566 > ],
567 > properties: {
568 > supported: {
569 > markdownDescription: nls.localize('vscode.extension.capabilities.untrustedWorkspaces.supported', "Declares the level of support for untrusted workspaces by the extension."),
570 > type: ['string', 'boolean'],
571 > enum: ['limited', true, false],
572 > enumDescriptions: [
573 > nls.localize('vscode.extension.capabilities.untrustedWorkspaces.supported.limited', "The extension will be enabled in untrusted workspaces with some functionality disabled."),
574 > nls.localize('vscode.extension.capabilities.untrustedWorkspaces.supported.true', "The extension will be enabled in untrusted workspaces with all functionality enabled."),
575 > nls.localize('vscode.extension.capabilities.untrustedWorkspaces.supported.false', "The extension will not be enabled in untrusted workspaces."),
576 > ]
577 > },
578 > restrictedConfigurations: {
579 > description: nls.localize('vscode.extension.capabilities.untrustedWorkspaces.restrictedConfigurations', "A list of configuration keys contributed by the extension that should not use workspace values in untrusted workspaces."),
580 > type: 'array',
581 > items: {
582 > type: 'string'
583 > }
584 > },
585 > description: {
586 > type: 'string',
587 > markdownDescription: nls.localize('vscode.extension.capabilities.untrustedWorkspaces.description', "A description of how workspace trust affects the extensions behavior and why it is needed. This only applies when `supported` is not `true`."),
588 > }
589 > }
590 > }
591 > }
592 > },
593 > sponsor: {
594 > description: nls.localize('vscode.extension.contributes.sponsor', "Specify the location from where users can sponsor your extension."),
595 > type: 'object',
596 > defaultSnippets: [
597 > { body: { url: '${1:https:}' } },
598 > ],
599 > properties: {
600 > 'url': {
601 > description: nls.localize('vscode.extension.contributes.sponsor.url', "URL from where users can sponsor your extension. It must be a valid URL with a HTTP or HTTPS protocol. Example value: https://github.com/sponsors/nvaccess"),
602 > type: 'string',
603 > }
604 > }
605 > },
606 > scripts: {
607 > type: 'object',
608 > properties: {
609 > 'vscode:prepublish': {
610 > description: nls.localize('vscode.extension.scripts.prepublish', 'Script executed before the package is published as a VS Code extension.'),
611 > type: 'string'
612 > },
613 > 'vscode:uninstall': {
614 > description: nls.localize('vscode.extension.scripts.uninstall', 'Uninstall hook for VS Code extension. Script that gets executed when the extension is completely uninstalled from VS Code which is when VS Code is restarted (shutdown and start) after the extension is uninstalled. Only Node scripts are supported.'),
615 > type: 'string'
616 > }
617 > }
618 > },
619 > icon: {
620 > type: 'string',
621 > description: nls.localize('vscode.extension.icon', 'The path to a 128x128 pixel icon.')
622 > },
623 > l10n: {
624 > type: 'string',
625 > description: nls.localize({
626 > key: 'vscode.extension.l10n',
627 > comment: [
628 > '{Locked="bundle.l10n._locale_.json"}',
629 > '{Locked="vscode.l10n API"}'
630 > ]
631 > }, 'The relative path to a folder containing localization (bundle.l10n.*.json) files. Must be specified if you are using the vscode.l10n API.')
632 > },
633 > pricing: {
634 > type: 'string',
635 > markdownDescription: nls.localize('vscode.extension.pricing', 'The pricing information for the extension. Can be Free (default) or Trial. For more details visit: https://code.visualstudio.com/api/working-with-extensions/publishing-extension#extension-pricing-label'),
636 > enum: ['Free', 'Trial'],
637 > default: 'Free'
638 > }
639 > }
640 > };
641 >
642 > export type removeArray<T> = T extends Array<infer X> ? X : T;
643 >
644 > export interface IExtensionPointDescriptor<T> {
645 > extensionPoint: string;
646 > deps?: IExtensionPoint<unknown>[];
647 > jsonSchema: IJSONSchema;
648 > defaultExtensionKind?: ExtensionKind[];
649 > canHandleResolver?: boolean;
650 > /**
651 > * A function which runs before the extension point has been validated and which
652 > * should collect automatic activation events from the contribution.
653 > */
654 > activationEventsGenerator?: IActivationEventsGenerator<removeArray<T>>;
655 > }
656 >
657 > export class ExtensionsRegistryImpl {
658 >
659 > private readonly _extensionPoints = new Map<string, ExtensionPoint<any>>();
660 >
661 > public registerExtensionPoint<T>(desc: IExtensionPointDescriptor<T>): IExtensionPoint<T> {
662 > if (this._extensionPoints.has(desc.extensionPoint)) { extensionsRegistry.ts
663 throw new Error('Duplicate extension point: ' + desc.extensionPoint);
664 }
665 > const result = new ExtensionPoint<T>(desc.extensionPoint, desc.defaultExtensionKind, desc.canHandleResolver); extensionsRegistry.ts
666 > this._extensionPoints.set(desc.extensionPoint, result);
667 > if (desc.activationEventsGenerator) {
668 > ImplicitActivationEvents.register(desc.extensionPoint, desc.activationEventsGenerator); extensionsRegistry.ts
669 > }
671 > schema.properties!['contributes'].properties![desc.extensionPoint] = desc.jsonSchema;
672 > schemaRegistry.registerSchema(schemaId, schema);
673 >
674 > return result;
675 > }
677 > public getExtensionPoints(): ExtensionPoint<unknown>[] {
678 return Array.from(this._extensionPoints.values());
679 }
681 >
682 > const PRExtensions = {
683 > ExtensionsRegistry: 'ExtensionsRegistry'
684 > };
685 > Registry.add(PRExtensions.ExtensionsRegistry, new ExtensionsRegistryImpl());
686 > export const ExtensionsRegistry: ExtensionsRegistryImpl = Registry.as(PRExtensions.ExtensionsRegistry);
687 >
688 > schemaRegistry.registerSchema(schemaId, schema);
689 >
690 >
691 > schemaRegistry.registerSchema(productSchemaId, {
692 > properties: {
693 > extensionEnabledApiProposals: {
694 > description: nls.localize('product.extensionEnabledApiProposals', "API proposals that the respective extensions can freely use."),
695 > type: 'object',
696 > properties: {},
697 > additionalProperties: {
698 > anyOf: [{
699 > type: 'array',
700 > uniqueItems: true,
701 > items: {
702 > type: 'string',
703 > enum: Object.keys(allApiProposals),
704 > markdownEnumDescriptions: Object.values(allApiProposals).map(value => value.proposal)
705 > }
706 > }]
707 > }
708 > }
709 > }
710 > });
src/vs/platform/configuration/common/configurationRegistry.ts 638 covered LOC · 98 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); configurationRegistry.ts
396 > return configuration;
397 > }
399 > public registerConfigurations(configurations: IConfigurationNode[], validate: boolean = true): void {
400 > const properties = new Set<string>(); configurationRegistry.ts
401 > this.doRegisterConfigurations(configurations, validate, properties);
402 >
403 > contributionRegistry.registerSchema(resourceLanguageSettingsSchemaId, this.resourceLanguageSettingsSchema);
404 > this._onDidSchemaChange.fire();
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>(); configurationRegistry.ts
419 > this.doDeregisterConfigurations(remove, properties);
420 > this.doRegisterConfigurations(add, false, properties);
421 >
422 > contributionRegistry.registerSchema(resourceLanguageSettingsSchemaId, this.resourceLanguageSettingsSchema);
423 > this._onDidSchemaChange.fire();
424 > this._onDidUpdateConfiguration.fire({ properties });
425 > }
427 > public registerDefaultConfigurations(configurationDefaults: IConfigurationDefaults[]): void {
428 const properties = new Set<string>();
429 this.doRegisterDefaultConfigurations(configurationDefaults, properties);
431 this._onDidUpdateConfiguration.fire({ properties, defaultsOverrides: true });
432 }
434 > private doRegisterDefaultConfigurations(configurationDefaults: IConfigurationDefaults[], bucket: Set<string>) {
435
436 this.registeredConfigurationDefaults.push(...configurationDefaults);
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 = {
549 section: {
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 || {};
569 const source = existingDefaultOverride?.source ?? new Map<string, ConfigurationDefaultSource>();
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) {
676 this.overrideIdentifiers.add(overrideIdentifier);
678 this.updateOverridePropertyPatternKey();
679 }
681 > private doRegisterConfigurations(configurations: IConfigurationNode[], validate: boolean, bucket: Set<string>): void {
683 > configurations.forEach(configuration => {
684 >
685 > this.validateAndRegisterProperties(configuration, validate, configuration.extensionInfo, configuration.restrictedProperties, undefined, bucket);
686 >
687 > this.configurationContributors.push(configuration);
688 > this.registerJSONConfiguration(configuration);
689 > });
690 > }
692 > private doDeregisterConfigurations(configurations: IConfigurationNode[], bucket: Set<string>): void {
694 > const deregisterConfiguration = (configuration: IConfigurationNode) => {
695 if (configuration.properties) {
696 for (const key in configuration.properties) {
715 configuration.allOf?.forEach(node => deregisterConfiguration(node));
716 };
717 > for (const configuration of configurations) { configurationRegistry.ts
718 deregisterConfiguration(configuration);
719 const index = this.configurationContributors.indexOf(configuration);
722 }
723 }
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; configurationRegistry.ts
728 > const properties = configuration.properties;
729 > if (properties) {
730 > for (const key in properties) {
731 > const property: IRegisteredConfigurationPropertySchema = properties[key];
732 > property.section = {
733 > id: configuration.id,
734 > title: configuration.title,
735 > order: configuration.order,
736 > extensionInfo: configuration.extensionInfo
737 > };
738 > if (validate && validateProperty(key, property, extensionInfo?.id)) {
739 delete properties[key];
740 continue;
741 }
743 > property.source = extensionInfo;
744 >
745 > // update default value
746 > property.defaultDefaultValue = properties[key].default;
747 > this.updatePropertyDefaultValue(key, property);
748 >
749 > // update scope
750 > if (OVERRIDE_PROPERTY_REGEX.test(key)) {
751 property.scope = undefined; // No scope for overridable properties `[${identifier}]`
752 > } else { configurationRegistry.ts
753 > property.scope = types.isUndefinedOrNull(property.scope) ? scope : property.scope;
754 > property.restricted = types.isUndefinedOrNull(property.restricted) ? !!restrictedProperties?.includes(key) : property.restricted;
755 > }
756 >
757 > if (property.experiment) {
758 > if (!property.tags?.some(tag => tag.toLowerCase() === 'onexp')) { configurationRegistry.ts
759 > property.tags = property.tags ?? [];
760 > property.tags.push('onExP');
761 > }
762 > } else if (property.tags?.some(tag => tag.toLowerCase() === 'onexp')) { configurationRegistry.ts
763 console.error(`Invalid tag 'onExP' found for property '${key}'. Please use 'experiment' property instead.`);
764 property.experiment = { mode: 'startup' };
765 }
767 > const excluded = properties[key].hasOwnProperty('included') && !properties[key].included;
768 > const policyName = properties[key].policy?.name; configurationRegistry.ts
769 > const policyReferenceName = properties[key].policyReference?.name;
770 >
771 > if (excluded) {
772 this.excludedConfigurationProperties[key] = properties[key];
773 if (policyName) {
780 }
781 delete properties[key];
782 > } else { configurationRegistry.ts
783 > bucket.add(key);
784 > if (policyName) {
785 > this.policyConfigurations.set(policyName, key); configurationRegistry.ts
786 > }
787 > if (policyReferenceName) { configurationRegistry.ts
788 this.addPolicyReferenceConfiguration(policyReferenceName, key);
789 }
790 > this.configurationProperties[key] = properties[key]; configurationRegistry.ts
791 > if (!properties[key].deprecationMessage && properties[key].markdownDeprecationMessage) {
792 // If not set, default deprecationMessage to the markdown source
793 properties[key].deprecationMessage = properties[key].markdownDeprecationMessage;
794 }
797 >
798 > }
799 > }
800 > const subNodes = configuration.allOf;
801 > if (subNodes) {
802 for (const node of subNodes) {
803 this.validateAndRegisterProperties(node, validate, extensionInfo, restrictedProperties, scope, bucket);
804 }
805 }
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; configurationRegistry.ts
824 > }
826 > getPolicyConfigurations(): Map<PolicyName, string> {
827 > return this.policyConfigurations; configurationRegistry.ts
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) => { configurationRegistry.ts
854 > const properties = configuration.properties;
855 > if (properties) {
856 > for (const key in properties) {
857 > this.updateSchema(key, properties[key]); configurationRegistry.ts
858 > }
860 > const subNodes = configuration.allOf;
861 > subNodes?.forEach(register);
862 > };
863 > register(configuration);
864 > }
866 > private updateSchema(key: string, property: IConfigurationPropertySchema): void {
867 > allSettings.properties[key] = property; configurationRegistry.ts
868 > switch (property.scope) {
869 > case ConfigurationScope.APPLICATION:
870 > applicationSettings.properties[key] = property; configurationRegistry.ts
871 > break;
872 > case ConfigurationScope.MACHINE: configurationRegistry.ts
873 > machineSettings.properties[key] = property; configurationRegistry.ts
874 > break;
875 > case ConfigurationScope.APPLICATION_MACHINE: configurationRegistry.ts
876 applicationMachineSettings.properties[key] = property;
877 break;
878 > case ConfigurationScope.MACHINE_OVERRIDABLE: configurationRegistry.ts
879 machineOverridableSettings.properties[key] = property;
880 break;
881 > case ConfigurationScope.WINDOW: configurationRegistry.ts
882 windowSettings.properties[key] = property;
883 break;
884 > case ConfigurationScope.RESOURCE: configurationRegistry.ts
885 resourceSettings.properties[key] = property;
886 break;
887 > case ConfigurationScope.LANGUAGE_OVERRIDABLE: configurationRegistry.ts
888 resourceSettings.properties[key] = property;
889 this.resourceLanguageSettingsSchema.properties![key] = property;
890 break;
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()) {
922 const overrideIdentifierProperty = `[${overrideIdentifier}]`;
937 }
938 }
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
964 defaultValue = configurationdefaultOverride.value;
965 defaultSource = configurationdefaultOverride.source;
966 }
967 > if (types.isUndefined(defaultValue)) { configurationRegistry.ts
968 > defaultValue = property.defaultDefaultValue; configurationRegistry.ts
969 > defaultSource = undefined;
970 > }
971 > if (types.isUndefined(defaultValue)) { configurationRegistry.ts
972 > defaultValue = getDefaultValue(property.type); configurationRegistry.ts
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[] = [];
986 if (OVERRIDE_PROPERTY_REGEX.test(key)) {
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; configurationRegistry.ts
1005 > switch (t) {
1006 > case 'boolean':
1007 return false;
1008 > case 'integer': configurationRegistry.ts
1009 > case 'number':
1010 return 0;
1011 > case 'string': configurationRegistry.ts
1012 > return ''; configurationRegistry.ts
1013 > case 'array': configurationRegistry.ts
1014 > return []; configurationRegistry.ts
1015 > case 'object': configurationRegistry.ts
1016 return {};
1017 > default: configurationRegistry.ts
1018 return null;
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()) { configurationRegistry.ts
1027 return nls.localize('config.property.empty', "Cannot register an empty property");
1028 }
1029 > if (OVERRIDE_PROPERTY_REGEX.test(property)) { configurationRegistry.ts
1030 return nls.localize('config.property.languageDefault', "Cannot register '{0}'. This matches property pattern '\\\\[.*\\\\]$' for describing language specific editor settings. Use 'configurationDefaults' contribution.", property);
1031 }
1032 > if (configurationRegistry.getConfigurationProperties()[property] !== undefined && (!extensionId || !EXTENSION_UNIFICATION_EXTENSION_IDS.has(extensionId.toLowerCase()))) { configurationRegistry.ts
1033 return nls.localize('config.property.duplicate', "Cannot register '{0}'. This property is already registered.", property);
1034 }
1035 > if (schema.policy && schema.policyReference) { configurationRegistry.ts
1036 return nls.localize('config.policy.bothPolicyAndReference', "Cannot register '{0}'. A setting must not declare both 'policy' and 'policyReference'.", property);
1037 }
1038 > if (schema.policy?.name && configurationRegistry.getPolicyConfigurations().get(schema.policy?.name) !== undefined) { configurationRegistry.ts
1039 return nls.localize('config.policy.duplicate', "Cannot register '{0}'. The associated policy {1} is already registered with {2}. To attach another setting to the same policy, use 'policyReference'.", property, schema.policy?.name, configurationRegistry.getPolicyConfigurations().get(schema.policy?.name));
1040 }
1041 > return null; configurationRegistry.ts
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/workbench/contrib/chat/common/tools/languageModelToolsService.ts 603 covered LOC · 35 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- languageModelToolsService.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { Separator } from '../../../../../base/common/actions.js';
7 > import { VSBuffer } from '../../../../../base/common/buffer.js';
8 > import { CancellationToken } from '../../../../../base/common/cancellation.js';
9 > import { Event } from '../../../../../base/common/event.js';
10 > import { IMarkdownString } from '../../../../../base/common/htmlContent.js';
11 > import { Iterable } from '../../../../../base/common/iterator.js';
12 > import { IJSONSchema } from '../../../../../base/common/jsonSchema.js';
13 > import { Disposable, IDisposable, toDisposable } from '../../../../../base/common/lifecycle.js';
14 > import { Schemas } from '../../../../../base/common/network.js';
15 > import { derived, IObservable, IReader, ITransaction, ObservableSet } from '../../../../../base/common/observable.js';
16 > import { ThemeIcon } from '../../../../../base/common/themables.js';
17 > import { URI } from '../../../../../base/common/uri.js';
18 > import { Location } from '../../../../../editor/common/languages.js';
19 > import { localize } from '../../../../../nls.js';
20 > import { ConfirmationOption } from '../../../../../platform/agentHost/common/state/protocol/state.js';
21 > import { ContextKeyExpression, IContextKeyService } from '../../../../../platform/contextkey/common/contextkey.js';
22 > import { ExtensionIdentifier } from '../../../../../platform/extensions/common/extensions.js';
23 > import { ByteSize } from '../../../../../platform/files/common/files.js';
24 > import { createDecorator } from '../../../../../platform/instantiation/common/instantiation.js';
25 > import { IProgress } from '../../../../../platform/progress/common/progress.js';
26 > import { ChatRequestToolReferenceEntry } from '../attachments/chatVariableEntries.js';
27 > import { IVariableReference } from '../chatModes.js';
28 > import { ConfirmedReason, IChatAgentFeedbackReviewConfirmationData, IChatAutomationConfigurationData, IChatAutomationConfiguredData, IChatExtensionsContent, IChatModifiedFilesConfirmationData, IChatSearchToolInvocationData, IChatSessionCreatedData, IChatSimpleToolInvocationData, IChatSubagentToolInvocationData, IChatTodoListContent, IChatToolInputInvocationData, IChatToolInvocation, type IChatTerminalToolInvocationData } from '../chatService/chatService.js';
29 > import { ILanguageModelChatMetadata, LanguageModelPartAudience } from '../languageModels.js';
30 > import { UserSelectedTools } from '../participants/chatAgents.js';
31 > import { PromptElementJSON, stringifyPromptElementJSON } from './promptTsxTypes.js';
32 >
33 > /**
34 > * Selector for matching language models by vendor, family, version, or id.
35 > * Used to filter tools to specific models or model families.
36 > */
37 > export interface ILanguageModelChatSelector {
38 > readonly vendor?: string;
39 > readonly family?: string;
40 > readonly version?: string;
41 > readonly id?: string;
42 > }
43 >
44 > export interface IToolData {
45 > readonly id: string;
46 > readonly source: ToolDataSource;
47 > readonly toolReferenceName?: string;
48 > readonly legacyToolReferenceFullNames?: readonly string[];
49 > readonly icon?: { dark: URI; light?: URI } | ThemeIcon;
50 > readonly when?: ContextKeyExpression;
51 > readonly tags?: readonly string[];
52 > readonly displayName: string;
53 > readonly userDescription?: string;
54 > readonly modelDescription: string;
55 > readonly inputSchema?: IJSONSchema;
56 > readonly canBeReferencedInPrompt?: boolean;
57 > /**
58 > * True if the tool runs in the (possibly remote) workspace, false if it runs
59 > * on the host, undefined if known.
60 > */
61 > readonly runsInWorkspace?: boolean;
62 > readonly alwaysDisplayInputOutput?: boolean;
63 > /** True if this tool might ask for pre-approval */
64 > readonly canRequestPreApproval?: boolean;
65 > /** True if this tool might ask for post-approval */
66 > readonly canRequestPostApproval?: boolean;
67 > /**
68 > * Model selectors that this tool is available for.
69 > * If defined, the tool is only available when the selected model matches one of the selectors.
70 > */
71 > readonly models?: readonly ILanguageModelChatSelector[];
72 > }
73 >
74 > /**
75 > * Check if a tool matches the given model metadata based on the tool's `models` selectors.
76 > * If the tool has no `models` defined, it matches all models.
77 > * If model is undefined, model-specific filtering is skipped (tool is included).
78 > */
79 > export function toolMatchesModel(toolData: IToolData, model: ILanguageModelChatMetadata | undefined): boolean {
80 // If no model selectors are defined, the tool is available for all models
81 if (!toolData.models || toolData.models.length === 0) {
94 );
95 }
97 > export interface IToolProgressStep {
98 > readonly message: string | IMarkdownString | undefined;
99 > /** 0-1 progress of the tool call */
100 > readonly progress?: number;
101 > }
102 >
103 > export type ToolProgress = IProgress<IToolProgressStep>;
104 >
105 > export type ToolDataSource =
106 > | {
107 > type: 'extension';
108 > label: string;
109 > extensionId: ExtensionIdentifier;
110 > }
111 > | {
112 > type: 'mcp';
113 > label: string;
114 > serverLabel: string | undefined;
115 > instructions: string | undefined;
116 > collectionId: string;
117 > definitionId: string;
118 > }
119 > | {
120 > type: 'user';
121 > label: string;
122 > file: URI;
123 > }
124 > | {
125 > type: 'internal';
126 > label: string;
127 > } | {
128 > type: 'external';
129 > label: string;
130 > };
131 >
132 > export namespace ToolDataSource {
133 >
134 > export const Internal: ToolDataSource = { type: 'internal', label: 'Built-In' };
135 >
136 > /** External tools may not be contributed or invoked, but may be invoked externally and described in an IChatToolInvocationSerialized */
137 > export const External: ToolDataSource = { type: 'external', label: 'External' };
138 >
139 > export function toKey(source: ToolDataSource): string {
140 switch (source.type) {
141 case 'extension': return `extension:${source.extensionId.value}`;
146 }
147 }
149 > export function equals(a: ToolDataSource, b: ToolDataSource): boolean {
150 return toKey(a) === toKey(b);
151 }
153 > export function classify(source: ToolDataSource): { readonly ordinal: number; readonly label: string } {
154 if (source.type === 'internal') {
155 return { ordinal: 1, label: localize('builtin', 'Built-In') };
162 }
163 }
165 >
166 > /**
167 > * Pre-tool-use hook result passed from the extension when the hook was executed externally.
168 > */
169 > export interface IExternalPreToolUseHookResult {
170 > permissionDecision?: 'allow' | 'deny' | 'ask';
171 > permissionDecisionReason?: string;
172 > // eslint-disable-next-line @typescript-eslint/no-explicit-any
173 > updatedInput?: Record<string, any>;
174 > }
175 >
176 > export interface IToolInvocation {
177 > callId: string;
178 > toolId: string;
179 > // eslint-disable-next-line @typescript-eslint/no-explicit-any
180 > parameters: Record<string, any>;
181 > tokenBudget?: number;
182 > context: IToolInvocationContext | undefined;
183 > chatRequestId?: string;
184 > chatInteractionId?: string;
185 > /**
186 > * Optional tool call ID from the chat stream, used to correlate with pending streaming tool calls.
187 > */
188 > chatStreamToolCallId?: string;
189 > /**
190 > * Lets us add some nicer UI to toolcalls that came from a sub-agent, but in the long run, this should probably just be rendered in a similar way to thinking text + tool call groups
191 > */
192 > subAgentInvocationId?: string;
193 > toolSpecificData?: IChatTerminalToolInvocationData | IChatToolInputInvocationData | IChatExtensionsContent | IChatTodoListContent | IChatSubagentToolInvocationData | IChatSimpleToolInvocationData | IChatSearchToolInvocationData | IChatModifiedFilesConfirmationData | IChatAgentFeedbackReviewConfirmationData | IChatSessionCreatedData | IChatAutomationConfigurationData | IChatAutomationConfiguredData;
194 > modelId?: string;
195 > userSelectedTools?: UserSelectedTools;
196 > /** The label of the custom button selected by the user during confirmation, if custom buttons were used. */
197 > selectedCustomButton?: string;
198 > /** Pre-tool-use hook result passed from the extension, if the hook was already executed externally. */
199 > preToolUseResult?: IExternalPreToolUseHookResult;
200 > /**
201 > * A confirmation reason resolved out-of-band by the caller (e.g. the agent
202 > * host, which decides auto-approval server-side). When set, the invocation
203 > * is treated as already auto-approved and transitions straight to executing
204 > * without ever entering the `WaitingForConfirmation` state. This avoids a
205 > * transient "needs input" flicker in surfaces (like the sessions list) that
206 > * observe pending confirmations, for tool calls that will be auto-approved
207 > * anyway.
208 > */
209 > preApproved?: ConfirmedReason;
210 > /**
211 > * Optional W3C trace context `traceparent` value identifying the parent distributed
212 > * tracing span for this tool invocation. Forwarded to MCP tool implementations as
213 > * `_meta.traceparent` (MCP SEP-414).
214 > */
215 > traceparent?: string;
216 > /** Optional W3C trace context `tracestate` value paired with {@link traceparent}. */
217 > tracestate?: string;
218 > }
219 >
220 > export interface IToolInvocationContext {
221 > readonly sessionResource: URI;
222 > /**
223 > * The working directory URI associated with this session.
224 > * Only set in the agents window context where each session can
225 > * have its own working directory that differs from the workspace folders.
226 > */
227 > readonly workingDirectory?: URI;
228 > }
229 >
230 > // eslint-disable-next-line @typescript-eslint/no-explicit-any
231 > export function isToolInvocationContext(obj: any): obj is IToolInvocationContext {
232 return obj !== null && typeof obj === 'object' && URI.isUri(obj.sessionResource);
233 }
235 > export interface IToolInvocationPreparationContext {
236 > // eslint-disable-next-line @typescript-eslint/no-explicit-any
237 > parameters: any;
238 > toolCallId: string;
239 > chatRequestId?: string;
240 > chatSessionResource: URI | undefined;
241 > chatInteractionId?: string;
242 > modelId?: string;
243 > /** If set, tells the tool that it should include confirmation messages. */
244 > forceConfirmationReason?: string;
245 > /**
246 > * The working directory URI for the session, if set.
247 > * Used by tools to resolve relative paths and check file access.
248 > */
249 > workingDirectory?: URI;
250 > }
251 >
252 > export type ToolInputOutputBase = {
253 > /** Mimetype of the value, optional */
254 > mimeType?: string;
255 > /** URI of the resource on the MCP server. */
256 > uri?: URI;
257 > /** If true, this part came in as a resource reference rather than direct data. */
258 > asResource?: boolean;
259 > /** Audience of the data part */
260 > audience?: LanguageModelPartAudience[];
261 > };
262 >
263 > export type ToolInputOutputEmbedded = ToolInputOutputBase & {
264 > type: 'embed';
265 > value: string;
266 > /** If true, value is text. If false or not given, value is base64 */
267 > isText?: boolean;
268 > };
269 >
270 > export type ToolInputOutputReference = ToolInputOutputBase & { type: 'ref'; uri: URI };
271 >
272 > export interface IToolResultInputOutputDetails {
273 > readonly input: string;
274 > /** Language identifier for syntax highlighting the input. Defaults to 'json'. */
275 > readonly inputLanguage?: string;
276 > readonly output: (ToolInputOutputEmbedded | ToolInputOutputReference)[];
277 > readonly isError?: boolean;
278 > /** Raw MCP tool result for MCP App UI rendering */
279 > readonly mcpOutput?: unknown;
280 > }
281 >
282 > export interface IToolResultOutputDetails {
283 > readonly output: { type: 'data'; mimeType: string; value: VSBuffer };
284 > }
285 >
286 > // eslint-disable-next-line @typescript-eslint/no-explicit-any
287 > export function isToolResultInputOutputDetails(obj: any): obj is IToolResultInputOutputDetails {
288 return typeof obj === 'object' && typeof obj?.input === 'string' && (typeof obj?.output === 'string' || Array.isArray(obj?.output));
289 }
291 > // eslint-disable-next-line @typescript-eslint/no-explicit-any
292 > export function isToolResultOutputDetails(obj: any): obj is IToolResultOutputDetails {
293 return typeof obj === 'object' && typeof obj?.output === 'object' && typeof obj?.output?.mimeType === 'string' && obj?.output?.type === 'data';
294 }
296 > export interface IToolResult {
297 > content: (IToolResultPromptTsxPart | IToolResultTextPart | IToolResultDataPart)[];
298 > toolSpecificData?: IChatTerminalToolInvocationData | IChatToolInputInvocationData | IChatExtensionsContent | IChatTodoListContent | IChatSubagentToolInvocationData | IChatSimpleToolInvocationData | IChatSearchToolInvocationData | IChatModifiedFilesConfirmationData | IChatAgentFeedbackReviewConfirmationData | IChatSessionCreatedData | IChatAutomationConfiguredData;
299 > toolResultMessage?: string | IMarkdownString;
300 > toolResultDetails?: Array<URI | Location> | IToolResultInputOutputDetails | IToolResultOutputDetails;
301 > toolResultError?: string | boolean;
302 > toolMetadata?: unknown;
303 > /** Whether to ask the user to confirm these tool results. Overrides {@link IToolConfirmationMessages.confirmResults}. */
304 > confirmResults?: boolean;
305 > }
306 >
307 > export function toolContentToA11yString(part: IToolResult['content']) {
308 return part.map(p => {
309 switch (p.kind) {
317 }).join(', ');
318 }
320 > export function toolResultHasBuffers(result: IToolResult): boolean {
321 return result.content.some(part => part.kind === 'data');
322 }
324 > export interface IToolResultPromptTsxPart {
325 > kind: 'promptTsx';
326 > value: unknown;
327 > }
328 >
329 > export function stringifyPromptTsxPart(part: IToolResultPromptTsxPart): string {
330 return stringifyPromptElementJSON(part.value as PromptElementJSON);
331 }
333 > export interface IToolResultTextPart {
334 > kind: 'text';
335 > value: string;
336 > audience?: LanguageModelPartAudience[];
337 > title?: string;
338 > }
339 >
340 > export interface IToolResultDataPart {
341 > kind: 'data';
342 > value: {
343 > mimeType: string;
344 > data: VSBuffer;
345 > };
346 > audience?: LanguageModelPartAudience[];
347 > title?: string;
348 > }
349 >
350 > export type IToolApprovalReason =
351 > | { readonly status: 'loading' }
352 > | {
353 > readonly status: 'complete';
354 > readonly explanation: string | IMarkdownString;
355 > readonly safety: number;
356 > };
357 >
358 > export interface IToolConfirmationMessages {
359 > /** Title for the confirmation. If set, the user will be asked to confirm execution of the tool */
360 > title?: string | IMarkdownString;
361 > /** MUST be set if `title` is also set */
362 > message?: string | IMarkdownString;
363 > disclaimer?: string | IMarkdownString;
364 > /** Model-provided assessment of whether automatic approval is safe. */
365 > approvalReason?: IToolApprovalReason;
366 > /** Whether this confirmation is eligible for automatic approval. */
367 > allowAutoConfirm?: boolean;
368 > terminalCustomActions?: ToolConfirmationAction[];
369 > /** If true, confirmation will be requested after the tool executes and before results are sent to the model */
370 > confirmResults?: boolean;
371 > /** If title is not set (no confirmation needed), this reason will be shown to explain why confirmation was not needed */
372 > confirmationNotNeededReason?: string | IMarkdownString;
373 > /** Custom options to display instead of the default Allow/Skip buttons. */
374 > customOptions?: ConfirmationOption[];
375 > /** When set, shows an additional approval option to approve this particular combination of tool and arguments */
376 > approveCombination?: {
377 > /** Human-readable label for the approval option */
378 > label: string | IMarkdownString;
379 > /** Precomputed SHA-256 key for the combination (set during tool preparation) */
380 > key: string;
381 > /** String representation of the arguments for this combination */
382 > arguments?: string;
383 > };
384 > }
385 >
386 > export interface IToolConfirmationAction {
387 > label: string;
388 > disabled?: boolean;
389 > tooltip?: string;
390 > // eslint-disable-next-line @typescript-eslint/no-explicit-any
391 > data: any;
392 > }
393 >
394 > export type ToolConfirmationAction = IToolConfirmationAction | Separator;
395 >
396 > export enum ToolInvocationPresentation {
397 > Hidden = 'hidden',
398 > HiddenAfterComplete = 'hiddenAfterComplete'
399 > }
400 >
401 > export interface IToolInvocationStreamContext {
402 > toolCallId: string;
403 > rawInput: unknown;
404 > chatRequestId?: string;
405 > chatSessionResource?: URI;
406 > chatInteractionId?: string;
407 > }
408 >
409 > export interface IStreamedToolInvocation {
410 > invocationMessage?: string | IMarkdownString;
411 > }
412 >
413 > export interface IPreparedToolInvocation {
414 > invocationMessage?: string | IMarkdownString;
415 > pastTenseMessage?: string | IMarkdownString;
416 > originMessage?: string | IMarkdownString;
417 > confirmationMessages?: IToolConfirmationMessages;
418 > presentation?: ToolInvocationPresentation;
419 > icon?: ThemeIcon;
420 > toolSpecificData?: IChatTerminalToolInvocationData | IChatToolInputInvocationData | IChatExtensionsContent | IChatTodoListContent | IChatSubagentToolInvocationData | IChatSimpleToolInvocationData | IChatSearchToolInvocationData | IChatModifiedFilesConfirmationData | IChatAgentFeedbackReviewConfirmationData | IChatSessionCreatedData | IChatAutomationConfigurationData | IChatAutomationConfiguredData;
421 > }
422 >
423 > export interface IToolImpl {
424 > invoke(invocation: IToolInvocation, countTokens: CountTokensCallback, progress: ToolProgress, token: CancellationToken): Promise<IToolResult>;
425 > prepareToolInvocation?(context: IToolInvocationPreparationContext, token: CancellationToken): Promise<IPreparedToolInvocation | undefined>;
426 > handleToolStream?(context: IToolInvocationStreamContext, token: CancellationToken): Promise<IStreamedToolInvocation | undefined>;
427 > }
428 >
429 > export interface IToolSet {
430 > readonly id: string;
431 > readonly referenceName: string;
432 > readonly icon: ThemeIcon;
433 > readonly source: ToolDataSource;
434 > readonly description?: string;
435 > /** A longer, human-readable description of what the tool set is for, shown as a subtitle in the Chat Customizations "Tools" section. */
436 > readonly detail?: string;
437 > readonly legacyFullNames?: string[];
438 > /** When true, this tool set is deprecated: it is hidden from the Chat Customizations "Tools" section and these groupings will be removed when the Local harness is dropped. */
439 > readonly deprecated?: boolean;
440 > /** When true, this tool set is hidden from the chat tools picker (e.g. a customizations-only grouping). */
441 > readonly hiddenInToolsPicker?: boolean;
442 >
443 > getTools(r?: IReader): Iterable<IToolData>;
444 > }
445 >
446 >
447 >
448 > /**
449 > * Maps tools and tool sets to their enablement state. Use a class to control creation of the map and ensure
450 > * that it is not mutated after creation.
451 > */
452 > export class ToolAndToolSetEnablementMap implements Iterable<[IToolData | IToolSet, boolean]> {
453 >
454 > static fromEntries(entries: Iterable<[IToolData | IToolSet, boolean]>): ToolAndToolSetEnablementMap {
455 > return new ToolAndToolSetEnablementMap(new Map(entries));
456 > }
457 >
458 > static fromMap(map: Map<IToolData | IToolSet, boolean>): ToolAndToolSetEnablementMap {
459 return new ToolAndToolSetEnablementMap(new Map(map));
460 }
462 > private constructor(private readonly _map: Map<IToolData | IToolSet, boolean>) {
463 }
465 > [Symbol.iterator](): IterableIterator<[IToolData | IToolSet, boolean]> {
466 return this._map[Symbol.iterator]();
467 }
469 > public get(toolOrToolSet: IToolData | IToolSet): boolean | undefined {
470 return this._map.get(toolOrToolSet);
471 }
473 > public has(toolOrToolSet: IToolData | IToolSet): boolean {
474 return this._map.has(toolOrToolSet);
475 }
477 > public get size(): number {
478 return this._map.size;
479 }
481 > public entries(): IterableIterator<[IToolData | IToolSet, boolean]> {
482 return this._map.entries();
483 }
485 >
486 > export function isToolSet(obj: IToolData | IToolSet | undefined): obj is IToolSet {
487 return !!obj && (obj as IToolSet).getTools !== undefined;
488 }
490 > export class ToolSet implements IToolSet {
491 >
492 > protected readonly _tools = new ObservableSet<IToolData>();
493 >
494 > protected readonly _toolSets = new ObservableSet<IToolSet>();
495 >
496 > /**
497 > * A homogenous tool set only contains tools from the same source as the tool set itself
498 > */
499 > readonly isHomogenous: IObservable<boolean>;
500 >
501 > constructor(
502 readonly id: string,
503 readonly referenceName: string,
517 });
518 }
520 > addTool(data: IToolData, tx?: ITransaction): IDisposable {
521 this._tools.add(data, tx);
522 return toDisposable(() => {
524 });
525 }
527 > addToolSet(toolSet: IToolSet, tx?: ITransaction): IDisposable {
528 if (toolSet === this) {
529 return Disposable.None;
534 });
535 }
537 > getTools(r?: IReader): Iterable<IToolData> {
538 return Iterable.concat(
539 Iterable.filter(this._tools.observable.read(r), toolData => this._contextKeyService.contextMatchesRules(toolData.when)),
541 );
542 }
544 >
545 > export class ToolSetForModel {
546 > public get id() {
547 > return this._toolSet.id;
548 > }
549 >
550 > public get referenceName() {
551 return this._toolSet.referenceName;
552 }
554 > public get icon() {
555 return this._toolSet.icon;
556 }
558 > public get source() {
559 return this._toolSet.source;
560 }
562 > public get description() {
563 return this._toolSet.description;
564 }
566 > public get detail() {
567 return this._toolSet.detail;
568 }
570 > public get legacyFullNames() {
571 return this._toolSet.legacyFullNames;
572 }
574 > public get deprecated() {
575 return this._toolSet.deprecated;
576 }
578 > public get hiddenInToolsPicker() {
579 return this._toolSet.hiddenInToolsPicker;
580 }
582 > constructor(
583 private readonly _toolSet: IToolSet,
584 private readonly model: ILanguageModelChatMetadata | undefined,
585 private readonly toolFilter?: (toolData: IToolData) => boolean,
586 ) { }
588 > public getTools(r?: IReader): Iterable<IToolData> {
589 return Iterable.filter(this._toolSet.getTools(r), toolData => toolMatchesModel(toolData, this.model) && (!this.toolFilter || this.toolFilter(toolData)));
590 }
592 >
593 >
594 > export interface IBeginToolCallOptions {
595 > toolCallId: string;
596 > toolId: string;
597 > chatRequestId?: string;
598 > sessionResource?: URI;
599 > subagentInvocationId?: string;
600 > /**
601 > * Create the streaming invocation even when the tool does not
602 > * implement `handleToolStream`. Used by callers that need a
603 > * `ChatToolInvocation` handle to observe state transitions (e.g.
604 > * confirmation) before invoking the tool.
605 > */
606 > force?: boolean;
607 > }
608 >
609 > export interface IToolInvokedEvent {
610 > readonly toolId: string;
611 > readonly sessionResource: URI | undefined;
612 > readonly requestId: string | undefined;
613 > readonly subagentInvocationId: string | undefined;
614 > }
615 >
616 > export const ILanguageModelToolsService = createDecorator<ILanguageModelToolsService>('ILanguageModelToolsService');
617 >
618 > export type CountTokensCallback = (input: string, token: CancellationToken) => Promise<number>;
619 >
620 > export interface ILanguageModelToolsService {
621 > _serviceBrand: undefined;
622 > readonly vscodeToolSet: ToolSet;
623 > readonly executeToolSet: ToolSet;
624 > readonly readToolSet: ToolSet;
625 > readonly agentToolSet: ToolSet;
626 > readonly onDidChangeTools: Event<void>;
627 > readonly onDidPrepareToolCallBecomeUnresponsive: Event<{ readonly sessionResource: URI; readonly toolData: IToolData }>;
628 > readonly onDidInvokeTool: Event<IToolInvokedEvent>;
629 > registerToolData(toolData: IToolData): IDisposable;
630 > registerToolImplementation(id: string, tool: IToolImpl): IDisposable;
631 > registerTool(toolData: IToolData, tool: IToolImpl): IDisposable;
632 >
633 > /**
634 > * Get all tools currently enabled (matching `when` clauses and model).
635 > * @param model The language model metadata to filter tools by. If undefined, model-specific filtering is skipped.
636 > */
637 > getTools(model: ILanguageModelChatMetadata | undefined): Iterable<IToolData>;
638 >
639 > /**
640 > * Creats an observable of enabled tools in the context. Note the observable
641 > * should be created and reused, not created per reader, for example:
642 > *
643 > * ```
644 > * const toolsObs = toolsService.observeTools(model);
645 > * autorun(reader => {
646 > * const tools = toolsObs.read(reader);
647 > * ...
648 > * });
649 > * ```
650 > * @param model The language model metadata to filter tools by. If undefined, model-specific filtering is skipped.
651 > */
652 > observeTools(model: ILanguageModelChatMetadata | undefined): IObservable<readonly IToolData[]>;
653 >
654 > /**
655 > * Get all registered tools regardless of enablement state.
656 > * Use this for configuration UIs, completions, etc. where all tools should be visible.
657 > */
658 > getAllToolsIncludingDisabled(): Iterable<IToolData>;
659 >
660 > /**
661 > * Get a tool by its ID. Does not check when clauses.
662 > */
663 > getTool(id: string): IToolData | undefined;
664 >
665 > /**
666 > * Get a tool by its reference name. Does not check when clauses.
667 > */
668 > getToolByName(name: string): IToolData | undefined;
669 >
670 > /**
671 > * Begin a tool call in the streaming phase.
672 > * Creates a ChatToolInvocation in the Streaming state and appends it to the chat.
673 > * Returns the invocation so it can be looked up later when invokeTool is called.
674 > */
675 > beginToolCall(options: IBeginToolCallOptions): IChatToolInvocation | undefined;
676 >
677 > /**
678 > * Update the streaming state of a pending tool call.
679 > * Calls the tool's handleToolStream method to get a custom invocation message.
680 > */
681 > updateToolStream(toolCallId: string, partialInput: unknown, token: CancellationToken): Promise<void>;
682 >
683 > invokeTool(invocation: IToolInvocation, countTokens: CountTokensCallback, token: CancellationToken): Promise<IToolResult>;
684 > cancelToolCallsForRequest(requestId: string): void;
685 > /** Flush any pending tool updates to the extension hosts. */
686 > flushToolUpdates(): void;
687 >
688 > readonly toolSets: IObservable<Iterable<IToolSet>>;
689 > getToolSetsForModel(model: ILanguageModelChatMetadata | undefined, reader?: IReader): Iterable<IToolSet>;
690 > getToolSet(id: string): IToolSet | undefined;
691 > getToolSetByName(name: string): IToolSet | undefined;
692 > createToolSet(source: ToolDataSource, id: string, referenceName: string, options?: { icon?: ThemeIcon; description?: string; detail?: string; legacyFullNames?: string[]; deprecated?: boolean; hiddenInToolsPicker?: boolean }): ToolSet & IDisposable;
693 >
694 > // tool names in prompt and agent files ('full reference names')
695 > getFullReferenceNames(): Iterable<string>;
696 > getFullReferenceName(tool: IToolData | IToolSet, toolSet?: IToolSet): string;
697 > getFullReferenceNameMap(): Map<IToolData | IToolSet, string>;
698 > getToolByFullReferenceName(fullReferenceName: string): IToolData | IToolSet | undefined;
699 > getDeprecatedFullReferenceNames(): Map<string, Set<string>>;
700 >
701 > /**
702 > * Gets the enablement maps based on the given set of references.
703 > * @param fullReferenceNames The full reference names of the tools and tool sets to enable.
704 > * @param model Optional language model metadata to filter tools by.
705 > * If undefined is passed, all tools will be returned, even if normally disabled.
706 > */
707 > toToolAndToolSetEnablementMap(fullReferenceNames: readonly string[], model: ILanguageModelChatMetadata | undefined): ToolAndToolSetEnablementMap;
708 >
709 > toFullReferenceNames(map: ToolAndToolSetEnablementMap): string[];
710 > toToolReferences(variableReferences: readonly IVariableReference[]): ChatRequestToolReferenceEntry[];
711 > }
712 >
713 >
714 > export function createToolInputUri(toolCallId: string): URI {
715 return URI.from({ scheme: Schemas.inMemory, path: `/lm/tool/${toolCallId}/tool_input.json` });
716 }
718 > export function createToolSchemaUri(toolOrId: IToolData | string): URI {
719 if (typeof toolOrId !== 'string') {
720 toolOrId = toolOrId.id;
722 return URI.from({ scheme: Schemas.vscode, authority: 'schemas', path: `/lm/tool/${toolOrId}` });
723 }
725 > export namespace SpecedToolAliases {
726 > export const execute = 'execute';
727 > export const edit = 'edit';
728 > export const search = 'search';
729 > export const agent = 'agent';
730 > export const read = 'read';
731 > export const web = 'web';
732 > export const todo = 'todo';
733 > }
734 >
735 > export namespace VSCodeToolReference {
736 > export const runSubagent = 'runSubagent';
737 > export const vscode = 'vscode';
738 >
739 > }
src/vs/workbench/services/textfile/common/textfiles.ts 575 covered LOC · 5 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- textfiles.ts
2 > * Copyright (c) Microsoft 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 { Event } from '../../../../base/common/event.js';
8 > import { IDisposable } from '../../../../base/common/lifecycle.js';
9 > import { ISaveOptions, IRevertOptions, SaveReason } from '../../../common/editor.js';
10 > import { ReadableStream } from '../../../../base/common/stream.js';
11 > import { IBaseFileStatWithMetadata, IFileStatWithMetadata, IWriteFileOptions, FileOperationError, FileOperationResult, IReadFileStreamOptions, IFileReadLimits } from '../../../../platform/files/common/files.js';
12 > import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
13 > import { ITextEditorModel } from '../../../../editor/common/services/resolverService.js';
14 > import { ITextBufferFactory, ITextModel, ITextSnapshot } from '../../../../editor/common/model.js';
15 > import { VSBuffer, VSBufferReadable, VSBufferReadableStream } from '../../../../base/common/buffer.js';
16 > import { areFunctions, isUndefinedOrNull } from '../../../../base/common/types.js';
17 > import { IWorkingCopy, IWorkingCopySaveEvent } from '../../workingCopy/common/workingCopy.js';
18 > import { IUntitledTextEditorModelManager } from '../../untitled/common/untitledTextEditorService.js';
19 > import { CancellationToken } from '../../../../base/common/cancellation.js';
20 > import { IProgress, IProgressStep } from '../../../../platform/progress/common/progress.js';
21 > import { IFileOperationUndoRedoInfo } from '../../workingCopy/common/workingCopyFileService.js';
22 >
23 > export const ITextFileService = createDecorator<ITextFileService>('textFileService');
24 >
25 > export interface ITextFileService extends IDisposable {
26 >
27 > readonly _serviceBrand: undefined;
28 >
29 > /**
30 > * Access to the manager of text file editor models providing further
31 > * methods to work with them.
32 > */
33 > readonly files: ITextFileEditorModelManager;
34 >
35 > /**
36 > * Access to the manager of untitled text editor models providing further
37 > * methods to work with them.
38 > */
39 > readonly untitled: IUntitledTextEditorModelManager;
40 >
41 > /**
42 > * Helper to determine encoding for resources.
43 > */
44 > readonly encoding: IResourceEncodings;
45 >
46 > /**
47 > * A resource is dirty if it has unsaved changes or is an untitled file not yet saved.
48 > *
49 > * @param resource the resource to check for being dirty
50 > */
51 > isDirty(resource: URI): boolean;
52 >
53 > /**
54 > * Saves the resource.
55 > *
56 > * @param resource the resource to save
57 > * @param options optional save options
58 > * @return Path of the saved resource or undefined if canceled.
59 > */
60 > save(resource: URI, options?: ITextFileSaveOptions): Promise<URI | undefined>;
61 >
62 > /**
63 > * Saves the provided resource asking the user for a file name or using the provided one.
64 > *
65 > * @param resource the resource to save as.
66 > * @param targetResource the optional target to save to.
67 > * @param options optional save options
68 > * @return Path of the saved resource or undefined if canceled.
69 > */
70 > saveAs(resource: URI, targetResource?: URI, options?: ITextFileSaveAsOptions): Promise<URI | undefined>;
71 >
72 > /**
73 > * Reverts the provided resource.
74 > *
75 > * @param resource the resource of the file to revert.
76 > * @param force to force revert even when the file is not dirty
77 > */
78 > revert(resource: URI, options?: IRevertOptions): Promise<void>;
79 >
80 > /**
81 > * Read the contents of a file identified by the resource.
82 > */
83 > read(resource: URI, options?: IReadTextFileOptions): Promise<ITextFileContent>;
84 >
85 > /**
86 > * Read the contents of a file identified by the resource as stream.
87 > */
88 > readStream(resource: URI, options?: IReadTextFileOptions): Promise<ITextFileStreamContent>;
89 >
90 > /**
91 > * Update a file with given contents.
92 > */
93 > write(resource: URI, value: string | ITextSnapshot, options?: IWriteTextFileOptions): Promise<IFileStatWithMetadata>;
94 >
95 > /**
96 > * Create files. If the file exists it will be overwritten with the contents if
97 > * the options enable to overwrite.
98 > */
99 > create(operations: { resource: URI; value?: string | ITextSnapshot; options?: { overwrite?: boolean } }[], undoInfo?: IFileOperationUndoRedoInfo): Promise<readonly IFileStatWithMetadata[]>;
100 >
101 > /**
102 > * Returns the readable that uses the appropriate encoding. This method should
103 > * be used whenever a `string` or `ITextSnapshot` is being persisted to the
104 > * file system.
105 > */
106 > getEncodedReadable(resource: URI | undefined, value: ITextSnapshot, options?: IWriteTextFileOptions): Promise<VSBufferReadable>;
107 > getEncodedReadable(resource: URI | undefined, value: string, options?: IWriteTextFileOptions): Promise<VSBuffer | VSBufferReadable>;
108 > getEncodedReadable(resource: URI | undefined, value?: ITextSnapshot, options?: IWriteTextFileOptions): Promise<VSBufferReadable | undefined>;
109 > getEncodedReadable(resource: URI | undefined, value?: string, options?: IWriteTextFileOptions): Promise<VSBuffer | VSBufferReadable | undefined>;
110 > getEncodedReadable(resource: URI | undefined, value?: string | ITextSnapshot, options?: IWriteTextFileOptions): Promise<VSBuffer | VSBufferReadable | undefined>;
111 >
112 > /**
113 > * Returns a stream of strings that uses the appropriate encoding. This method should
114 > * be used whenever a `VSBufferReadableStream` is being loaded from the file system.
115 > *
116 > * Will throw an error if `acceptTextOnly: true` for resources that seem to be binary.
117 > */
118 > getDecodedStream(resource: URI | undefined, value: VSBufferReadableStream, options?: IReadTextFileEncodingOptions): Promise<ReadableStream<string>>;
119 >
120 > /**
121 > * Get the encoding for the provided `resource`. Will try to determine the encoding
122 > * from any existing model for that `resource` and fallback to the configured defaults.
123 > */
124 > getEncoding(resource: URI): string;
125 >
126 > /**
127 > * Get the properties for decoding the provided `resource` based on configuration.
128 > */
129 > resolveDecoding(resource: URI | undefined, options?: IReadTextFileEncodingOptions): Promise<{ preferredEncoding: string; guessEncoding: boolean; candidateGuessEncodings: string[] }>;
130 >
131 > /**
132 > * Get the properties for encoding the provided `resource` based on configuration.
133 > */
134 > resolveEncoding(resource: URI | undefined, options?: IWriteTextFileOptions): Promise<{ encoding: string; addBOM: boolean }>;
135 >
136 > /**
137 > * Given a detected encoding, validate it against the configured encoding options.
138 > */
139 > validateDetectedEncoding(resource: URI | undefined, detectedEncoding: string, options?: IReadTextFileEncodingOptions): Promise<string>;
140 > }
141 >
142 > export interface IReadTextFileEncodingOptions {
143 >
144 > /**
145 > * The optional encoding parameter allows to specify the desired encoding when resolving
146 > * the contents of the file.
147 > */
148 > readonly encoding?: string;
149 >
150 > /**
151 > * The optional guessEncoding parameter allows to guess encoding from content of the file.
152 > */
153 > readonly autoGuessEncoding?: boolean;
154 >
155 > /**
156 > * The optional candidateGuessEncodings parameter limits the allowed encodings to guess from.
157 > */
158 > readonly candidateGuessEncodings?: string[];
159 >
160 > /**
161 > * The optional acceptTextOnly parameter allows to fail this request early if the file
162 > * contents are not textual.
163 > */
164 > readonly acceptTextOnly?: boolean;
165 > }
166 >
167 > export interface IReadTextFileOptions extends IReadTextFileEncodingOptions, IReadFileStreamOptions { }
168 >
169 > export interface IWriteTextFileOptions extends IWriteFileOptions {
170 >
171 > /**
172 > * The encoding to use when updating a file.
173 > */
174 > readonly encoding?: string;
175 >
176 > /**
177 > * Whether to write to the file as elevated (admin) user. When setting this option a prompt will
178 > * ask the user to authenticate as super user.
179 > */
180 > readonly writeElevated?: boolean;
181 > }
182 >
183 > export const enum TextFileOperationResult {
184 > FILE_IS_BINARY
185 > }
186 >
187 > export class TextFileOperationError extends FileOperationError {
188 >
189 > static isTextFileOperationError(obj: unknown): obj is TextFileOperationError {
190 > return obj instanceof Error && !isUndefinedOrNull((obj as TextFileOperationError).textFileOperationResult);
191 > }
192 >
193 > override readonly options?: IReadTextFileOptions & IWriteTextFileOptions;
194 >
195 > constructor(
196 message: string,
197 public textFileOperationResult: TextFileOperationResult,
202 this.options = options;
203 }
204 > } textfiles.ts
205 >
206 > export interface IResourceEncodings {
207 > getPreferredReadEncoding(resource: URI): Promise<IResourceEncoding>;
208 > getPreferredWriteEncoding(resource: URI, preferredEncoding?: string): Promise<IResourceEncoding>;
209 > }
210 >
211 > export interface IResourceEncoding {
212 > readonly encoding: string;
213 > readonly hasBOM: boolean;
214 > }
215 >
216 > /**
217 > * The save error handler can be installed on the text file editor model to install code that executes when save errors occur.
218 > */
219 > export interface ISaveErrorHandler {
220 >
221 > /**
222 > * Called whenever a save fails.
223 > */
224 > onSaveError(error: Error, model: ITextFileEditorModel, options: ITextFileSaveAsOptions): void;
225 > }
226 >
227 > /**
228 > * States the text file editor model can be in.
229 > */
230 > export const enum TextFileEditorModelState {
231 >
232 > /**
233 > * A model is saved.
234 > */
235 > SAVED,
236 >
237 > /**
238 > * A model is dirty.
239 > */
240 > DIRTY,
241 >
242 > /**
243 > * A model is currently being saved but this operation has not completed yet.
244 > */
245 > PENDING_SAVE,
246 >
247 > /**
248 > * A model is in conflict mode when changes cannot be saved because the
249 > * underlying file has changed. Models in conflict mode are always dirty.
250 > */
251 > CONFLICT,
252 >
253 > /**
254 > * A model is in orphan state when the underlying file has been deleted.
255 > */
256 > ORPHAN,
257 >
258 > /**
259 > * Any error that happens during a save that is not causing the CONFLICT state.
260 > * Models in error mode are always dirty.
261 > */
262 > ERROR
263 > }
264 >
265 > export const enum TextFileResolveReason {
266 > EDITOR = 1,
267 > REFERENCE = 2,
268 > OTHER = 3
269 > }
270 >
271 > interface IBaseTextFileContent extends IBaseFileStatWithMetadata {
272 >
273 > /**
274 > * The encoding of the content if known.
275 > */
276 > readonly encoding: string;
277 > }
278 >
279 > export interface ITextFileContent extends IBaseTextFileContent {
280 >
281 > /**
282 > * The content of a text file.
283 > */
284 > readonly value: string;
285 > }
286 >
287 > export interface ITextFileStreamContent extends IBaseTextFileContent {
288 >
289 > /**
290 > * The line grouped content of a text file.
291 > */
292 > readonly value: ITextBufferFactory;
293 > }
294 >
295 > export interface ITextFileEditorModelResolveOrCreateOptions extends ITextFileResolveOptions {
296 >
297 > /**
298 > * The language id to use for the model text content.
299 > */
300 > readonly languageId?: string;
301 >
302 > /**
303 > * The encoding to use when resolving the model text content.
304 > */
305 > readonly encoding?: string;
306 >
307 > /**
308 > * If the model was already resolved before, allows to trigger
309 > * a reload of it to fetch the latest contents.
310 > */
311 > readonly reload?: {
312 >
313 > /**
314 > * Controls whether the reload happens in the background
315 > * or whether `resolve` will await the reload to happen.
316 > */
317 > readonly async: boolean;
318 > };
319 > }
320 >
321 > export interface ITextFileSaveEvent extends ITextFileEditorModelSaveEvent {
322 >
323 > /**
324 > * The model that was saved.
325 > */
326 > readonly model: ITextFileEditorModel;
327 > }
328 >
329 > export interface ITextFileResolveEvent {
330 >
331 > /**
332 > * The model that was resolved.
333 > */
334 > readonly model: ITextFileEditorModel;
335 >
336 > /**
337 > * The reason why the model was resolved.
338 > */
339 > readonly reason: TextFileResolveReason;
340 > }
341 >
342 > export interface ITextFileSaveParticipantContext {
343 >
344 > /**
345 > * The reason why the save was triggered.
346 > */
347 > readonly reason: SaveReason;
348 >
349 > /**
350 > * Only applies to when a text file was saved as, for
351 > * example when starting with untitled and saving. This
352 > * provides access to the initial resource the text
353 > * file had before.
354 > */
355 > readonly savedFrom?: URI;
356 > }
357 >
358 > export interface ITextFileSaveParticipant {
359 >
360 > /**
361 > * The ordinal number which determines the order of participation.
362 > * Lower values mean to participant sooner
363 > */
364 > readonly ordinal?: number;
365 >
366 > /**
367 > * Participate in a save of a model. Allows to change the model
368 > * before it is being saved to disk.
369 > */
370 > participate(
371 > model: ITextFileEditorModel,
372 > context: ITextFileSaveParticipantContext,
373 > progress: IProgress<IProgressStep>,
374 > token: CancellationToken
375 > ): Promise<void>;
376 > }
377 >
378 > export interface ITextFileEditorModelManager {
379 >
380 > readonly onDidCreate: Event<ITextFileEditorModel>;
381 > readonly onDidResolve: Event<ITextFileResolveEvent>;
382 > readonly onDidChangeDirty: Event<ITextFileEditorModel>;
383 > readonly onDidChangeReadonly: Event<ITextFileEditorModel>;
384 > readonly onDidRemove: Event<URI>;
385 > readonly onDidChangeOrphaned: Event<ITextFileEditorModel>;
386 > readonly onDidChangeEncoding: Event<ITextFileEditorModel>;
387 > readonly onDidSaveError: Event<ITextFileEditorModel>;
388 > readonly onDidSave: Event<ITextFileSaveEvent>;
389 > readonly onDidRevert: Event<ITextFileEditorModel>;
390 >
391 > /**
392 > * Access to all text file editor models in memory.
393 > */
394 > readonly models: ITextFileEditorModel[];
395 >
396 > /**
397 > * Allows to configure the error handler that is called on save errors.
398 > */
399 > saveErrorHandler: ISaveErrorHandler;
400 >
401 > /**
402 > * Returns the text file editor model for the provided resource
403 > * or undefined if none.
404 > */
405 > get(resource: URI): ITextFileEditorModel | undefined;
406 >
407 > /**
408 > * Allows to resolve a text file model from disk.
409 > */
410 > resolve(resource: URI, options?: ITextFileEditorModelResolveOrCreateOptions): Promise<ITextFileEditorModel>;
411 >
412 > /**
413 > * Adds a participant for saving text file models.
414 > */
415 > addSaveParticipant(participant: ITextFileSaveParticipant): IDisposable;
416 >
417 > /**
418 > * Runs the registered save participants on the provided model.
419 > */
420 > runSaveParticipants(model: ITextFileEditorModel, context: ITextFileSaveParticipantContext, progress: IProgress<IProgressStep>, token: CancellationToken): Promise<void>;
421 >
422 > /**
423 > * Waits for the model to be ready to be disposed. There may be conditions
424 > * under which the model cannot be disposed, e.g. when it is dirty. Once the
425 > * promise is settled, it is safe to dispose the model.
426 > */
427 > canDispose(model: ITextFileEditorModel): true | Promise<true>;
428 > }
429 >
430 > export interface ITextFileSaveOptions extends ISaveOptions {
431 >
432 > /**
433 > * Save the file with an attempt to unlock it.
434 > */
435 > readonly writeUnlock?: boolean;
436 >
437 > /**
438 > * Save the file with elevated privileges.
439 > *
440 > * Note: This may not be supported in all environments.
441 > */
442 > readonly writeElevated?: boolean;
443 >
444 > /**
445 > * Allows to write to a file even if it has been modified on disk.
446 > */
447 > readonly ignoreModifiedSince?: boolean;
448 >
449 > /**
450 > * If set, will bubble up the error to the caller instead of handling it.
451 > */
452 > readonly ignoreErrorHandler?: boolean;
453 > }
454 >
455 > export interface ITextFileSaveAsOptions extends ITextFileSaveOptions {
456 >
457 > /**
458 > * Optional URI of the resource the text file is saved from if known.
459 > */
460 > readonly from?: URI;
461 >
462 > /**
463 > * Optional URI to use as suggested file path to save as.
464 > */
465 > readonly suggestedTarget?: URI;
466 > }
467 >
468 > export interface ITextFileResolveOptions {
469 >
470 > /**
471 > * The contents to use for the model if known. If not
472 > * provided, the contents will be retrieved from the
473 > * underlying resource or backup if present.
474 > */
475 > readonly contents?: ITextBufferFactory;
476 >
477 > /**
478 > * Go to file bypassing any cache of the model if any.
479 > */
480 > readonly forceReadFromFile?: boolean;
481 >
482 > /**
483 > * Allow to resolve a model even if we think it is a binary file.
484 > */
485 > readonly allowBinary?: boolean;
486 >
487 > /**
488 > * Context why the model is being resolved.
489 > */
490 > readonly reason?: TextFileResolveReason;
491 >
492 > /**
493 > * If provided, the size of the file will be checked against the limits
494 > * and an error will be thrown if any limit is exceeded.
495 > */
496 > readonly limits?: IFileReadLimits;
497 > }
498 >
499 > export const enum EncodingMode {
500 >
501 > /**
502 > * Instructs the encoding support to encode the object with the provided encoding
503 > */
504 > Encode,
505 >
506 > /**
507 > * Instructs the encoding support to decode the object with the provided encoding
508 > */
509 > Decode
510 > }
511 >
512 > export interface IEncodingSupport {
513 >
514 > /**
515 > * Gets the encoding of the object if known.
516 > */
517 > getEncoding(): string | undefined;
518 >
519 > /**
520 > * Sets the encoding for the object for saving.
521 > */
522 > setEncoding(encoding: string, mode: EncodingMode): Promise<void>;
523 > }
524 >
525 > export interface ILanguageSupport {
526 >
527 > /**
528 > * Sets the language id of the object.
529 > */
530 > setLanguageId(languageId: string, source?: string): void;
531 > }
532 >
533 > export interface ITextFileEditorModelSaveEvent extends IWorkingCopySaveEvent {
534 >
535 > /**
536 > * The resolved stat from the save operation.
537 > */
538 > readonly stat: IFileStatWithMetadata;
539 > }
540 >
541 > export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport, ILanguageSupport, IWorkingCopy {
542 >
543 > readonly onDidSave: Event<ITextFileEditorModelSaveEvent>;
544 > readonly onDidSaveError: Event<void>;
545 > readonly onDidChangeOrphaned: Event<void>;
546 > readonly onDidChangeReadonly: Event<void>;
547 > readonly onDidChangeEncoding: Event<void>;
548 >
549 > hasState(state: TextFileEditorModelState): boolean;
550 > joinState(state: TextFileEditorModelState.PENDING_SAVE): Promise<void>;
551 >
552 > updatePreferredEncoding(encoding: string | undefined): void;
553 >
554 > save(options?: ITextFileSaveAsOptions): Promise<boolean>;
555 > revert(options?: IRevertOptions): Promise<void>;
556 >
557 > resolve(options?: ITextFileResolveOptions): Promise<void>;
558 >
559 > isDirty(): this is IResolvedTextFileEditorModel;
560 >
561 > getLanguageId(): string | undefined;
562 >
563 > isResolved(): this is IResolvedTextFileEditorModel;
564 > }
565 >
566 > export function isTextFileEditorModel(model: ITextEditorModel): model is ITextFileEditorModel {
567 const candidate = model as ITextFileEditorModel;
568
569 return areFunctions(candidate.setEncoding, candidate.getEncoding, candidate.save, candidate.revert, candidate.isDirty, candidate.getLanguageId);
570 }
571 > textfiles.ts
572 > export interface IResolvedTextFileEditorModel extends ITextFileEditorModel {
573 >
574 > readonly textEditorModel: ITextModel;
575 >
576 > createSnapshot(): ITextSnapshot;
577 > }
578 >
579 > export function snapshotToString(snapshot: ITextSnapshot): string {
580 const chunks: string[] = [];
581
587 return chunks.join('');
588 }
589 > textfiles.ts
590 > export function stringToSnapshot(value: string): ITextSnapshot {
591 let done = false;
592
603 };
604 }
605 > textfiles.ts
606 > export function toBufferOrReadable(value: string): VSBuffer;
607 > export function toBufferOrReadable(value: ITextSnapshot): VSBufferReadable;
608 > export function toBufferOrReadable(value: string | ITextSnapshot): VSBuffer | VSBufferReadable;
609 > export function toBufferOrReadable(value: string | ITextSnapshot | undefined): VSBuffer | VSBufferReadable | undefined;
610 > export function toBufferOrReadable(value: string | ITextSnapshot | undefined): VSBuffer | VSBufferReadable | undefined {
611 if (typeof value === 'undefined') {
612 return undefined;
src/vs/workbench/services/search/common/searchExtTypes.ts 560 covered LOC · 4 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- searchExtTypes.ts
2 > * Copyright (c) Microsoft 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 { URI } from '../../../../base/common/uri.js';
8 > import { IProgress } from '../../../../platform/progress/common/progress.js';
9 >
10 > export class Position {
11 > constructor(readonly line: number, readonly character: number) { }
12 >
13 > isBefore(other: Position): boolean { return false; }
14 > isBeforeOrEqual(other: Position): boolean { return false; }
15 > isAfter(other: Position): boolean { return false; }
16 > isAfterOrEqual(other: Position): boolean { return false; }
17 > isEqual(other: Position): boolean { return false; }
18 > compareTo(other: Position): number { return 0; }
19 > translate(lineDelta?: number, characterDelta?: number): Position;
20 > translate(change: { lineDelta?: number; characterDelta?: number }): Position;
21 > translate(_?: any, _2?: any): Position { return new Position(0, 0); }
22 > with(line?: number, character?: number): Position;
23 > with(change: { line?: number; character?: number }): Position;
24 > with(_: any): Position { return new Position(0, 0); }
25 > }
26 >
27 > export class Range {
28 > readonly start: Position;
29 > readonly end: Position;
30 >
31 > constructor(startLine: number, startCol: number, endLine: number, endCol: number) {
32 this.start = new Position(startLine, startCol);
33 this.end = new Position(endLine, endCol);
34 }
36 > isEmpty = false;
37 > isSingleLine = false;
38 > contains(positionOrRange: Position | Range): boolean { return false; }
39 > isEqual(other: Range): boolean { return false; }
40 > intersection(range: Range): Range | undefined { return undefined; }
41 > union(other: Range): Range { return new Range(0, 0, 0, 0); }
42 >
43 > with(start?: Position, end?: Position): Range;
44 > with(change: { start?: Position; end?: Position }): Range;
45 > with(_: any): Range { return new Range(0, 0, 0, 0); }
46 > }
47 >
48 > export type ProviderResult<T> = T | undefined | null | Thenable<T | undefined | null>;
49 >
50 > /**
51 > * A relative pattern is a helper to construct glob patterns that are matched
52 > * relatively to a base path. The base path can either be an absolute file path
53 > * or a [workspace folder](#WorkspaceFolder).
54 > */
55 > export interface RelativePattern {
56 >
57 > /**
58 > * A base file path to which this pattern will be matched against relatively. The
59 > * file path must be absolute, should not have any trailing path separators and
60 > * not include any relative segments (`.` or `..`).
61 > */
62 > baseUri: URI;
63 >
64 > /**
65 > * A file glob pattern like `*.{ts,js}` that will be matched on file paths
66 > * relative to the base path.
67 > *
68 > * Example: Given a base of `/home/work/folder` and a file path of `/home/work/folder/index.js`,
69 > * the file glob pattern will match on `index.js`.
70 > */
71 > pattern: string;
72 > }
73 >
74 > /**
75 > * A file glob pattern to match file paths against. This can either be a glob pattern string
76 > * (like `** /*.{ts,js}` without space before / or `*.{ts,js}`) or a [relative pattern](#RelativePattern).
77 > *
78 > * Glob patterns can have the following syntax:
79 > * * `*` to match zero or more characters in a path segment
80 > * * `?` to match on one character in a path segment
81 > * * `**` to match any number of path segments, including none
82 > * * `{}` to group conditions (e.g. `** /*.{ts,js}` without space before / matches all TypeScript and JavaScript files)
83 > * * `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …)
84 > * * `[!...]` 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`)
85 > *
86 > * Note: a backslash (`\`) is not valid within a glob pattern. If you have an existing file
87 > * path to match against, consider to use the [relative pattern](#RelativePattern) support
88 > * that takes care of converting any backslash into slash. Otherwise, make sure to convert
89 > * any backslash to slash when creating the glob pattern.
90 > */
91 > export type GlobPattern = string | RelativePattern;
92 >
93 > /**
94 > * The parameters of a query for text search.
95 > */
96 > export interface TextSearchQuery2 {
97 > /**
98 > * The text pattern to search for.
99 > */
100 > pattern: string;
101 >
102 > /**
103 > * Whether or not `pattern` should match multiple lines of text.
104 > */
105 > isMultiline?: boolean;
106 >
107 > /**
108 > * Whether or not `pattern` should be interpreted as a regular expression.
109 > */
110 > isRegExp?: boolean;
111 >
112 > /**
113 > * Whether or not the search should be case-sensitive.
114 > */
115 > isCaseSensitive?: boolean;
116 >
117 > /**
118 > * Whether or not to search for whole word matches only.
119 > */
120 > isWordMatch?: boolean;
121 > }
122 >
123 >
124 > export interface TextSearchProviderFolderOptions {
125 > /**
126 > * The root folder to search within.
127 > */
128 > folder: URI;
129 >
130 > /**
131 > * Files that match an `includes` glob pattern should be included in the search.
132 > */
133 > includes: string[];
134 >
135 > /**
136 > * Files that match an `excludes` glob pattern should be excluded from the search.
137 > */
138 > excludes: GlobPattern[];
139 >
140 > /**
141 > * Whether to ignore case for glob patterns.
142 > */
143 > ignoreGlobCase?: boolean;
144 >
145 > /**
146 > * Whether symlinks should be followed while searching.
147 > * For more info, see the setting description for `search.followSymlinks`.
148 > */
149 > followSymlinks: boolean;
150 >
151 > /**
152 > * Which file locations we should look for ignore (.gitignore or .ignore) files to respect.
153 > */
154 > useIgnoreFiles: {
155 > /**
156 > * Use ignore files at the current workspace root.
157 > */
158 > local: boolean;
159 > /**
160 > * Use ignore files at the parent directory. If set, `local` in {@link TextSearchProviderFolderOptions.useIgnoreFiles} should also be `true`.
161 > */
162 > parent: boolean;
163 > /**
164 > * Use global ignore files. If set, `local` in {@link TextSearchProviderFolderOptions.useIgnoreFiles} should also be `true`.
165 > */
166 > global: boolean;
167 > };
168 >
169 > /**
170 > * Interpret files using this encoding.
171 > * See the vscode setting `"files.encoding"`
172 > */
173 > encoding: string;
174 > }
175 >
176 > /**
177 > * Options that apply to text search.
178 > */
179 > export interface TextSearchProviderOptions {
180 >
181 > folderOptions: TextSearchProviderFolderOptions[];
182 >
183 > /**
184 > * The maximum number of results to be returned.
185 > */
186 > maxResults: number;
187 >
188 > /**
189 > * Options to specify the size of the result text preview.
190 > */
191 > previewOptions: {
192 > /**
193 > * The maximum number of lines in the preview.
194 > * Only search providers that support multiline search will ever return more than one line in the match.
195 > * Defaults to 100.
196 > */
197 > matchLines: number;
198 >
199 > /**
200 > * The maximum number of characters included per line.
201 > * Defaults to 10000.
202 > */
203 > charsPerLine: number;
204 > };
205 >
206 > /**
207 > * Exclude files larger than `maxFileSize` in bytes.
208 > */
209 > maxFileSize: number | undefined;
210 >
211 >
212 > /**
213 > * Number of lines of context to include before and after each match.
214 > */
215 > surroundingContext: number;
216 > }
217 >
218 >
219 > /**
220 > * Information collected when text search is complete.
221 > */
222 > export interface TextSearchComplete2 {
223 > /**
224 > * Whether the search hit the limit on the maximum number of search results.
225 > * `maxResults` on [`TextSearchOptions`](#TextSearchOptions) specifies the max number of results.
226 > * - If exactly that number of matches exist, this should be false.
227 > * - If `maxResults` matches are returned and more exist, this should be true.
228 > * - If search hits an internal limit which is less than `maxResults`, this should be true.
229 > */
230 > limitHit?: boolean;
231 > }
232 >
233 > export interface FileSearchProviderFolderOptions {
234 > /**
235 > * The root folder to search within.
236 > */
237 > folder: URI;
238 >
239 > /**
240 > * Files that match an `includes` glob pattern should be included in the search.
241 > */
242 > includes: string[];
243 >
244 > /**
245 > * Files that match an `excludes` glob pattern should be excluded from the search.
246 > */
247 > excludes: GlobPattern[];
248 >
249 > /**
250 > * Whether symlinks should be followed while searching.
251 > * For more info, see the setting description for `search.followSymlinks`.
252 > */
253 > followSymlinks: boolean;
254 >
255 > /**
256 > * Which file locations we should look for ignore (.gitignore or .ignore) files to respect.
257 > */
258 > useIgnoreFiles: {
259 > /**
260 > * Use ignore files at the current workspace root.
261 > */
262 > local: boolean;
263 > /**
264 > * Use ignore files at the parent directory. If set, {@link FileSearchProviderOptions.useIgnoreFiles.local} should also be `true`.
265 > */
266 > parent: boolean;
267 > /**
268 > * Use global ignore files. If set, {@link FileSearchProviderOptions.useIgnoreFiles.local} should also be `true`.
269 > */
270 > global: boolean;
271 > };
272 > }
273 >
274 > /**
275 > * Options that apply to file search.
276 > */
277 > export interface FileSearchProviderOptions {
278 > folderOptions: FileSearchProviderFolderOptions[];
279 >
280 > /**
281 > * An object with a lifespan that matches the session's lifespan. If the provider chooses to, this object can be used as the key for a cache,
282 > * and searches with the same session object can search the same cache. When the token is cancelled, the session is complete and the cache can be cleared.
283 > */
284 > session: unknown;
285 >
286 > /**
287 > * The maximum number of results to be returned.
288 > */
289 > maxResults: number;
290 > }
291 >
292 > /**
293 > * The main match information for a {@link TextSearchResult2}.
294 > */
295 > export class TextSearchMatch2 {
296 > /**
297 > * @param uri The uri for the matching document.
298 > * @param ranges The ranges associated with this match.
299 > * @param previewText The text that is used to preview the match. The highlighted range in `previewText` is specified in `ranges`.
300 > */
301 > constructor(
302 public uri: URI,
303 public ranges: { sourceRange: Range; previewRange: Range }[],
304 public previewText: string) { }
306 > }
307 >
308 > /**
309 > * The potential context information for a {@link TextSearchResult2}.
310 > */
311 > export class TextSearchContext2 {
312 > /**
313 > * @param uri The uri for the matching document.
314 > * @param text The line of context text.
315 > * @param lineNumber The line number of this line of context.
316 > */
317 > constructor(
318 public uri: URI,
319 public text: string,
320 public lineNumber: number) { }
322 >
323 > /**
324 > /**
325 > * Keyword suggestion for AI search.
326 > */
327 > export class AISearchKeyword {
328 > /**
329 > * @param keyword The keyword associated with the search.
330 > */
331 > constructor(public keyword: string) { }
332 > }
333 >
334 > /**
335 > * A result payload for a text search, pertaining to matches within a single file.
336 > */
337 > export type TextSearchResult2 = TextSearchMatch2 | TextSearchContext2;
338 >
339 > /**
340 > * A result payload for an AI search.
341 > * This can be a {@link TextSearchMatch2 match} or a {@link AISearchKeyword keyword}.
342 > * The result can be a match or a keyword.
343 > */
344 > export type AISearchResult = TextSearchResult2 | AISearchKeyword;
345 >
346 > /**
347 > * A FileSearchProvider provides search results for files in the given folder that match a query string. It can be invoked by quickaccess or other extensions.
348 > *
349 > * A FileSearchProvider is the more powerful of two ways to implement file search in VS Code. Use a FileSearchProvider if you wish to search within a folder for
350 > * all files that match the user's query.
351 > *
352 > * The FileSearchProvider will be invoked on every keypress in quickaccess. When `workspace.findFiles` is called, it will be invoked with an empty query string,
353 > * and in that case, every file in the folder should be returned.
354 > */
355 > export interface FileSearchProvider2 {
356 > /**
357 > * Provide the set of files that match a certain file path pattern.
358 > * @param query The parameters for this query.
359 > * @param options A set of options to consider while searching files.
360 > * @param progress A progress callback that must be invoked for all results.
361 > * @param token A cancellation token.
362 > */
363 > provideFileSearchResults(pattern: string, options: FileSearchProviderOptions, token: CancellationToken): ProviderResult<URI[]>;
364 > }
365 >
366 > /**
367 > * A TextSearchProvider provides search results for text results inside files in the workspace.
368 > */
369 > export interface TextSearchProvider2 {
370 > /**
371 > * Provide results that match the given text pattern.
372 > * @param query The parameters for this query.
373 > * @param options A set of options to consider while searching.
374 > * @param progress A progress callback that must be invoked for all results.
375 > * @param token A cancellation token.
376 > */
377 > provideTextSearchResults(query: TextSearchQuery2, options: TextSearchProviderOptions, progress: IProgress<TextSearchResult2>, token: CancellationToken): ProviderResult<TextSearchComplete2>;
378 > }
379 >
380 > /**
381 > * Information collected when text search is complete.
382 > */
383 > export interface TextSearchComplete2 {
384 > /**
385 > * Whether the search hit the limit on the maximum number of search results.
386 > * `maxResults` on {@linkcode TextSearchOptions} specifies the max number of results.
387 > * - If exactly that number of matches exist, this should be false.
388 > * - If `maxResults` matches are returned and more exist, this should be true.
389 > * - If search hits an internal limit which is less than `maxResults`, this should be true.
390 > */
391 > limitHit?: boolean;
392 >
393 > /**
394 > * Additional information regarding the state of the completed search.
395 > *
396 > * Messages with "Information" style support links in markdown syntax:
397 > * - Click to [run a command](command:workbench.action.OpenQuickPick)
398 > * - Click to [open a website](https://aka.ms)
399 > *
400 > * Commands may optionally return { triggerSearch: true } to signal to the editor that the original search should run be again.
401 > */
402 > message?: TextSearchCompleteMessage2[];
403 > }
404 >
405 > /**
406 > * A message regarding a completed search.
407 > */
408 > export interface TextSearchCompleteMessage2 {
409 > /**
410 > * Markdown text of the message.
411 > */
412 > text: string;
413 > /**
414 > * Whether the source of the message is trusted, command links are disabled for untrusted message sources.
415 > * Messaged are untrusted by default.
416 > */
417 > trusted?: boolean;
418 > /**
419 > * The message type, this affects how the message will be rendered.
420 > */
421 > type: TextSearchCompleteMessageType;
422 > }
423 >
424 >
425 > /**
426 > * A FileSearchProvider provides search results for files in the given folder that match a query string. It can be invoked by quickaccess or other extensions.
427 > *
428 > * A FileSearchProvider is the more powerful of two ways to implement file search in VS Code. Use a FileSearchProvider if you wish to search within a folder for
429 > * all files that match the user's query.
430 > *
431 > * The FileSearchProvider will be invoked on every keypress in quickaccess. When `workspace.findFiles` is called, it will be invoked with an empty query string,
432 > * and in that case, every file in the folder should be returned.
433 > */
434 > export interface FileSearchProvider2 {
435 > /**
436 > * Provide the set of files that match a certain file path pattern.
437 > * @param query The parameters for this query.
438 > * @param options A set of options to consider while searching files.
439 > * @param progress A progress callback that must be invoked for all results.
440 > * @param token A cancellation token.
441 > */
442 > provideFileSearchResults(pattern: string, options: FileSearchProviderOptions, token: CancellationToken): ProviderResult<URI[]>;
443 > }
444 >
445 > /**
446 > * A TextSearchProvider provides search results for text results inside files in the workspace.
447 > */
448 > export interface TextSearchProvider2 {
449 > /**
450 > * Provide results that match the given text pattern.
451 > * @param query The parameters for this query.
452 > * @param options A set of options to consider while searching.
453 > * @param progress A progress callback that must be invoked for all results.
454 > * @param token A cancellation token.
455 > */
456 > provideTextSearchResults(query: TextSearchQuery2, options: TextSearchProviderOptions, progress: IProgress<TextSearchResult2>, token: CancellationToken): ProviderResult<TextSearchComplete2>;
457 > }
458 >
459 > /**
460 > * Information collected when text search is complete.
461 > */
462 > export interface TextSearchComplete2 {
463 > /**
464 > * Whether the search hit the limit on the maximum number of search results.
465 > * `maxResults` on {@link TextSearchOptions} specifies the max number of results.
466 > * - If exactly that number of matches exist, this should be false.
467 > * - If `maxResults` matches are returned and more exist, this should be true.
468 > * - If search hits an internal limit which is less than `maxResults`, this should be true.
469 > */
470 > limitHit?: boolean;
471 >
472 > /**
473 > * Additional information regarding the state of the completed search.
474 > *
475 > * Messages with "Information" style support links in markdown syntax:
476 > * - Click to [run a command](command:workbench.action.OpenQuickPick)
477 > * - Click to [open a website](https://aka.ms)
478 > *
479 > * Commands may optionally return { triggerSearch: true } to signal to the editor that the original search should run be again.
480 > */
481 > message?: TextSearchCompleteMessage2[];
482 > }
483 >
484 > /**
485 > * A message regarding a completed search.
486 > */
487 > export interface TextSearchCompleteMessage2 {
488 > /**
489 > * Markdown text of the message.
490 > */
491 > text: string;
492 > /**
493 > * Whether the source of the message is trusted, command links are disabled for untrusted message sources.
494 > * Messaged are untrusted by default.
495 > */
496 > trusted?: boolean;
497 > /**
498 > * The message type, this affects how the message will be rendered.
499 > */
500 > type: TextSearchCompleteMessageType;
501 > }
502 >
503 > /**
504 > * Options for following search.exclude and files.exclude settings.
505 > */
506 > export enum ExcludeSettingOptions {
507 > /*
508 > * Don't use any exclude settings.
509 > */
510 > None = 1,
511 > /*
512 > * Use:
513 > * - files.exclude setting
514 > */
515 > FilesExclude = 2,
516 > /*
517 > * Use:
518 > * - files.exclude setting
519 > * - search.exclude setting
520 > */
521 > SearchAndFilesExclude = 3
522 > }
523 >
524 > export enum TextSearchCompleteMessageType {
525 > Information = 1,
526 > Warning = 2,
527 > }
528 >
529 >
530 > /**
531 > * A message regarding a completed search.
532 > */
533 > export interface TextSearchCompleteMessage {
534 > /**
535 > * Markdown text of the message.
536 > */
537 > text: string;
538 > /**
539 > * Whether the source of the message is trusted, command links are disabled for untrusted message sources.
540 > */
541 > trusted?: boolean;
542 > /**
543 > * The message type, this affects how the message will be rendered.
544 > */
545 > type: TextSearchCompleteMessageType;
546 > }
547 >
548 >
549 > /**
550 > * An AITextSearchProvider provides additional AI text search results in the workspace.
551 > */
552 > export interface AITextSearchProvider {
553 >
554 > /**
555 > * The name of the AI searcher. Will be displayed as `{name} Results` in the Search View.
556 > */
557 > readonly name?: string;
558 >
559 > /**
560 > * WARNING: VERY EXPERIMENTAL.
561 > *
562 > * Provide results that match the given text pattern.
563 > * @param query The parameter for this query.
564 > * @param options A set of options to consider while searching.
565 > * @param progress A progress callback that must be invoked for all results.
566 > * @param token A cancellation token.
567 > */
568 > provideAITextSearchResults(query: string, options: TextSearchProviderOptions, progress: IProgress<TextSearchResult2>, token: CancellationToken): ProviderResult<TextSearchComplete2>;
569 > }
src/vs/workbench/services/search/common/search.ts 559 covered LOC · 34 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- search.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { mapArrayOrNot } from '../../../../base/common/arrays.js';
7 > import { CancellationToken } from '../../../../base/common/cancellation.js';
8 > import * as glob from '../../../../base/common/glob.js';
9 > import { IDisposable } from '../../../../base/common/lifecycle.js';
10 > import * as objects from '../../../../base/common/objects.js';
11 > import * as extpath from '../../../../base/common/extpath.js';
12 > import { fuzzyContains, getNLines } from '../../../../base/common/strings.js';
13 > import { URI, UriComponents } from '../../../../base/common/uri.js';
14 > import { IFilesConfiguration } from '../../../../platform/files/common/files.js';
15 > import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
16 > import { ITelemetryData } from '../../../../platform/telemetry/common/telemetry.js';
17 > import { Event } from '../../../../base/common/event.js';
18 > import * as paths from '../../../../base/common/path.js';
19 > import { isCancellationError } from '../../../../base/common/errors.js';
20 > import { AISearchKeyword, GlobPattern, TextSearchCompleteMessageType } from './searchExtTypes.js';
21 > import { isThenable } from '../../../../base/common/async.js';
22 > import { ResourceSet } from '../../../../base/common/map.js';
23 >
24 > export { TextSearchCompleteMessageType };
25 >
26 > export const VIEWLET_ID = 'workbench.view.search';
27 > export const PANEL_ID = 'workbench.panel.search';
28 > export const VIEW_ID = 'workbench.view.search';
29 > export const SEARCH_RESULT_LANGUAGE_ID = 'search-result';
30 >
31 > export const SEARCH_EXCLUDE_CONFIG = 'search.exclude';
32 > export const DEFAULT_MAX_SEARCH_RESULTS = 20000;
33 >
34 > // Warning: this pattern is used in the search editor to detect offsets. If you
35 > // change this, also change the search-result built-in extension
36 > const SEARCH_ELIDED_PREFIX = '⟪ ';
37 > const SEARCH_ELIDED_SUFFIX = ' characters skipped ⟫';
38 > const SEARCH_ELIDED_MIN_LEN = (SEARCH_ELIDED_PREFIX.length + SEARCH_ELIDED_SUFFIX.length + 5) * 2;
39 >
40 > export const ISearchService = createDecorator<ISearchService>('searchService');
41 >
42 > /**
43 > * A service that enables to search for files or with in files.
44 > */
45 > export interface ISearchService {
46 > readonly _serviceBrand: undefined;
47 > textSearch(query: ITextQuery, token?: CancellationToken, onProgress?: (result: ISearchProgressItem) => void): Promise<ISearchComplete>;
48 > aiTextSearch(query: IAITextQuery, token?: CancellationToken, onProgress?: (result: ISearchProgressItem) => void): Promise<ISearchComplete>;
49 > getAIName(): Promise<string | undefined>;
50 > textSearchSplitSyncAsync(query: ITextQuery, token?: CancellationToken | undefined, onProgress?: ((result: ISearchProgressItem) => void) | undefined, notebookFilesToIgnore?: ResourceSet, asyncNotebookFilesToIgnore?: Promise<ResourceSet>): { syncResults: ISearchComplete; asyncResults: Promise<ISearchComplete> };
51 > fileSearch(query: IFileQuery, token?: CancellationToken): Promise<ISearchComplete>;
52 > schemeHasFileSearchProvider(scheme: string): boolean;
53 > clearCache(cacheKey: string): Promise<void>;
54 > registerSearchResultProvider(scheme: string, type: SearchProviderType, provider: ISearchResultProvider): IDisposable;
55 > }
56 >
57 > /**
58 > * TODO@roblou - split text from file search entirely, or share code in a more natural way.
59 > */
60 > export const enum SearchProviderType {
61 > file,
62 > text,
63 > aiText
64 > }
65 >
66 > export interface ISearchResultProvider {
67 > getAIName(): Promise<string | undefined>;
68 > textSearch(query: ITextQuery, onProgress?: (p: ISearchProgressItem) => void, token?: CancellationToken): Promise<ISearchComplete>;
69 > fileSearch(query: IFileQuery, token?: CancellationToken): Promise<ISearchComplete>;
70 > clearCache(cacheKey: string): Promise<void>;
71 > }
72 >
73 >
74 > export interface ExcludeGlobPattern<U extends UriComponents = URI> {
75 > folder?: U;
76 > pattern: glob.IExpression;
77 > }
78 >
79 > export interface IFolderQuery<U extends UriComponents = URI> {
80 > folder: U;
81 > folderName?: string;
82 > excludePattern?: ExcludeGlobPattern<U>[];
83 > includePattern?: glob.IExpression;
84 > ignoreGlobCase?: boolean;
85 > fileEncoding?: string;
86 > disregardIgnoreFiles?: boolean;
87 > disregardGlobalIgnoreFiles?: boolean;
88 > disregardParentIgnoreFiles?: boolean;
89 > ignoreSymlinks?: boolean;
90 > }
91 >
92 > export interface ICommonQueryProps<U extends UriComponents> {
93 > /** For telemetry - indicates what is triggering the source */
94 > _reason?: string;
95 >
96 > folderQueries: IFolderQuery<U>[];
97 > // The include pattern for files that gets passed into ripgrep.
98 > // Note that this will override any ignore files if applicable.
99 > includePattern?: glob.IExpression;
100 > excludePattern?: glob.IExpression;
101 > ignoreGlobCase?: boolean;
102 > extraFileResources?: U[];
103 >
104 > onlyOpenEditors?: boolean;
105 >
106 > maxResults?: number;
107 > usingSearchPaths?: boolean;
108 > onlyFileScheme?: boolean;
109 > }
110 >
111 > export interface IFileQueryProps<U extends UriComponents> extends ICommonQueryProps<U> {
112 > type: QueryType.File;
113 > filePattern?: string;
114 >
115 > // when walking through the tree to find the result, don't use the filePattern to fuzzy match.
116 > // Instead, should use glob matching.
117 > shouldGlobMatchFilePattern?: boolean;
118 >
119 > /**
120 > * If true no results will be returned. Instead `limitHit` will indicate if at least one result exists or not.
121 > * Currently does not work with queries including a 'siblings clause'.
122 > */
123 > exists?: boolean;
124 > sortByScore?: boolean;
125 > cacheKey?: string;
126 > }
127 >
128 > export interface ITextQueryProps<U extends UriComponents> extends ICommonQueryProps<U> {
129 > type: QueryType.Text;
130 > contentPattern: IPatternInfo;
131 >
132 > previewOptions?: ITextSearchPreviewOptions;
133 > maxFileSize?: number;
134 > surroundingContext?: number;
135 >
136 > userDisabledExcludesAndIgnoreFiles?: boolean;
137 > }
138 >
139 > export interface IAITextQueryProps<U extends UriComponents> extends ICommonQueryProps<U> {
140 > type: QueryType.aiText;
141 > contentPattern: string;
142 >
143 > previewOptions?: ITextSearchPreviewOptions;
144 > maxFileSize?: number;
145 > surroundingContext?: number;
146 >
147 > userDisabledExcludesAndIgnoreFiles?: boolean;
148 > }
149 >
150 > export type IFileQuery = IFileQueryProps<URI>;
151 > export type IRawFileQuery = IFileQueryProps<UriComponents>;
152 > export type ITextQuery = ITextQueryProps<URI>;
153 > export type IRawTextQuery = ITextQueryProps<UriComponents>;
154 > export type IAITextQuery = IAITextQueryProps<URI>;
155 > export type IRawAITextQuery = IAITextQueryProps<UriComponents>;
156 >
157 > export type IRawQuery = IRawTextQuery | IRawFileQuery | IRawAITextQuery;
158 > export type ISearchQuery = ITextQuery | IFileQuery | IAITextQuery;
159 > export type ITextSearchQuery = ITextQuery | IAITextQuery;
160 >
161 > export const enum QueryType {
162 > File = 1,
163 > Text = 2,
164 > aiText = 3
165 > }
166 >
167 > /* __GDPR__FRAGMENT__
168 > "IPatternInfo" : {
169 > "isRegExp": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
170 > "isWordMatch": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
171 > "wordSeparators": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
172 > "isMultiline": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
173 > "isCaseSensitive": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
174 > "isSmartCase": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }
175 > }
176 > */
177 > export interface IPatternInfo {
178 > pattern: string;
179 > isRegExp?: boolean;
180 > isWordMatch?: boolean;
181 > wordSeparators?: string;
182 > isMultiline?: boolean;
183 > isUnicode?: boolean;
184 > isCaseSensitive?: boolean;
185 > notebookInfo?: INotebookPatternInfo;
186 > }
187 >
188 > export interface INotebookPatternInfo {
189 > isInNotebookMarkdownInput?: boolean;
190 > isInNotebookMarkdownPreview?: boolean;
191 > isInNotebookCellInput?: boolean;
192 > isInNotebookCellOutput?: boolean;
193 > }
194 >
195 > export interface IFileMatch<U extends UriComponents = URI> {
196 > resource: U;
197 > results?: ITextSearchResult<U>[];
198 > }
199 >
200 > export type IRawFileMatch2 = IFileMatch<UriComponents>;
201 >
202 > export interface ITextSearchPreviewOptions {
203 > matchLines: number;
204 > charsPerLine: number;
205 > }
206 >
207 > export interface ISearchRange {
208 > readonly startLineNumber: number;
209 > readonly startColumn: number;
210 > readonly endLineNumber: number;
211 > readonly endColumn: number;
212 > }
213 >
214 > export interface ITextSearchMatch<U extends UriComponents = URI> {
215 > uri?: U;
216 > rangeLocations: SearchRangeSetPairing[];
217 > previewText: string;
218 > webviewIndex?: number;
219 > cellFragment?: string;
220 > }
221 >
222 > export interface ITextSearchContext<U extends UriComponents = URI> {
223 > uri?: U;
224 > text: string;
225 > lineNumber: number;
226 > }
227 >
228 > export type ITextSearchResult<U extends UriComponents = URI> = ITextSearchMatch<U> | ITextSearchContext<U>;
229 >
230 > export function resultIsMatch(result: ITextSearchResult): result is ITextSearchMatch {
231 return !!(<ITextSearchMatch>result).rangeLocations && !!(<ITextSearchMatch>result).previewText;
232 }
233 > search.ts
234 > export interface IProgressMessage {
235 > message: string;
236 > }
237 >
238 > export type ISearchProgressItem = IFileMatch | IProgressMessage | AISearchKeyword;
239 >
240 > export function isFileMatch(p: ISearchProgressItem): p is IFileMatch {
241 return !!(<IFileMatch>p).resource;
242 }
243 > search.ts
244 > export function isAIKeyword(p: ISearchProgressItem): p is AISearchKeyword {
245 return !!(<AISearchKeyword>p).keyword;
246 }
247 > search.ts
248 > export function isProgressMessage(p: ISearchProgressItem | ISerializedSearchProgressItem): p is IProgressMessage {
249 return !!(p as IProgressMessage).message;
250 }
251 > search.ts
252 > export interface ITextSearchCompleteMessage {
253 > text: string;
254 > type: TextSearchCompleteMessageType;
255 > trusted?: boolean;
256 > }
257 >
258 > export interface ISearchCompleteStats {
259 > limitHit?: boolean;
260 > messages: ITextSearchCompleteMessage[];
261 > stats?: IFileSearchStats | ITextSearchStats;
262 > }
263 >
264 > export interface ISearchComplete extends ISearchCompleteStats {
265 > results: IFileMatch[];
266 > exit?: SearchCompletionExitCode;
267 > aiKeywords?: AISearchKeyword[];
268 > }
269 >
270 > export const enum SearchCompletionExitCode {
271 > Normal,
272 > NewSearchStarted
273 > }
274 >
275 > export interface ITextSearchStats {
276 > type: 'textSearchProvider' | 'searchProcess' | 'aiTextSearchProvider';
277 > }
278 >
279 > export interface IFileSearchStats {
280 > fromCache: boolean;
281 > detailStats: ISearchEngineStats | ICachedSearchStats | IFileSearchProviderStats;
282 >
283 > resultCount: number;
284 > type: 'fileSearchProvider' | 'searchProcess';
285 > sortingTime?: number;
286 > }
287 >
288 > export interface ICachedSearchStats {
289 > cacheWasResolved: boolean;
290 > cacheLookupTime: number;
291 > cacheFilterTime: number;
292 > cacheEntryCount: number;
293 > }
294 >
295 > export interface ISearchEngineStats {
296 > fileWalkTime: number;
297 > directoriesWalked: number;
298 > filesWalked: number;
299 > cmdTime: number;
300 > cmdResultCount?: number;
301 > }
302 >
303 > export interface IFileSearchProviderStats {
304 > providerTime: number;
305 > postProcessTime: number;
306 > }
307 >
308 > export class FileMatch implements IFileMatch {
309 > results: ITextSearchResult[] = [];
310 > constructor(public resource: URI) {
311 // empty
312 }
313 > } search.ts
314 >
315 > export interface SearchRangeSetPairing {
316 > source: ISearchRange;
317 > preview: ISearchRange;
318 > }
319 >
320 > export class TextSearchMatch implements ITextSearchMatch {
321 > rangeLocations: SearchRangeSetPairing[] = [];
322 > previewText: string;
323 > webviewIndex?: number;
324 >
325 > constructor(text: string, ranges: ISearchRange | ISearchRange[], previewOptions?: ITextSearchPreviewOptions, webviewIndex?: number) {
326 this.webviewIndex = webviewIndex;
327
371 }
372 }
373 > } search.ts
374 >
375 function isSingleLineRangeList(ranges: ISearchRange[]): boolean {
376 const line = ranges[0].startLineNumber;
383 return true;
384 }
385 > search.ts
386 > export class SearchRange implements ISearchRange {
387 > startLineNumber: number;
388 > startColumn: number;
389 > endLineNumber: number;
390 > endColumn: number;
391 >
392 > constructor(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number) {
393 this.startLineNumber = startLineNumber;
394 this.startColumn = startColumn;
396 this.endColumn = endColumn;
397 }
398 > } search.ts
399 >
400 > export class OneLineRange extends SearchRange {
401 > constructor(lineNumber: number, startColumn: number, endColumn: number) {
402 super(lineNumber, startColumn, lineNumber, endColumn);
403 }
404 > } search.ts
405 >
406 > export const enum ViewMode {
407 > List = 'list',
408 > Tree = 'tree'
409 > }
410 >
411 > export const enum SearchSortOrder {
412 > Default = 'default',
413 > FileNames = 'fileNames',
414 > Type = 'type',
415 > Modified = 'modified',
416 > CountDescending = 'countDescending',
417 > CountAscending = 'countAscending'
418 > }
419 >
420 > export const enum SemanticSearchBehavior {
421 > Auto = 'auto',
422 > Manual = 'manual',
423 > RunOnEmpty = 'runOnEmpty',
424 > }
425 >
426 > export interface ISearchConfigurationProperties {
427 > exclude: glob.IExpression;
428 > /**
429 > * Use ignore file for file search.
430 > */
431 > useIgnoreFiles: boolean;
432 > useGlobalIgnoreFiles: boolean;
433 > useParentIgnoreFiles: boolean;
434 > followSymlinks: boolean;
435 > smartCase: boolean;
436 > globalFindClipboard: boolean;
437 > useReplacePreview: boolean;
438 > showLineNumbers: boolean;
439 > actionsPosition: 'auto' | 'right';
440 > maxResults: number | null;
441 > collapseResults: 'auto' | 'alwaysCollapse' | 'alwaysExpand';
442 > searchOnType: boolean;
443 > seedOnFocus: boolean;
444 > seedWithNearestWord: boolean;
445 > searchOnTypeDebouncePeriod: number;
446 > mode: 'view' | 'reuseEditor' | 'newEditor';
447 > searchEditor: {
448 > doubleClickBehaviour: 'selectWord' | 'goToLocation' | 'openLocationToSide';
449 > singleClickBehaviour: 'default' | 'peekDefinition';
450 > reusePriorSearchConfiguration: boolean;
451 > defaultNumberOfContextLines: number | null;
452 > focusResultsOnSearch: boolean;
453 > experimental: {};
454 > };
455 > sortOrder: SearchSortOrder;
456 > decorations: {
457 > colors: boolean;
458 > badges: boolean;
459 > };
460 > quickAccess: {
461 > preserveInput: boolean;
462 > };
463 > defaultViewMode: ViewMode;
464 > experimental: {
465 > closedNotebookRichContentResults: boolean;
466 > };
467 > searchView: {
468 > semanticSearchBehavior: string;
469 > keywordSuggestions: boolean;
470 > };
471 > }
472 >
473 > export interface ISearchConfiguration extends IFilesConfiguration {
474 > search?: ISearchConfigurationProperties;
475 > editor: {
476 > wordSeparators: string;
477 > };
478 > }
479 >
480 > export function getExcludes(configuration: ISearchConfiguration, includeSearchExcludes = true): glob.IExpression | undefined {
481 const fileExcludes = configuration && configuration.files && configuration.files.exclude;
482 const searchExcludes = includeSearchExcludes && configuration && configuration.search && configuration.search.exclude;
497 return allExcludes;
498 }
499 > search.ts
500 > export function pathIncludedInQuery(queryProps: ICommonQueryProps<URI>, fsPath: string): boolean {
501 const globOptions = queryProps.ignoreGlobCase ? { ignoreCase: true } : undefined;
502 if (queryProps.excludePattern && glob.match(queryProps.excludePattern, fsPath, globOptions)) {
527 return true;
528 }
529 > search.ts
530 > export enum SearchErrorCode {
531 > unknownEncoding = 1,
532 > regexParseError,
533 > globParseError,
534 > invalidLiteral,
535 > rgProcessError,
536 > other,
537 > canceled
538 > }
539 >
540 > export class SearchError extends Error {
541 > constructor(message: string, readonly code?: SearchErrorCode) {
542 super(message);
543 }
544 > } search.ts
545 >
546 > export function deserializeSearchError(error: Error): SearchError {
547 const errorMsg = error.message;
548
558 }
559 }
560 > search.ts
561 > export function serializeSearchError(searchError: SearchError): Error {
562 const details = { message: searchError.message, code: searchError.code };
563 return new Error(JSON.stringify(details));
564 }
565 > export interface ITelemetryEvent { search.ts
566 > eventName: string;
567 > data: ITelemetryData;
568 > }
569 >
570 > export interface IRawSearchService {
571 > fileSearch(search: IRawFileQuery): Event<ISerializedSearchProgressItem | ISerializedSearchComplete>;
572 > textSearch(search: IRawTextQuery): Event<ISerializedSearchProgressItem | ISerializedSearchComplete>;
573 > clearCache(cacheKey: string): Promise<void>;
574 > }
575 >
576 > export interface IRawFileMatch {
577 > base?: string;
578 > /**
579 > * The path of the file relative to the containing `base` folder.
580 > * This path is exactly as it appears on the filesystem.
581 > */
582 > relativePath: string;
583 > /**
584 > * This path is transformed for search purposes. For example, this could be
585 > * the `relativePath` with the workspace folder name prepended. This way the
586 > * search algorithm would also match against the name of the containing folder.
587 > *
588 > * If not given, the search algorithm should use `relativePath`.
589 > */
590 > searchPath: string | undefined;
591 > }
592 >
593 > export interface ISearchEngine<T> {
594 > search: (onResult: (matches: T) => void, onProgress: (progress: IProgressMessage) => void, done: (error: Error | null, complete: ISearchEngineSuccess) => void) => void;
595 > cancel: () => void;
596 > }
597 >
598 > export interface ISerializedSearchSuccess {
599 > type: 'success';
600 > limitHit: boolean;
601 > messages: ITextSearchCompleteMessage[];
602 > stats?: IFileSearchStats | ITextSearchStats;
603 > }
604 >
605 > export interface ISearchEngineSuccess {
606 > limitHit: boolean;
607 > messages: ITextSearchCompleteMessage[];
608 > stats: ISearchEngineStats;
609 > }
610 >
611 > export interface ISerializedSearchError {
612 > type: 'error';
613 > error: {
614 > message: string;
615 > stack: string;
616 > };
617 > }
618 >
619 > export type ISerializedSearchComplete = ISerializedSearchSuccess | ISerializedSearchError;
620 >
621 > export function isSerializedSearchComplete(arg: ISerializedSearchProgressItem | ISerializedSearchComplete): arg is ISerializedSearchComplete {
622 // eslint-disable-next-line local/code-no-any-casts
623 if ((arg as any).type === 'error') {
630 }
631 }
632 > search.ts
633 > export function isSerializedSearchSuccess(arg: ISerializedSearchComplete): arg is ISerializedSearchSuccess {
634 return arg.type === 'success';
635 }
636 > search.ts
637 > export function isSerializedFileMatch(arg: ISerializedSearchProgressItem): arg is ISerializedFileMatch {
638 return !!(<ISerializedFileMatch>arg).path;
639 }
640 > search.ts
641 > const filePatternIgnoreCaseOptions = { ignoreCase: true };
642 >
643 > export function isFilePatternMatch(candidate: IRawFileMatch, filePatternToUse: string, fuzzy = true, ignoreCase?: boolean): boolean {
644 const pathToMatch = candidate.searchPath ? candidate.searchPath : candidate.relativePath;
645 return fuzzy ?
647 glob.match(filePatternToUse, pathToMatch, ignoreCase ? filePatternIgnoreCaseOptions : undefined);
648 }
649 > search.ts
650 > export interface ISerializedFileMatch {
651 > path: string;
652 > results?: ITextSearchResult[];
653 > numMatches?: number;
654 > }
655 >
656 > // Type of the possible values for progress calls from the engine
657 > export type ISerializedSearchProgressItem = ISerializedFileMatch | ISerializedFileMatch[] | IProgressMessage;
658 > export type IFileSearchProgressItem = IRawFileMatch | IRawFileMatch[] | IProgressMessage;
659 >
660 >
661 > export class SerializableFileMatch implements ISerializedFileMatch {
662 > path: string;
663 > results: ITextSearchMatch[];
664 >
665 > constructor(path: string) {
666 this.path = path;
667 this.results = [];
668 }
669 > search.ts
670 > addMatch(match: ITextSearchMatch): void {
671 this.results.push(match);
672 }
673 > search.ts
674 > serialize(): ISerializedFileMatch {
675 return {
676 path: this.path,
679 };
680 }
681 > } search.ts
682 >
683 > /**
684 > * Computes the patterns that the provider handles. Discards sibling clauses and 'false' patterns
685 > */
686 > export function resolvePatternsForProvider(globalPattern: glob.IExpression | undefined, folderPattern: glob.IExpression | undefined): string[] {
687 const merged = {
688 ...(globalPattern || {}),
696 });
697 }
698 > search.ts
699 > export class QueryGlobTester {
700 >
701 > private _excludeExpression: glob.IExpression[]; // TODO: evaluate globs based on baseURI of pattern
702 > private _parsedExcludeExpression: glob.ParsedExpression[];
703 >
704 > private _parsedIncludeExpression: glob.ParsedExpression | null = null;
705 >
706 > constructor(config: ISearchQuery, folderQuery: IFolderQuery) {
707 const globOptions = config.ignoreGlobCase || folderQuery.ignoreGlobCase ? { ignoreCase: true } : undefined;
708
739 }
740 }
741 > search.ts
742 > private _evalParsedExcludeExpression(testPath: string, basename: string | undefined, hasSibling?: (name: string) => boolean): string | null {
743 // todo: less hacky way of evaluating sync vs async sibling clauses
744 let result: string | null = null;
756 return result;
757 }
758 > search.ts
759 >
760 > matchesExcludesSync(testPath: string, basename?: string, hasSibling?: (name: string) => boolean): boolean {
761 if (this._parsedExcludeExpression && this._evalParsedExcludeExpression(testPath, basename, hasSibling)) {
762 return true;
765 return false;
766 }
767 > search.ts
768 > /**
769 > * Guaranteed sync - siblingsFn should not return a promise.
770 > */
771 > includedInQuerySync(testPath: string, basename?: string, hasSibling?: (name: string) => boolean): boolean {
772 if (this._parsedExcludeExpression && this._evalParsedExcludeExpression(testPath, basename, hasSibling)) {
773 return false;
780 return true;
781 }
782 > search.ts
783 > /**
784 > * Evaluating the exclude expression is only async if it includes sibling clauses. As an optimization, avoid doing anything with Promises
785 > * unless the expression is async.
786 > */
787 > includedInQuery(testPath: string, basename?: string, hasSibling?: (name: string) => boolean | Promise<boolean>): Promise<boolean> | boolean {
788
789 const isIncluded = () => {
811
812 }
813 > search.ts
814 > hasSiblingExcludeClauses(): boolean {
815 return this._excludeExpression.reduce((prev, curr) => hasSiblingClauses(curr) || prev, false);
816 }
817 > } search.ts
818 >
819 function hasSiblingClauses(pattern: glob.IExpression): boolean {
820 for (const key in pattern) {
826 return false;
827 }
828 > search.ts
829 > export function hasSiblingPromiseFn(siblingsFn?: () => Promise<string[]>) {
830 if (!siblingsFn) {
831 return undefined;
841 };
842 }
843 > search.ts
844 > export function hasSiblingFn(siblingsFn?: () => string[]) {
845 if (!siblingsFn) {
846 return undefined;
856 };
857 }
858 > search.ts
859 function listToMap(list: string[]) {
860 const map: Record<string, true> = {};
864 return map;
865 }
866 > search.ts
867 > export function excludeToGlobPattern(excludesForFolder: { baseUri?: URI | undefined; patterns: string[] }[]): GlobPattern[] {
868 return excludesForFolder.flatMap(exclude => exclude.patterns.map(pattern => {
869 return exclude.baseUri ?
874 }));
875 }
876 > search.ts
877 > export const DEFAULT_TEXT_SEARCH_PREVIEW_OPTIONS = {
878 > matchLines: 100,
879 > charsPerLine: 10000
880 > };
src/vs/platform/editor/common/editor.ts 541 covered LOC · 3 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- editor.ts
2 > * Copyright (c) Microsoft 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 { Event } from '../../../base/common/event.js';
8 > import { IDisposable } from '../../../base/common/lifecycle.js';
9 > import { URI } from '../../../base/common/uri.js';
10 > import { IContextKeyService } from '../../contextkey/common/contextkey.js';
11 > import { IUriIdentityService } from '../../uriIdentity/common/uriIdentity.js';
12 > import { IRectangle } from '../../window/common/window.js';
13 >
14 > export interface IResolvableEditorModel extends IDisposable {
15 >
16 > /**
17 > * Resolves the model.
18 > */
19 > resolve(): Promise<void>;
20 >
21 > /**
22 > * Find out if the editor model was resolved or not.
23 > */
24 > isResolved(): boolean;
25 > }
26 >
27 > export function isResolvedEditorModel(model: IDisposable | undefined | null): model is IResolvableEditorModel {
28 const candidate = model as IResolvableEditorModel | undefined | null;
29
31 && typeof candidate?.isResolved === 'function';
32 }
33 > editor.ts
34 > export interface IBaseUntypedEditorInput {
35 >
36 > /**
37 > * Optional options to use when opening the input.
38 > */
39 > options?: IEditorOptions;
40 >
41 > /**
42 > * Label to show for the input.
43 > */
44 > readonly label?: string;
45 >
46 > /**
47 > * Description to show for the input.
48 > */
49 > readonly description?: string;
50 > }
51 >
52 > export interface IBaseResourceEditorInput extends IBaseUntypedEditorInput {
53 >
54 > /**
55 > * Hint to indicate that this input should be treated as a
56 > * untitled file.
57 > *
58 > * Without this hint, the editor service will make a guess by
59 > * looking at the scheme of the resource(s).
60 > *
61 > * Use `forceUntitled: true` when you pass in a `resource` that
62 > * does not use the `untitled` scheme. The `resource` will then
63 > * be used as associated path when saving the untitled file.
64 > */
65 > readonly forceUntitled?: boolean;
66 > }
67 >
68 > export interface IBaseTextResourceEditorInput extends IBaseResourceEditorInput {
69 >
70 > /**
71 > * Optional options to use when opening the text input.
72 > */
73 > options?: ITextEditorOptions;
74 >
75 > /**
76 > * The contents of the text input if known. If provided,
77 > * the input will not attempt to load the contents from
78 > * disk and may appear dirty.
79 > */
80 > contents?: string;
81 >
82 > /**
83 > * The encoding of the text input if known.
84 > */
85 > encoding?: string;
86 >
87 > /**
88 > * The identifier of the language id of the text input
89 > * if known to use when displaying the contents.
90 > */
91 > languageId?: string;
92 > }
93 >
94 > export interface IResourceEditorInput extends IBaseResourceEditorInput {
95 >
96 > /**
97 > * The resource URI of the resource to open.
98 > */
99 > readonly resource: URI;
100 > }
101 >
102 > export interface ITextResourceEditorInput extends IResourceEditorInput, IBaseTextResourceEditorInput {
103 >
104 > /**
105 > * Optional options to use when opening the text input.
106 > */
107 > options?: ITextEditorOptions;
108 > }
109 >
110 > /**
111 > * This identifier allows to uniquely identify an editor with a
112 > * resource, type and editor identifier.
113 > */
114 > export interface IResourceEditorInputIdentifier {
115 >
116 > /**
117 > * The type of the editor.
118 > */
119 > readonly typeId: string;
120 >
121 > /**
122 > * The identifier of the editor if provided.
123 > */
124 > readonly editorId: string | undefined;
125 >
126 > /**
127 > * The resource URI of the editor.
128 > */
129 > readonly resource: URI;
130 > }
131 >
132 > export enum EditorActivation {
133 >
134 > /**
135 > * Activate the editor after it opened. This will automatically restore
136 > * the editor if it is minimized.
137 > */
138 > ACTIVATE = 1,
139 >
140 > /**
141 > * Only restore the editor if it is minimized but do not activate it.
142 > *
143 > * Note: will only work in combination with the `preserveFocus: true` option.
144 > * Otherwise, if focus moves into the editor, it will activate and restore
145 > * automatically.
146 > */
147 > RESTORE,
148 >
149 > /**
150 > * Preserve the current active editor.
151 > *
152 > * Note: will only work in combination with the `preserveFocus: true` option.
153 > * Otherwise, if focus moves into the editor, it will activate and restore
154 > * automatically.
155 > */
156 > PRESERVE
157 > }
158 >
159 > export enum EditorResolution {
160 >
161 > /**
162 > * Displays a picker and allows the user to decide which editor to use.
163 > */
164 > PICK,
165 >
166 > /**
167 > * Only exclusive editors are considered.
168 > */
169 > EXCLUSIVE_ONLY
170 > }
171 >
172 > export enum EditorOpenSource {
173 >
174 > /**
175 > * Default: the editor is opening via a programmatic call
176 > * to the editor service API.
177 > */
178 > API,
179 >
180 > /**
181 > * Indicates that a user action triggered the opening, e.g.
182 > * via mouse or keyboard use.
183 > */
184 > USER
185 > }
186 >
187 > export interface IEditorOptions {
188 >
189 > /**
190 > * Tells the editor to not receive keyboard focus when the editor is being opened.
191 > *
192 > * Will also not activate the group the editor opens in unless the group is already
193 > * the active one. This behaviour can be overridden via the `activation` option.
194 > */
195 > preserveFocus?: boolean;
196 >
197 > /**
198 > * This option is only relevant if an editor is opened into a group that is not active
199 > * already and allows to control if the inactive group should become active, restored
200 > * or preserved.
201 > *
202 > * By default, the editor group will become active unless `preserveFocus` or `inactive`
203 > * is specified.
204 > */
205 > activation?: EditorActivation;
206 >
207 > /**
208 > * Tells the editor to reload the editor input in the editor even if it is identical to the one
209 > * already showing. By default, the editor will not reload the input if it is identical to the
210 > * one showing.
211 > */
212 > forceReload?: boolean;
213 >
214 > /**
215 > * Will reveal the editor if it is already opened and visible in any of the opened editor groups.
216 > *
217 > * Note that this option is just a hint that might be ignored if the user wants to open an editor explicitly
218 > * to the side of another one or into a specific editor group.
219 > */
220 > revealIfVisible?: boolean;
221 >
222 > /**
223 > * Will reveal the editor if it is already opened (even when not visible) in any of the opened editor groups.
224 > *
225 > * Note that this option is just a hint that might be ignored if the user wants to open an editor explicitly
226 > * to the side of another one or into a specific editor group.
227 > */
228 > revealIfOpened?: boolean;
229 >
230 > /**
231 > * An editor that is pinned remains in the editor stack even when another editor is being opened.
232 > * An editor that is not pinned will always get replaced by another editor that is not pinned.
233 > */
234 > pinned?: boolean;
235 >
236 > /**
237 > * An editor that is sticky moves to the beginning of the editors list within the group and will remain
238 > * there unless explicitly closed. Operations such as "Close All" will not close sticky editors.
239 > */
240 > sticky?: boolean;
241 >
242 > /**
243 > * The index in the document stack where to insert the editor into when opening.
244 > */
245 > index?: number;
246 >
247 > /**
248 > * An active editor that is opened will show its contents directly. Set to true to open an editor
249 > * in the background without loading its contents.
250 > *
251 > * Will also not activate the group the editor opens in unless the group is already
252 > * the active one. This behaviour can be overridden via the `activation` option.
253 > */
254 > inactive?: boolean;
255 >
256 > /**
257 > * In case of an error opening the editor, will not present this error to the user (e.g. by showing
258 > * a generic placeholder in the editor area). So it is up to the caller to provide error information
259 > * in that case.
260 > *
261 > * By default, an error when opening an editor will result in a placeholder editor that shows the error.
262 > * In certain cases a modal dialog may be presented to ask the user for further action.
263 > */
264 > ignoreError?: boolean;
265 >
266 > /**
267 > * Allows to override the editor that should be used to display the input:
268 > * - `undefined`: let the editor decide for itself
269 > * - `string`: specific override by id
270 > * - `EditorResolution`: specific override handling
271 > */
272 > override?: string | EditorResolution;
273 >
274 > /**
275 > * A optional hint to signal in which context the editor opens.
276 > *
277 > * If configured to be `EditorOpenSource.USER`, this hint can be
278 > * used in various places to control the experience. For example,
279 > * if the editor to open fails with an error, a notification could
280 > * inform about this in a modal dialog. If the editor opened through
281 > * some background task, the notification would show in the background,
282 > * not as a modal dialog.
283 > */
284 > source?: EditorOpenSource;
285 >
286 > /**
287 > * Indicates whether the editor is being opened due to an explicit user
288 > * action (`true`) or automatically (`false`) as a side effect of another
289 > * action (e.g. the chat agent opening files it has edited).
290 > *
291 > * When omitted, callers should be treated as explicit. Layout logic may
292 > * use this to decide whether to react to the visibility change (for
293 > * example, by leaving the auxiliary side bar maximized when the change
294 > * was not initiated by the user).
295 > */
296 > isExplicit?: boolean;
297 >
298 > /**
299 > * An optional property to signal that certain view state should be
300 > * applied when opening the editor.
301 > */
302 > viewState?: object;
303 >
304 > /**
305 > * A transient editor will attempt to appear as preview and certain components
306 > * (such as history tracking) may decide to ignore the editor when it becomes
307 > * active.
308 > * This option is meant to be used only when the editor is used for a short
309 > * period of time, for example when opening a preview of the editor from a
310 > * picker control in the background while navigating through results of the picker.
311 > *
312 > * Note: an editor that is already opened in a group that is not transient, will
313 > * not turn transient.
314 > */
315 > transient?: boolean;
316 >
317 > /**
318 > * Options that only apply when `AUX_WINDOW_GROUP` is used for opening.
319 > */
320 > auxiliary?: {
321 >
322 > /**
323 > * Define the bounds of the editor window.
324 > */
325 > bounds?: Partial<IRectangle>;
326 >
327 > /**
328 > * Show editor compact, hiding unnecessary elements.
329 > */
330 > compact?: boolean;
331 >
332 > /**
333 > * Show the editor always on top of other windows.
334 > */
335 > alwaysOnTop?: boolean;
336 > };
337 >
338 > /**
339 > * Options that only apply when `MODAL_GROUP` is used for opening.
340 > */
341 > modal?: IModalEditorPartOptions;
342 > }
343 >
344 > export interface IModalEditorPartOptions {
345 >
346 > /**
347 > * Whether the modal editor should be maximized.
348 > */
349 > readonly maximized?: boolean;
350 >
351 > /**
352 > * Size of the modal editor part unless it is maximized.
353 > */
354 > readonly size?: { readonly width: number; readonly height: number };
355 >
356 > /**
357 > * Position of the modal editor part unless it is maximized.
358 > */
359 > readonly position?: { readonly left: number; readonly top: number };
360 >
361 > /**
362 > * The navigation context for navigating between items
363 > * within this modal editor. Pass `undefined` to clear.
364 > */
365 > readonly navigation?: IModalEditorNavigation;
366 >
367 > /**
368 > * Optional sidebar content to render on the left side of the
369 > * modal editor. The caller provides a render callback that
370 > * receives a container element and a layout callback, and
371 > * returns a disposable to clean up when the modal closes.
372 > *
373 > * Note: the sidebar will only be shown when provided during
374 > * opening and cannot currently be added, removed, or updated
375 > * after the modal editor is opened.
376 > */
377 > readonly sidebar?: IModalEditorSidebar;
378 > }
379 >
380 > /**
381 > * Per-editor modal options provided by an editor input that wants to influence
382 > * how it is rendered inside the modal editor part. Unlike
383 > * {@link IModalEditorPartOptions}, these options are scoped to a single editor
384 > * and resolved from the active editor (not from the part-level options API).
385 > */
386 > export interface IModalEditorOptions {
387 >
388 > /**
389 > * When true, the modal editor renders a simplified header:
390 > * uses the editor background, hides the title icon, removes the
391 > * bottom border and uses a slightly taller fixed height. Useful
392 > * for editors that provide their own header chrome.
393 > */
394 > readonly compactHeader?: boolean;
395 > }
396 >
397 > /**
398 > * Marker interface for editor inputs that want to customize how they are
399 > * rendered when opened in the modal editor part (see {@link IModalEditorOptions}).
400 > */
401 > export interface IModalEditorOptionsProvider {
402 > getModalEditorOptions(): IModalEditorOptions | undefined;
403 > }
404 >
405 > export function isModalEditorOptionsProvider(obj: unknown): obj is IModalEditorOptionsProvider {
406 return !!obj && typeof (obj as IModalEditorOptionsProvider).getModalEditorOptions === 'function';
407 }
408 > editor.ts
409 > /**
410 > * Modal sidebar supports rendering custom content in a sidebar next to the main editor content.
411 > */
412 > export interface IModalEditorSidebar {
413 >
414 > /**
415 > * Sidebar width set by the user via resizing, if any.
416 > */
417 > readonly sidebarWidth?: number;
418 >
419 > /**
420 > * Whether the sidebar is hidden.
421 > */
422 > readonly sidebarHidden?: boolean;
423 >
424 > /**
425 > * Render the sidebar content into the given container.
426 > *
427 > * @param container The DOM element to render into.
428 > * @param onDidLayout An event that fires when the sidebar is
429 > * laid out with the available dimensions.
430 > * @param contextKeyService A context key service scoped to the modal
431 > * that content should descend from (e.g. when creating lists/trees)
432 > * so that modal-level context keys remain active while the content
433 > * has focus.
434 > * @returns A disposable to clean up when the modal closes.
435 > */
436 > readonly render: (container: unknown /* HTMLElement */, onDidLayout: Event<{ readonly height: number; readonly width: number }>, contextKeyService: IContextKeyService) => IDisposable;
437 > }
438 >
439 > /**
440 > * Context for navigating between items within a modal editor.
441 > */
442 > export interface IModalEditorNavigation {
443 >
444 > /**
445 > * Total number of items in the navigation list.
446 > */
447 > readonly total: number;
448 >
449 > /**
450 > * Current 0-based index in the navigation list.
451 > */
452 > readonly current: number;
453 >
454 > /**
455 > * Navigate to the item at the given 0-based index.
456 > */
457 > readonly navigate: (index: number) => void;
458 > }
459 >
460 > export interface ITextEditorSelection {
461 > readonly startLineNumber: number;
462 > readonly startColumn: number;
463 > readonly endLineNumber?: number;
464 > readonly endColumn?: number;
465 > }
466 >
467 > export const enum TextEditorSelectionRevealType {
468 > /**
469 > * Option to scroll vertically or horizontally as necessary and reveal a range centered vertically.
470 > */
471 > Center = 0,
472 >
473 > /**
474 > * Option to scroll vertically or horizontally as necessary and reveal a range centered vertically only if it lies outside the viewport.
475 > */
476 > CenterIfOutsideViewport = 1,
477 >
478 > /**
479 > * Option to scroll vertically or horizontally as necessary and reveal a range close to the top of the viewport, but not quite at the top.
480 > */
481 > NearTop = 2,
482 >
483 > /**
484 > * Option to scroll vertically or horizontally as necessary and reveal a range close to the top of the viewport, but not quite at the top.
485 > * Only if it lies outside the viewport
486 > */
487 > NearTopIfOutsideViewport = 3,
488 > }
489 >
490 > export const enum TextEditorSelectionSource {
491 >
492 > /**
493 > * Programmatic source indicates a selection change that
494 > * was not triggered by the user via keyboard or mouse
495 > * but through text editor APIs.
496 > */
497 > PROGRAMMATIC = 'api',
498 >
499 > /**
500 > * Navigation source indicates a selection change that
501 > * was caused via some command or UI component such as
502 > * an outline tree.
503 > */
504 > NAVIGATION = 'code.navigation',
505 >
506 > /**
507 > * Jump source indicates a selection change that
508 > * was caused from within the text editor to another
509 > * location in the same or different text editor such
510 > * as "Go to definition".
511 > */
512 > JUMP = 'code.jump'
513 > }
514 >
515 > export interface ITextEditorOptions extends IEditorOptions {
516 >
517 > /**
518 > * Text editor selection.
519 > */
520 > selection?: ITextEditorSelection;
521 >
522 > /**
523 > * Option to control the text editor selection reveal type.
524 > * Defaults to TextEditorSelectionRevealType.Center
525 > */
526 > selectionRevealType?: TextEditorSelectionRevealType;
527 >
528 > /**
529 > * Source of the call that caused the selection.
530 > */
531 > selectionSource?: TextEditorSelectionSource | string;
532 > }
533 >
534 > export type ITextEditorChange = [
535 > originalStartLineNumber: number,
536 > originalEndLineNumberExclusive: number,
537 > modifiedStartLineNumber: number,
538 > modifiedEndLineNumberExclusive: number
539 > ];
540 >
541 > export interface ITextEditorDiffInformation {
542 > readonly documentVersion: number;
543 > readonly original: URI | undefined;
544 > readonly modified: URI;
545 > readonly changes: readonly ITextEditorChange[];
546 > }
547 >
548 > export function isTextEditorDiffInformationEqual(
549 uriIdentityService: IUriIdentityService,
550 diff1: ITextEditorDiffInformation | undefined,
src/vs/platform/extensions/common/extensionsApiProposals.ts 539 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extensionsApiProposals.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > // THIS IS A GENERATED FILE. DO NOT EDIT DIRECTLY.
7 >
8 > const _allApiProposals = {
9 > activeComment: {
10 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.activeComment.d.ts',
11 > },
12 > agentEditorComments: {
13 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.agentEditorComments.d.ts',
14 > },
15 > agentSessionsWorkspace: {
16 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.agentSessionsWorkspace.d.ts',
17 > },
18 > agentsWindowConfiguration: {
19 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.agentsWindowConfiguration.d.ts',
20 > },
21 > aiRelatedInformation: {
22 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.aiRelatedInformation.d.ts',
23 > },
24 > aiSettingsSearch: {
25 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.aiSettingsSearch.d.ts',
26 > },
27 > aiTextSearchProvider: {
28 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.aiTextSearchProvider.d.ts',
29 > },
30 > authIssuers: {
31 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.authIssuers.d.ts',
32 > },
33 > authLearnMore: {
34 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.authLearnMore.d.ts',
35 > },
36 > authProviderSpecific: {
37 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.authProviderSpecific.d.ts',
38 > },
39 > authSession: {
40 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.authSession.d.ts',
41 > },
42 > authSessionAudience: {
43 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.authSessionAudience.d.ts',
44 > },
45 > authenticationChallenges: {
46 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.authenticationChallenges.d.ts',
47 > },
48 > browser: {
49 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.browser.d.ts',
50 > },
51 > canonicalUriProvider: {
52 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.canonicalUriProvider.d.ts',
53 > },
54 > chatContextProvider: {
55 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatContextProvider.d.ts',
56 > },
57 > chatDebug: {
58 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatDebug.d.ts',
59 > },
60 > chatHooks: {
61 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatHooks.d.ts',
62 > },
63 > chatInputNotification: {
64 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatInputNotification.d.ts',
65 > },
66 > chatOutputRenderer: {
67 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatOutputRenderer.d.ts',
68 > },
69 > chatParticipantAdditions: {
70 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatParticipantAdditions.d.ts',
71 > },
72 > chatParticipantPrivate: {
73 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatParticipantPrivate.d.ts',
74 > },
75 > chatPromptFiles: {
76 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatPromptFiles.d.ts',
77 > },
78 > chatProvider: {
79 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatProvider.d.ts',
80 > },
81 > chatReferenceBinaryData: {
82 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatReferenceBinaryData.d.ts',
83 > },
84 > chatReferenceDiagnostic: {
85 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatReferenceDiagnostic.d.ts',
86 > },
87 > chatSessionCustomizationProvider: {
88 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatSessionCustomizationProvider.d.ts',
89 > },
90 > chatSessionsProvider: {
91 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatSessionsProvider.d.ts',
92 > },
93 > chatStatusItem: {
94 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatStatusItem.d.ts',
95 > },
96 > chatTab: {
97 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatTab.d.ts',
98 > },
99 > codeActionAI: {
100 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.codeActionAI.d.ts',
101 > },
102 > codeActionRanges: {
103 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.codeActionRanges.d.ts',
104 > },
105 > codiconDecoration: {
106 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.codiconDecoration.d.ts',
107 > },
108 > commentReactor: {
109 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.commentReactor.d.ts',
110 > },
111 > commentReveal: {
112 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.commentReveal.d.ts',
113 > },
114 > commentThreadApplicability: {
115 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.commentThreadApplicability.d.ts',
116 > },
117 > commentingRangeHint: {
118 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.commentingRangeHint.d.ts',
119 > },
120 > commentsDraftState: {
121 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.commentsDraftState.d.ts',
122 > },
123 > contribAccessibilityHelpContent: {
124 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribAccessibilityHelpContent.d.ts',
125 > },
126 > contribChatEditorInlineGutterMenu: {
127 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribChatEditorInlineGutterMenu.d.ts',
128 > },
129 > contribCommentEditorActionsMenu: {
130 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribCommentEditorActionsMenu.d.ts',
131 > },
132 > contribCommentPeekContext: {
133 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribCommentPeekContext.d.ts',
134 > },
135 > contribCommentThreadAdditionalMenu: {
136 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribCommentThreadAdditionalMenu.d.ts',
137 > },
138 > contribCommentsViewThreadMenus: {
139 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribCommentsViewThreadMenus.d.ts',
140 > },
141 > contribDebugCreateConfiguration: {
142 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribDebugCreateConfiguration.d.ts',
143 > },
144 > contribDiffEditorGutterToolBarMenus: {
145 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribDiffEditorGutterToolBarMenus.d.ts',
146 > },
147 > contribEditSessions: {
148 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribEditSessions.d.ts',
149 > },
150 > contribEditorContentMenu: {
151 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribEditorContentMenu.d.ts',
152 > },
153 > contribLabelFormatterWorkspaceTooltip: {
154 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribLabelFormatterWorkspaceTooltip.d.ts',
155 > },
156 > contribLanguageModelToolSets: {
157 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribLanguageModelToolSets.d.ts',
158 > },
159 > contribMenuBarHome: {
160 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribMenuBarHome.d.ts',
161 > },
162 > contribMergeEditorMenus: {
163 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribMergeEditorMenus.d.ts',
164 > },
165 > contribMultiDiffEditorMenus: {
166 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribMultiDiffEditorMenus.d.ts',
167 > },
168 > contribNotebookStaticPreloads: {
169 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribNotebookStaticPreloads.d.ts',
170 > },
171 > contribRemoteHelp: {
172 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribRemoteHelp.d.ts',
173 > },
174 > contribShareMenu: {
175 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribShareMenu.d.ts',
176 > },
177 > contribSourceControlArtifactGroupMenu: {
178 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribSourceControlArtifactGroupMenu.d.ts',
179 > },
180 > contribSourceControlArtifactMenu: {
181 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribSourceControlArtifactMenu.d.ts',
182 > },
183 > contribSourceControlHistoryItemMenu: {
184 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribSourceControlHistoryItemMenu.d.ts',
185 > },
186 > contribSourceControlHistoryTitleMenu: {
187 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribSourceControlHistoryTitleMenu.d.ts',
188 > },
189 > contribSourceControlInputBoxMenu: {
190 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribSourceControlInputBoxMenu.d.ts',
191 > },
192 > contribSourceControlTitleMenu: {
193 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribSourceControlTitleMenu.d.ts',
194 > },
195 > contribStatusBarItems: {
196 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribStatusBarItems.d.ts',
197 > },
198 > contribViewContainerTitle: {
199 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribViewContainerTitle.d.ts',
200 > },
201 > contribViewsRemote: {
202 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribViewsRemote.d.ts',
203 > },
204 > contribViewsWelcome: {
205 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribViewsWelcome.d.ts',
206 > },
207 > css: {
208 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.css.d.ts',
209 > },
210 > customEditorDiffs: {
211 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.customEditorDiffs.d.ts',
212 > },
213 > customEditorMove: {
214 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.customEditorMove.d.ts',
215 > },
216 > customEditorPriority: {
217 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.customEditorPriority.d.ts',
218 > },
219 > dataChannels: {
220 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.dataChannels.d.ts',
221 > },
222 > debugVisualization: {
223 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.debugVisualization.d.ts',
224 > },
225 > defaultChatParticipant: {
226 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.defaultChatParticipant.d.ts',
227 > },
228 > devDeviceId: {
229 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.devDeviceId.d.ts',
230 > },
231 > diffCommand: {
232 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.diffCommand.d.ts',
233 > },
234 > diffContentOptions: {
235 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.diffContentOptions.d.ts',
236 > },
237 > documentDiff: {
238 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.documentDiff.d.ts',
239 > },
240 > documentFiltersExclusive: {
241 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.documentFiltersExclusive.d.ts',
242 > },
243 > documentSyntaxHighlighting: {
244 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.documentSyntaxHighlighting.d.ts',
245 > },
246 > editSessionIdentityProvider: {
247 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.editSessionIdentityProvider.d.ts',
248 > },
249 > editorHoverVerbosityLevel: {
250 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.editorHoverVerbosityLevel.d.ts',
251 > },
252 > editorInsets: {
253 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.editorInsets.d.ts',
254 > },
255 > embeddings: {
256 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.embeddings.d.ts',
257 > },
258 > envIsConnectionMetered: {
259 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.envIsConnectionMetered.d.ts',
260 > },
261 > environmentPower: {
262 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.environmentPower.d.ts',
263 > },
264 > extensionAffinity: {
265 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.extensionAffinity.d.ts',
266 > },
267 > extensionRuntime: {
268 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.extensionRuntime.d.ts',
269 > },
270 > extensionsAny: {
271 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.extensionsAny.d.ts',
272 > },
273 > externalUriOpener: {
274 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.externalUriOpener.d.ts',
275 > },
276 > fileSearchProvider: {
277 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.fileSearchProvider.d.ts',
278 > },
279 > fileSearchProvider2: {
280 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.fileSearchProvider2.d.ts',
281 > },
282 > findFiles2: {
283 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.findFiles2.d.ts',
284 > },
285 > findTextInFiles: {
286 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.findTextInFiles.d.ts',
287 > },
288 > findTextInFiles2: {
289 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.findTextInFiles2.d.ts',
290 > },
291 > fsChunks: {
292 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.fsChunks.d.ts',
293 > },
294 > inlineCompletionsAdditions: {
295 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.inlineCompletionsAdditions.d.ts',
296 > },
297 > interactive: {
298 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.interactive.d.ts',
299 > },
300 > interactiveWindow: {
301 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.interactiveWindow.d.ts',
302 > },
303 > ipc: {
304 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.ipc.d.ts',
305 > },
306 > languageModelCapabilities: {
307 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.languageModelCapabilities.d.ts',
308 > },
309 > languageModelPricing: {
310 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.languageModelPricing.d.ts',
311 > },
312 > languageModelProxy: {
313 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.languageModelProxy.d.ts',
314 > },
315 > languageModelSystem: {
316 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.languageModelSystem.d.ts',
317 > },
318 > languageModelThinkingPart: {
319 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.languageModelThinkingPart.d.ts',
320 > },
321 > languageModelToolResultAudience: {
322 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.languageModelToolResultAudience.d.ts',
323 > },
324 > languageModelToolSupportsModel: {
325 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.languageModelToolSupportsModel.d.ts',
326 > },
327 > languageStatusText: {
328 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.languageStatusText.d.ts',
329 > },
330 > mappedEditsProvider: {
331 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.mappedEditsProvider.d.ts',
332 > },
333 > markdownAlertSyntax: {
334 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.markdownAlertSyntax.d.ts',
335 > },
336 > mcpServerDefinitions: {
337 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.mcpServerDefinitions.d.ts',
338 > },
339 > mcpToolDefinitions: {
340 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.mcpToolDefinitions.d.ts',
341 > },
342 > multiDocumentHighlightProvider: {
343 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.multiDocumentHighlightProvider.d.ts',
344 > },
345 > nativeWindowHandle: {
346 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.nativeWindowHandle.d.ts',
347 > },
348 > newSymbolNamesProvider: {
349 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.newSymbolNamesProvider.d.ts',
350 > },
351 > notebookCellExecution: {
352 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.notebookCellExecution.d.ts',
353 > },
354 > notebookControllerAffinityHidden: {
355 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.notebookControllerAffinityHidden.d.ts',
356 > },
357 > notebookDeprecated: {
358 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.notebookDeprecated.d.ts',
359 > },
360 > notebookExecution: {
361 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.notebookExecution.d.ts',
362 > },
363 > notebookKernelSource: {
364 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.notebookKernelSource.d.ts',
365 > },
366 > notebookLiveShare: {
367 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.notebookLiveShare.d.ts',
368 > },
369 > notebookMessaging: {
370 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.notebookMessaging.d.ts',
371 > },
372 > notebookMime: {
373 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.notebookMime.d.ts',
374 > },
375 > notebookReplDocument: {
376 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.notebookReplDocument.d.ts',
377 > },
378 > notebookVariableProvider: {
379 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.notebookVariableProvider.d.ts',
380 > },
381 > portsAttributes: {
382 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.portsAttributes.d.ts',
383 > },
384 > profileContentHandlers: {
385 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.profileContentHandlers.d.ts',
386 > },
387 > quickDiffProvider: {
388 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.quickDiffProvider.d.ts',
389 > },
390 > quickPickItemTooltip: {
391 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.quickPickItemTooltip.d.ts',
392 > },
393 > quickPickSortByLabel: {
394 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.quickPickSortByLabel.d.ts',
395 > },
396 > remoteCodingAgents: {
397 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.remoteCodingAgents.d.ts',
398 > },
399 > resolvers: {
400 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.resolvers.d.ts',
401 > },
402 > scmActionButton: {
403 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.scmActionButton.d.ts',
404 > },
405 > scmArtifactProvider: {
406 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.scmArtifactProvider.d.ts',
407 > },
408 > scmHistoryProvider: {
409 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.scmHistoryProvider.d.ts',
410 > },
411 > scmMultiDiffEditor: {
412 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.scmMultiDiffEditor.d.ts',
413 > },
414 > scmProviderOptions: {
415 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.scmProviderOptions.d.ts',
416 > },
417 > scmSelectedProvider: {
418 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.scmSelectedProvider.d.ts',
419 > },
420 > scmTextDocument: {
421 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.scmTextDocument.d.ts',
422 > },
423 > scmValidation: {
424 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.scmValidation.d.ts',
425 > },
426 > shareProvider: {
427 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.shareProvider.d.ts',
428 > },
429 > speech: {
430 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.speech.d.ts',
431 > },
432 > statusBarItemTooltip: {
433 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.statusBarItemTooltip.d.ts',
434 > },
435 > tabInputMultiDiff: {
436 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.tabInputMultiDiff.d.ts',
437 > },
438 > tabInputTextMerge: {
439 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.tabInputTextMerge.d.ts',
440 > },
441 > taskExecutionTerminal: {
442 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.taskExecutionTerminal.d.ts',
443 > },
444 > taskPresentationGroup: {
445 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.taskPresentationGroup.d.ts',
446 > },
447 > taskProblemMatcherStatus: {
448 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.taskProblemMatcherStatus.d.ts',
449 > },
450 > taskRunOptions: {
451 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.taskRunOptions.d.ts',
452 > },
453 > telemetry: {
454 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.telemetry.d.ts',
455 > },
456 > terminalCompletionProvider: {
457 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.terminalCompletionProvider.d.ts',
458 > },
459 > terminalDataWriteEvent: {
460 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.terminalDataWriteEvent.d.ts',
461 > },
462 > terminalDimensions: {
463 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.terminalDimensions.d.ts',
464 > },
465 > terminalExecuteCommandEvent: {
466 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.terminalExecuteCommandEvent.d.ts',
467 > },
468 > terminalQuickFixProvider: {
469 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.terminalQuickFixProvider.d.ts',
470 > },
471 > terminalSelection: {
472 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.terminalSelection.d.ts',
473 > },
474 > terminalShellEnv: {
475 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.terminalShellEnv.d.ts',
476 > },
477 > terminalTitle: {
478 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.terminalTitle.d.ts',
479 > },
480 > testObserver: {
481 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.testObserver.d.ts',
482 > },
483 > testRelatedCode: {
484 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.testRelatedCode.d.ts',
485 > },
486 > textDocumentChangeReason: {
487 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.textDocumentChangeReason.d.ts',
488 > },
489 > textEditorDiffInformation: {
490 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.textEditorDiffInformation.d.ts',
491 > },
492 > textSearchComplete2: {
493 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.textSearchComplete2.d.ts',
494 > },
495 > textSearchProvider: {
496 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.textSearchProvider.d.ts',
497 > },
498 > textSearchProvider2: {
499 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.textSearchProvider2.d.ts',
500 > },
501 > timeline: {
502 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.timeline.d.ts',
503 > },
504 > tokenInformation: {
505 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.tokenInformation.d.ts',
506 > },
507 > toolInvocationApproveCombination: {
508 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.toolInvocationApproveCombination.d.ts',
509 > },
510 > toolProgress: {
511 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.toolProgress.d.ts',
512 > },
513 > treeItemMarkdownLabel: {
514 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.treeItemMarkdownLabel.d.ts',
515 > },
516 > treeViewActiveItem: {
517 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.treeViewActiveItem.d.ts',
518 > },
519 > treeViewMarkdownMessage: {
520 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.treeViewMarkdownMessage.d.ts',
521 > },
522 > treeViewReveal: {
523 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.treeViewReveal.d.ts',
524 > },
525 > tunnelFactory: {
526 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.tunnelFactory.d.ts',
527 > },
528 > tunnels: {
529 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.tunnels.d.ts',
530 > },
531 > valueSelectionInQuickPick: {
532 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.valueSelectionInQuickPick.d.ts',
533 > },
534 > workspaceTrust: {
535 > proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.workspaceTrust.d.ts',
536 > }
537 > };
538 > export const allApiProposals = Object.freeze<{ [proposalName: string]: Readonly<{ proposal: string }> }>(_allApiProposals);
539 > export type ApiProposalName = keyof typeof _allApiProposals;
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/workbench/services/authentication/common/authentication.ts 507 covered LOC · 4 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- authentication.ts
2 > * Copyright (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 { Event } from '../../../../base/common/event.js';
6 > import { IDisposable } from '../../../../base/common/lifecycle.js';
7 > import { IAuthenticationChallenge, IAuthorizationProtectedResourceMetadata, IAuthorizationServerMetadata } from '../../../../base/common/oauth.js';
8 > import { URI } from '../../../../base/common/uri.js';
9 > import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
10 >
11 > /**
12 > * Use this if you don't want the onDidChangeSessions event to fire in the extension host
13 > */
14 > export const INTERNAL_AUTH_PROVIDER_PREFIX = '__';
15 >
16 > export interface AuthenticationSessionAccount {
17 > label: string;
18 > id: string;
19 > }
20 >
21 > export interface AuthenticationSession {
22 > id: string;
23 > accessToken: string;
24 > account: AuthenticationSessionAccount;
25 > scopes: ReadonlyArray<string>;
26 > idToken?: string;
27 > }
28 >
29 > export interface AuthenticationSessionsChangeEvent {
30 > added: ReadonlyArray<AuthenticationSession> | undefined;
31 > removed: ReadonlyArray<AuthenticationSession> | undefined;
32 > changed: ReadonlyArray<AuthenticationSession> | undefined;
33 > }
34 >
35 > export interface AuthenticationProviderInformation {
36 > id: string;
37 > label: string;
38 > authorizationServerGlobs?: ReadonlyArray<string>;
39 > }
40 >
41 > /**
42 > * Options for creating an authentication session via the service.
43 > */
44 > export interface IAuthenticationCreateSessionOptions {
45 > activateImmediate?: boolean;
46 > /**
47 > * The account that is being asked about. If this is passed in, the provider should
48 > * attempt to return the sessions that are only related to this account.
49 > */
50 > account?: AuthenticationSessionAccount;
51 > /**
52 > * The authorization server URI to use for this creation request. If passed in, first we validate that
53 > * the provider can use this authorization server, then it is passed down to the auth provider.
54 > */
55 > authorizationServer?: URI;
56 > /**
57 > * When specified, the authentication provider will request a token bound to this resource URI
58 > * (RFC 8707 resource indicator).
59 > */
60 > resource?: string;
61 > /**
62 > * The audience for the requested access token. Primarily used for OAuth Identity Assertion
63 > * Authorization Grant (ID-JAG, defined in `draft-ietf-oauth-identity-assertion-authz-grant` using RFC 8693 token-exchange semantics) flows where the audience identifies the authorization server of the resource that
64 > * will redeem the assertion (typically the resource's authorization server URL). Providers that do not understand audience-bound tokens should
65 > * ignore this option.
66 > */
67 > audience?: string;
68 > /**
69 > * Allows the authentication provider to take in additional parameters.
70 > * It is up to the provider to define what these parameters are and handle them.
71 > * This is useful for passing in additional information that is specific to the provider
72 > * and not part of the standard authentication flow.
73 > */
74 > [key: string]: any;
75 > }
76 >
77 > export interface IAuthenticationWwwAuthenticateRequest {
78 > /**
79 > * The raw WWW-Authenticate header value that triggered this challenge.
80 > * This will be parsed by the authentication provider to extract the necessary
81 > * challenge information.
82 > */
83 > readonly wwwAuthenticate: string;
84 >
85 > /**
86 > * Optional scopes for the session. If not provided, the authentication provider
87 > * may use default scopes or extract them from the challenge.
88 > */
89 > readonly fallbackScopes?: readonly string[];
90 > }
91 >
92 > export function isAuthenticationWwwAuthenticateRequest(obj: unknown): obj is IAuthenticationWwwAuthenticateRequest {
93 return typeof obj === 'object'
94 && obj !== null
96 && (typeof obj.wwwAuthenticate === 'string');
97 }
99 > /**
100 > * Represents constraints for authentication, including challenges and optional scopes.
101 > * This is used when creating or retrieving sessions that must satisfy specific authentication
102 > * requirements from WWW-Authenticate headers.
103 > */
104 > export interface IAuthenticationConstraint {
105 > /**
106 > * Array of authentication challenges parsed from WWW-Authenticate headers.
107 > */
108 > readonly challenges: readonly IAuthenticationChallenge[];
109 >
110 > /**
111 > * Optional scopes for the session. If not provided, the authentication provider
112 > * may extract scopes from the challenges or use default scopes.
113 > */
114 > readonly fallbackScopes?: readonly string[];
115 > }
116 >
117 > /**
118 > * Options for getting authentication sessions via the service.
119 > */
120 > export interface IAuthenticationGetSessionsOptions {
121 > /**
122 > * Whether the provider must avoid user interaction while resolving existing sessions.
123 > */
124 > silent?: boolean;
125 > /**
126 > * The account that is being asked about. If this is passed in, the provider should
127 > * attempt to return the sessions that are only related to this account.
128 > */
129 > account?: AuthenticationSessionAccount;
130 > /**
131 > * The authorization server URI to use for this request. If passed in, first we validate that
132 > * the provider can use this authorization server, then it is passed down to the auth provider.
133 > */
134 > authorizationServer?: URI;
135 > /**
136 > * When specified, the authentication provider will request a token bound to this resource URI
137 > * (RFC 8707 resource indicator).
138 > */
139 > resource?: string;
140 > /**
141 > * The audience for the requested access token. Primarily used for OAuth Identity Assertion
142 > * Authorization Grant (ID-JAG, defined in `draft-ietf-oauth-identity-assertion-authz-grant` using RFC 8693 token-exchange semantics) flows where the audience identifies the authorization server of the resource that
143 > * will redeem the assertion (typically the resource's authorization server URL). Providers that do not understand audience-bound tokens should
144 > * ignore this option.
145 > */
146 > audience?: string;
147 > /**
148 > * Allows the authentication provider to take in additional parameters.
149 > * It is up to the provider to define what these parameters are and handle them.
150 > * This is useful for passing in additional information that is specific to the provider
151 > * and not part of the standard authentication flow.
152 > */
153 > [key: string]: any;
154 > }
155 >
156 > export interface AllowedExtension {
157 > id: string;
158 > name: string;
159 > /**
160 > * If true or undefined, the extension is allowed to use the account
161 > * If false, the extension is not allowed to use the account
162 > * TODO: undefined shouldn't be a valid value, but it is for now
163 > */
164 > allowed?: boolean;
165 > lastUsed?: number;
166 > // If true, this comes from the product.json
167 > trusted?: boolean;
168 > }
169 >
170 > export interface IAuthenticationProviderHostDelegate {
171 > /** Priority for this delegate, delegates are tested in descending priority order */
172 > readonly priority: number;
173 > create(authorizationServer: URI, serverMetadata: IAuthorizationServerMetadata, resource: IAuthorizationProtectedResourceMetadata | undefined, clientId?: string, clientSecret?: string): Promise<string>;
174 > /**
175 > * Creates an XAA (enterprise-managed, ID-JAG) authentication provider for the given SSO issuer.
176 > * The returned string is the provider id.
177 > */
178 > createXaa?(issuer: URI): Promise<string>;
179 > }
180 >
181 > export function getDynamicAuthenticationProviderId(authorizationServer: URI, resource: IAuthorizationProtectedResourceMetadata | undefined): string {
182 return resource ? `${authorizationServer.toString(true)} ${resource.resource}` : authorizationServer.toString(true);
183 }
185 > export const IAuthenticationService = createDecorator<IAuthenticationService>('IAuthenticationService');
186 >
187 > export interface IAuthenticationService {
188 > readonly _serviceBrand: undefined;
189 >
190 > /**
191 > * Fires when an authentication provider has been registered
192 > */
193 > readonly onDidRegisterAuthenticationProvider: Event<AuthenticationProviderInformation>;
194 > /**
195 > * Fires when an authentication provider has been unregistered
196 > */
197 > readonly onDidUnregisterAuthenticationProvider: Event<AuthenticationProviderInformation>;
198 >
199 > /**
200 > * Fires when the list of sessions for a provider has been added, removed or changed
201 > */
202 > readonly onDidChangeSessions: Event<{ providerId: string; label: string; event: AuthenticationSessionsChangeEvent }>;
203 >
204 > /**
205 > * Fires when the list of declaredProviders has changed
206 > */
207 > readonly onDidChangeDeclaredProviders: Event<void>;
208 >
209 > /**
210 > * All providers that have been statically declared by extensions. These may not actually be registered or active yet.
211 > */
212 > readonly declaredProviders: AuthenticationProviderInformation[];
213 >
214 > /**
215 > * Registers that an extension has declared an authentication provider in their package.json
216 > * @param provider The provider information to register
217 > */
218 > registerDeclaredAuthenticationProvider(provider: AuthenticationProviderInformation): void;
219 >
220 > /**
221 > * Unregisters a declared authentication provider
222 > * @param id The id of the provider to unregister
223 > */
224 > unregisterDeclaredAuthenticationProvider(id: string): void;
225 >
226 > /**
227 > * Checks if an authentication provider has been registered
228 > * @param id The id of the provider to check
229 > */
230 > isAuthenticationProviderRegistered(id: string): boolean;
231 >
232 > /**
233 > * Checks if an authentication provider is dynamic
234 > * @param id The id of the provider to check
235 > */
236 > isDynamicAuthenticationProvider(id: string): boolean;
237 >
238 > /**
239 > * Registers an authentication provider
240 > * @param id The id of the provider
241 > * @param provider The implementation of the provider
242 > */
243 > registerAuthenticationProvider(id: string, provider: IAuthenticationProvider): void;
244 >
245 > /**
246 > * Unregisters an authentication provider
247 > * @param id The id of the provider to unregister
248 > */
249 > unregisterAuthenticationProvider(id: string): void;
250 >
251 > /**
252 > * Gets the provider ids of all registered authentication providers
253 > */
254 > getProviderIds(): string[];
255 >
256 > /**
257 > * Gets the provider with the given id.
258 > * @param id The id of the provider to get
259 > * @throws if the provider is not registered
260 > */
261 > getProvider(id: string): IAuthenticationProvider;
262 >
263 > /**
264 > * Gets all accounts that are currently logged in across all sessions
265 > * @param id The id of the provider to ask for accounts
266 > * @returns A promise that resolves to an array of accounts
267 > */
268 > getAccounts(id: string): Promise<ReadonlyArray<AuthenticationSessionAccount>>;
269 >
270 > /**
271 > * Gets all sessions that satisfy the given scopes from the provider with the given id
272 > * @param id The id of the provider to ask for a session
273 > * @param scopes The scopes for the session
274 > * @param options Additional options for getting sessions
275 > * @param activateImmediate If true, the provider should activate immediately if it is not already
276 > */
277 > getSessions(id: string, scopeListOrRequest?: ReadonlyArray<string> | IAuthenticationWwwAuthenticateRequest, options?: IAuthenticationGetSessionsOptions, activateImmediate?: boolean): Promise<ReadonlyArray<AuthenticationSession>>;
278 >
279 > /**
280 > * Creates an AuthenticationSession with the given provider and scopes
281 > * @param providerId The id of the provider
282 > * @param scopes The scopes to request
283 > * @param options Additional options for creating the session
284 > */
285 > createSession(providerId: string, scopeListOrRequest: ReadonlyArray<string> | IAuthenticationWwwAuthenticateRequest, options?: IAuthenticationCreateSessionOptions): Promise<AuthenticationSession>;
286 >
287 > /**
288 > * Removes the session with the given id from the provider with the given id
289 > * @param providerId The id of the provider
290 > * @param sessionId The id of the session to remove
291 > */
292 > removeSession(providerId: string, sessionId: string): Promise<void>;
293 >
294 > /**
295 > * Gets a provider id for a specified authorization server
296 > * @param authorizationServer The authorization server url that this provider is responsible for
297 > * @param resourceServer The resource server URI that should match the provider's resourceServer (if defined)
298 > */
299 > getOrActivateProviderIdForServer(authorizationServer: URI, resourceServer?: URI): Promise<string | undefined>;
300 >
301 > /**
302 > * Allows the ability register a delegate that will be used to start authentication providers
303 > * @param delegate The delegate to register
304 > */
305 > registerAuthenticationProviderHostDelegate(delegate: IAuthenticationProviderHostDelegate): IDisposable;
306 >
307 > /**
308 > * Creates a dynamic authentication provider for the given server metadata
309 > * @param serverMetadata The metadata for the server that is being authenticated against
310 > */
311 > createDynamicAuthenticationProvider(authorizationServer: URI, serverMetadata: IAuthorizationServerMetadata, resourceMetadata: IAuthorizationProtectedResourceMetadata | undefined, clientId?: string, clientSecret?: string): Promise<IAuthenticationProvider | undefined>;
312 >
313 > /**
314 > * Gets or creates a built-in XAA (enterprise-managed, ID-JAG) authentication provider for the given
315 > * SSO issuer. Subsequent calls with the same issuer return the existing provider. The returned id
316 > * can be used with {@link getSessions}/{@link createSession} just like any other provider.
317 > *
318 > * @param issuer The OAuth/OIDC issuer URL (typically read from `mcp.enterpriseManagedAuth.idp`).
319 > */
320 > createOrGetXaaProvider(issuer: URI): Promise<string | undefined>;
321 > }
322 >
323 > export function isAuthenticationSession(thing: unknown): thing is AuthenticationSession {
324 if (typeof thing !== 'object' || !thing) {
325 return false;
349 return true;
350 }
352 > // TODO: Move this into MainThreadAuthentication
353 > export const IAuthenticationExtensionsService = createDecorator<IAuthenticationExtensionsService>('IAuthenticationExtensionsService');
354 > export interface IAuthenticationExtensionsService {
355 > readonly _serviceBrand: undefined;
356 >
357 > /**
358 > * Fires when an account preference for a specific provider has changed for the specified extensions. Does not fire when:
359 > * * An account preference is removed
360 > * * A session preference is changed (because it's deprecated)
361 > * * A session preference is removed (because it's deprecated)
362 > */
363 > readonly onDidChangeAccountPreference: Event<{ extensionIds: string[]; providerId: string }>;
364 > /**
365 > * Returns the accountName (also known as account.label) to pair with `IAuthenticationAccessService` to get the account preference
366 > * @param providerId The authentication provider id
367 > * @param extensionId The extension id to get the preference for
368 > * @returns The accountName of the preference, or undefined if there is no preference set
369 > */
370 > getAccountPreference(extensionId: string, providerId: string): string | undefined;
371 > /**
372 > * Sets the account preference for the given provider and extension
373 > * @param providerId The authentication provider id
374 > * @param extensionId The extension id to set the preference for
375 > * @param account The account to set the preference to
376 > */
377 > updateAccountPreference(extensionId: string, providerId: string, account: AuthenticationSessionAccount): void;
378 > /**
379 > * Removes the account preference for the given provider and extension
380 > * @param providerId The authentication provider id
381 > * @param extensionId The extension id to remove the preference for
382 > */
383 > removeAccountPreference(extensionId: string, providerId: string): void;
384 > /**
385 > * @deprecated Sets the session preference for the given provider and extension
386 > * @param providerId
387 > * @param extensionId
388 > * @param session
389 > */
390 > updateSessionPreference(providerId: string, extensionId: string, session: AuthenticationSession): void;
391 > /**
392 > * @deprecated Gets the session preference for the given provider and extension
393 > * @param providerId
394 > * @param extensionId
395 > * @param scopes
396 > */
397 > getSessionPreference(providerId: string, extensionId: string, scopes: string[]): string | undefined;
398 > /**
399 > * @deprecated Removes the session preference for the given provider and extension
400 > * @param providerId
401 > * @param extensionId
402 > * @param scopes
403 > */
404 > removeSessionPreference(providerId: string, extensionId: string, scopes: string[]): void;
405 > selectSession(providerId: string, extensionId: string, extensionName: string, scopeListOrRequest: ReadonlyArray<string> | IAuthenticationWwwAuthenticateRequest, possibleSessions: readonly AuthenticationSession[]): Promise<AuthenticationSession>;
406 > requestSessionAccess(providerId: string, extensionId: string, extensionName: string, scopeListOrRequest: ReadonlyArray<string> | IAuthenticationWwwAuthenticateRequest, possibleSessions: readonly AuthenticationSession[]): void;
407 > requestNewSession(providerId: string, scopeListOrRequest: ReadonlyArray<string> | IAuthenticationWwwAuthenticateRequest, extensionId: string, extensionName: string): Promise<void>;
408 > updateNewSessionRequests(providerId: string, addedSessions: readonly AuthenticationSession[]): void;
409 > }
410 >
411 > /**
412 > * Options passed to the authentication provider when asking for sessions.
413 > */
414 > export interface IAuthenticationProviderSessionOptions {
415 > /**
416 > * Whether the provider must avoid user interaction while resolving existing sessions.
417 > */
418 > silent?: boolean;
419 > /**
420 > * The account that is being asked about. If this is passed in, the provider should
421 > * attempt to return the sessions that are only related to this account.
422 > */
423 > account?: AuthenticationSessionAccount;
424 > /**
425 > * The authorization server that is being asked about. If this is passed in, the provider should
426 > * attempt to return sessions that are only related to this authorization server.
427 > */
428 > authorizationServer?: URI;
429 > /**
430 > * When specified, the authentication provider will request a token bound to this resource URI
431 > * (RFC 8707 resource indicator).
432 > */
433 > resource?: string;
434 > /**
435 > * The audience for the requested access token. Primarily used for OAuth Identity Assertion
436 > * Authorization Grant (ID-JAG, defined in `draft-ietf-oauth-identity-assertion-authz-grant` using RFC 8693 token-exchange semantics) flows where the audience identifies the authorization server of the resource that
437 > * will redeem the assertion (typically the resource's authorization server URL). Providers that do not understand audience-bound tokens should
438 > * ignore this option.
439 > */
440 > audience?: string;
441 > /**
442 > * Allows the authentication provider to take in additional parameters.
443 > * It is up to the provider to define what these parameters are and handle them.
444 > * This is useful for passing in additional information that is specific to the provider
445 > * and not part of the standard authentication flow.
446 > */
447 > [key: string]: any;
448 > }
449 >
450 > /**
451 > * Represents an authentication provider.
452 > */
453 > export interface IAuthenticationProvider {
454 > /**
455 > * The unique identifier of the authentication provider.
456 > */
457 > readonly id: string;
458 >
459 > /**
460 > * The display label of the authentication provider.
461 > */
462 > readonly label: string;
463 >
464 > /**
465 > * The resource server URI that this provider is responsible for, if any.
466 > * TODO@TylerLeonhardt: Rather than this being added to the provider, it should be passed in to
467 > * getSessions/createSession/etc... this way we can have providers that handle multiple resource servers.
468 > */
469 > readonly resourceServer?: URI;
470 >
471 > /**
472 > * The resolved authorization servers. These can still contain globs, but should be concrete URIs
473 > */
474 > readonly authorizationServers?: ReadonlyArray<URI>;
475 >
476 > /**
477 > * Indicates whether the authentication provider supports multiple accounts.
478 > */
479 > readonly supportsMultipleAccounts: boolean;
480 >
481 > /**
482 > * Optional function to provide a custom confirmation message for authentication prompts.
483 > * If not implemented, the default confirmation messages will be used.
484 > * @param extensionName - The name of the extension requesting authentication.
485 > * @param recreatingSession - Whether this is recreating an existing session.
486 > * @returns A custom confirmation message or undefined to use the default message.
487 > */
488 > readonly confirmation?: (extensionName: string, recreatingSession: boolean) => string | undefined;
489 >
490 > /**
491 > * An {@link Event} which fires when the array of sessions has changed, or data
492 > * within a session has changed.
493 > */
494 > readonly onDidChangeSessions: Event<AuthenticationSessionsChangeEvent>;
495 >
496 > /**
497 > * Retrieves a list of authentication sessions.
498 > * @param scopes - An optional list of scopes. If provided, the sessions returned should match these permissions, otherwise all sessions should be returned.
499 > * @param options - Additional options for getting sessions.
500 > * @returns A promise that resolves to an array of authentication sessions.
501 > */
502 > getSessions(scopes: string[] | undefined, options: IAuthenticationProviderSessionOptions): Promise<readonly AuthenticationSession[]>;
503 >
504 > /**
505 > * Prompts the user to log in.
506 > * If login is successful, the `onDidChangeSessions` event should be fired.
507 > * If login fails, a rejected promise should be returned.
508 > * If the provider does not support multiple accounts, this method should not be called if there is already an existing session matching the provided scopes.
509 > * @param scopes - A list of scopes that the new session should be created with.
510 > * @param options - Additional options for creating the session.
511 > * @returns A promise that resolves to an authentication session.
512 > */
513 > createSession(scopes: string[], options: IAuthenticationProviderSessionOptions): Promise<AuthenticationSession>;
514 >
515 > /**
516 > * Get existing sessions that match the given authentication constraints.
517 > *
518 > * @param constraint The authentication constraint containing challenges and optional scopes
519 > * @param options Options for the session request
520 > * @returns A thenable that resolves to an array of existing authentication sessions
521 > */
522 > getSessionsFromChallenges?(constraint: IAuthenticationConstraint, options: IAuthenticationProviderSessionOptions): Promise<readonly AuthenticationSession[]>;
523 >
524 > /**
525 > * Create a new session based on authentication constraints.
526 > * This is called when no existing session matches the constraint requirements.
527 > *
528 > * @param constraint The authentication constraint containing challenges and optional scopes
529 > * @param options Options for the session creation
530 > * @returns A thenable that resolves to a new authentication session
531 > */
532 > createSessionFromChallenges?(constraint: IAuthenticationConstraint, options: IAuthenticationProviderSessionOptions): Promise<AuthenticationSession>;
533 >
534 > /**
535 > * Removes the session corresponding to the specified session ID.
536 > * If the removal is successful, the `onDidChangeSessions` event should be fired.
537 > * If a session cannot be removed, the provider should reject with an error message.
538 > * @param sessionId - The ID of the session to remove.
539 > */
540 > removeSession(sessionId: string): Promise<void>;
541 > }
src/vs/workbench/contrib/chat/common/attachments/chatVariableEntries.ts 506 covered LOC · 54 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- chatVariableEntries.ts
2 > * Copyright (c) Microsoft 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 { IMarkdownString } from '../../../../../base/common/htmlContent.js';
8 > import { basename } from '../../../../../base/common/resources.js';
9 > import { ThemeIcon } from '../../../../../base/common/themables.js';
10 > import { URI } from '../../../../../base/common/uri.js';
11 > import { generateUuid } from '../../../../../base/common/uuid.js';
12 > import { IRange } from '../../../../../editor/common/core/range.js';
13 > import { IOffsetRange } from '../../../../../editor/common/core/ranges/offsetRange.js';
14 > import { isLocation, Location, SymbolKind } from '../../../../../editor/common/languages.js';
15 > import { localize } from '../../../../../nls.js';
16 > import { MarkerSeverity, IMarker } from '../../../../../platform/markers/common/markers.js';
17 > import { ISCMHistoryItem } from '../../../scm/common/history.js';
18 > import { IChatContentReference } from '../chatService/chatService.js';
19 > import { IChatRequestVariableValue } from './chatVariables.js';
20 > import { IToolData, IToolSet } from '../tools/languageModelToolsService.js';
21 > import type { ILanguageModelChatMetadata } from '../languageModels.js';
22 > import { decodeBase64, encodeBase64, VSBuffer } from '../../../../../base/common/buffer.js';
23 > import { Mutable } from '../../../../../base/common/types.js';
24 >
25 >
26 > /**
27 > * An icon for a chat context item. Mirrors the `IconPath` type from the extension API:
28 > * either a {@link ThemeIcon theme icon}, a single {@link URI} or separate light/dark {@link URI uris}.
29 > */
30 > export type ChatContextIconPath = ThemeIcon | URI | { light: URI; dark: URI };
31 >
32 > /**
33 > * Type guard for {@link ChatContextIconPath}. Accepts a {@link ThemeIcon theme icon}, a single
34 > * {@link URI} or an object with both `light` and `dark` {@link URI uris}. Rejects `null`, `undefined`
35 > * and partially-specified light/dark objects.
36 > */
37 > export function isChatContextIconPath(value: unknown): value is ChatContextIconPath {
38 if (!value || typeof value !== 'object') {
39 return false;
45 return URI.isUri(asDualPath.light) && URI.isUri(asDualPath.dark);
46 }
48 > /**
49 > * Resolve a {@link ChatContextIconPath} into a value that can be passed to the `iconPath`
50 > * option of an icon label, picking the light or dark uri based on the current theme.
51 > *
52 > * @param iconPath The icon path to resolve.
53 > * @param useDark Whether the current theme is a dark theme.
54 > */
55 > export function resolveChatContextIcon(iconPath: ChatContextIconPath, useDark: boolean): ThemeIcon | URI {
56 if (ThemeIcon.isThemeIcon(iconPath) || URI.isUri(iconPath)) {
57 return iconPath;
59 return useDark ? iconPath.dark : iconPath.light;
60 }
62 > interface IBaseChatRequestVariableEntry {
63 > readonly id: string;
64 > readonly fullName?: string;
65 > readonly icon?: ThemeIcon;
66 > readonly name: string;
67 > readonly modelDescription?: string;
68 >
69 > /**
70 > * The offset-range in the prompt. This means this entry has been explicitly typed out
71 > * by the user.
72 > */
73 > readonly range?: IOffsetRange;
74 > readonly value: IChatRequestVariableValue;
75 > readonly references?: IChatContentReference[];
76 >
77 > /**
78 > * Implementation-defined metadata that providers attach to a variable
79 > * entry. Used to round-trip provider-specific data (e.g. agent-host
80 > * `_meta`) when an entry is sent back to the provider as part of a
81 > * request attachment.
82 > */
83 > readonly _meta?: Record<string, unknown>;
84 >
85 > omittedState?: OmittedState;
86 > }
87 >
88 > export interface IGenericChatRequestVariableEntry extends IBaseChatRequestVariableEntry {
89 > kind: 'generic';
90 > tooltip?: IMarkdownString;
91 > /**
92 > * A provider-supplied icon that may be a {@link ThemeIcon theme icon}, a single uri or light/dark uris.
93 > * Takes precedence over the {@link IBaseChatRequestVariableEntry.icon base theme icon} when rendering.
94 > */
95 > iconPath?: ChatContextIconPath;
96 > }
97 >
98 > export const ChatPasteAttachmentMetadata = {
99 > Kind: 'vscode.chat.attachment.kind',
100 > Language: 'vscode.chat.attachment.language',
101 > FileName: 'vscode.chat.attachment.fileName',
102 > PastedLines: 'vscode.chat.attachment.pastedLines',
103 > } as const;
104 >
105 > export interface IRestorablePasteAttachment {
106 > readonly label: string;
107 > readonly displayKind?: string;
108 > readonly modelRepresentation?: string;
109 > readonly _meta?: Record<string, unknown>;
110 > }
111 >
112 > export const enum AgentHostCompletionReferenceKind {
113 > Skill = 'skill',
114 > Command = 'command',
115 > }
116 >
117 > export interface IAgentHostCompletionVariableValue {
118 > readonly $mid: 'agentHostCompletion';
119 > readonly kind: AgentHostCompletionReferenceKind;
120 > }
121 >
122 function agentHostCompletionVariableValue(kind: AgentHostCompletionReferenceKind): IAgentHostCompletionVariableValue {
123 return { $mid: 'agentHostCompletion', kind };
124 }
126 function agentHostCompletionVariableId(kind: AgentHostCompletionReferenceKind, reference: URI | string): string {
127 switch (kind) {
132 }
133 }
135 > export function toAgentHostCompletionVariableEntry(kind: AgentHostCompletionReferenceKind, name: string, reference: URI | string | undefined, _meta: Record<string, unknown> | undefined): IGenericChatRequestVariableEntry & { value: IAgentHostCompletionVariableValue } {
136 return {
137 kind: 'generic',
142 };
143 }
145 > export function toAgentHostCompletionVariableEntryFromMetadata(kind: AgentHostCompletionReferenceKind, name: string, _meta: Record<string, unknown> | undefined): IGenericChatRequestVariableEntry & { value: IAgentHostCompletionVariableValue } {
146 switch (kind) {
147 case AgentHostCompletionReferenceKind.Skill:
151 }
152 }
154 > export function getAgentHostCompletionReferenceKind(entry: IChatRequestVariableEntry): AgentHostCompletionReferenceKind | undefined {
155 if (entry.kind !== 'generic') {
156 return undefined;
158 return getAgentHostCompletionReferenceKindFromValue(entry.value);
159 }
161 > export function getAgentHostCompletionReferenceKindFromValue(value: IChatRequestVariableValue): AgentHostCompletionReferenceKind | undefined {
162 if (typeof value !== 'object' || value === null) {
163 return undefined;
176 return undefined;
177 }
179 > export function isAgentHostCompletionVariableEntry(entry: IChatRequestVariableEntry): entry is IGenericChatRequestVariableEntry & { value: IAgentHostCompletionVariableValue } {
180 return getAgentHostCompletionReferenceKind(entry) !== undefined;
181 }
183 >
184 > export interface IChatRequestDirectoryEntry extends IBaseChatRequestVariableEntry {
185 > kind: 'directory';
186 > imageCount?: number;
187 > }
188 >
189 > export interface IChatRequestFileEntry extends IBaseChatRequestVariableEntry {
190 > kind: 'file';
191 > }
192 >
193 > export const enum OmittedState {
194 > NotOmitted,
195 > Partial,
196 > Full,
197 > ImageLimitExceeded,
198 > }
199 >
200 > const CLAUDE_MESSAGES_MAX_IMAGES_PER_REQUEST = 20;
201 > const GEMINI_MAX_IMAGES_PER_REQUEST = 10;
202 >
203 > /**
204 > * Returns the image-attachment limit for the selected model.
205 > *
206 > * Claude-family models use a max of 20 (Messages API), Gemini-family models use
207 > * a max of 10. Other models do not have a UI-enforced image count limit.
208 > */
209 > export function getImageAttachmentLimit(model: Pick<ILanguageModelChatMetadata, 'family'> | undefined): number | undefined {
210 if (!model) {
211 return undefined;
223 return undefined;
224 }
226 > export interface IChatRequestToolEntry extends IBaseChatRequestVariableEntry {
227 > readonly kind: 'tool';
228 > }
229 >
230 > export interface IChatRequestToolSetEntry extends IBaseChatRequestVariableEntry {
231 > readonly kind: 'toolset';
232 > readonly value: IChatRequestToolEntry[];
233 > }
234 >
235 > export type ChatRequestToolReferenceEntry = IChatRequestToolEntry | IChatRequestToolSetEntry;
236 >
237 > export interface StringChatContextValue {
238 > value?: string;
239 > name?: string;
240 > modelDescription?: string;
241 > iconPath?: ChatContextIconPath;
242 > uri: URI;
243 > resourceUri?: URI;
244 > tooltip?: IMarkdownString;
245 > /**
246 > * Command ID to execute when this context item is clicked.
247 > */
248 > readonly commandId?: string;
249 > readonly handle: number;
250 > }
251 >
252 > export interface IChatRequestImplicitVariableEntry extends IBaseChatRequestVariableEntry {
253 > readonly kind: 'implicit';
254 > readonly isFile: true;
255 > readonly value: URI | Location | StringChatContextValue | undefined;
256 > readonly uri: URI | undefined;
257 > readonly isSelection: boolean;
258 > enabled: boolean;
259 > }
260 >
261 > export interface IChatRequestStringVariableEntry extends IBaseChatRequestVariableEntry {
262 > readonly kind: 'string';
263 > readonly value: string | undefined;
264 > readonly modelDescription?: string;
265 > readonly iconPath?: ChatContextIconPath;
266 > readonly uri: URI;
267 > readonly resourceUri?: URI;
268 > readonly tooltip?: IMarkdownString;
269 > /**
270 > * Command ID to execute when this context item is clicked.
271 > */
272 > readonly commandId?: string;
273 > readonly handle: number;
274 > }
275 >
276 > export interface IChatRequestWorkspaceVariableEntry extends IBaseChatRequestVariableEntry {
277 > readonly kind: 'workspace';
278 > readonly value: string;
279 > readonly modelDescription?: string;
280 > }
281 >
282 >
283 > export interface IChatRequestPasteVariableEntry extends IBaseChatRequestVariableEntry {
284 > readonly kind: 'paste';
285 > readonly code: string;
286 > readonly language: string;
287 > readonly pastedLines: string;
288 >
289 > // This is only used for old serialized data and should be removed once we no longer support it
290 > readonly fileName: string;
291 >
292 > // This is only undefined on old serialized data
293 > readonly copiedFrom: {
294 > readonly uri: URI;
295 > readonly range: IRange;
296 > } | undefined;
297 > }
298 >
299 > export function toPasteVariableEntry(
300 name: string,
301 code: string,
332 };
333 }
335 > export function restorePasteVariableEntryFromAttachment(attachment: IRestorablePasteAttachment): IChatRequestPasteVariableEntry | undefined {
336 const modelRepresentation = attachment.modelRepresentation;
337 if (typeof modelRepresentation !== 'string' || attachment._meta?.[ChatPasteAttachmentMetadata.Kind] !== 'paste') {
350 });
351 }
353 > export interface ISymbolVariableEntry extends IBaseChatRequestVariableEntry {
354 > readonly kind: 'symbol';
355 > readonly value: Location;
356 > readonly symbolKind: SymbolKind;
357 > }
358 >
359 > export interface ICommandResultVariableEntry extends IBaseChatRequestVariableEntry {
360 > readonly kind: 'command';
361 > }
362 >
363 > export interface IImageVariableEntry extends IBaseChatRequestVariableEntry {
364 > readonly kind: 'image';
365 > readonly isPasted?: boolean;
366 > readonly isURL?: boolean;
367 > readonly mimeType?: string;
368 > }
369 >
370 > export interface INotebookOutputVariableEntry extends IBaseChatRequestVariableEntry {
371 > readonly kind: 'notebookOutput';
372 > readonly outputIndex?: number;
373 > readonly mimeType?: string;
374 > }
375 >
376 > export interface IDiagnosticVariableEntryFilterData {
377 > readonly owner?: string;
378 > readonly problemMessage?: string;
379 > readonly filterUri?: URI;
380 > readonly filterSeverity?: MarkerSeverity;
381 > readonly filterRange?: IRange;
382 > }
383 >
384 >
385 >
386 > export namespace IDiagnosticVariableEntryFilterData {
387 > export const icon = Codicon.error;
388 >
389 > export function fromMarker(marker: IMarker): IDiagnosticVariableEntryFilterData {
390 return {
391 filterUri: marker.resource,
395 };
396 }
398 > export function toEntry(data: IDiagnosticVariableEntryFilterData): IDiagnosticVariableEntry {
399 return {
400 id: id(data),
406 };
407 }
409 > export function id(data: IDiagnosticVariableEntryFilterData) {
410 return [data.filterUri, data.owner, data.filterSeverity, data.filterRange?.startLineNumber, data.filterRange?.startColumn].join(':');
411 }
413 > export function label(data: IDiagnosticVariableEntryFilterData) {
414 const enum TrimThreshold {
415 MaxChars = 30,
436 return labelStr;
437 }
439 >
440 > export interface IDiagnosticVariableEntry extends IBaseChatRequestVariableEntry, IDiagnosticVariableEntryFilterData {
441 > readonly kind: 'diagnostic';
442 > }
443 >
444 > export interface IElementAncestorData {
445 > readonly tagName: string;
446 > readonly id?: string;
447 > readonly classNames?: string[];
448 > }
449 >
450 > export interface IElementVariableEntry extends IBaseChatRequestVariableEntry {
451 > readonly kind: 'element';
452 > readonly value: string;
453 > readonly ancestors?: IElementAncestorData[];
454 > readonly attributes?: Record<string, string>;
455 > readonly computedStyles?: Record<string, string>;
456 > readonly dimensions?: { readonly top: number; readonly left: number; readonly width: number; readonly height: number };
457 > readonly innerText?: string;
458 > }
459 >
460 > export interface IPromptFileVariableEntry extends IBaseChatRequestVariableEntry {
461 > readonly kind: 'promptFile';
462 > readonly value: URI;
463 > readonly isRoot: boolean;
464 > readonly originLabel?: string;
465 > readonly modelDescription: string;
466 > readonly automaticallyAdded: boolean;
467 > readonly toolReferences?: readonly ChatRequestToolReferenceEntry[];
468 > }
469 >
470 > export interface IPromptTextVariableEntry extends IBaseChatRequestVariableEntry {
471 > readonly kind: 'promptText';
472 > readonly value: string;
473 > readonly settingId?: string;
474 > readonly modelDescription: string;
475 > readonly automaticallyAdded: boolean;
476 > readonly toolReferences?: readonly ChatRequestToolReferenceEntry[];
477 > }
478 >
479 > export interface ISCMHistoryItemVariableEntry extends IBaseChatRequestVariableEntry {
480 > readonly kind: 'scmHistoryItem';
481 > readonly value: URI;
482 > readonly historyItem: ISCMHistoryItem;
483 > }
484 >
485 > export interface ISCMHistoryItemChangeVariableEntry extends IBaseChatRequestVariableEntry {
486 > readonly kind: 'scmHistoryItemChange';
487 > readonly value: URI;
488 > readonly historyItem: ISCMHistoryItem;
489 > }
490 >
491 > export interface ISCMHistoryItemChangeRangeVariableEntry extends IBaseChatRequestVariableEntry {
492 > readonly kind: 'scmHistoryItemChangeRange';
493 > readonly value: URI;
494 > readonly historyItemChangeStart: {
495 > readonly uri: URI;
496 > readonly historyItem: ISCMHistoryItem;
497 > };
498 > readonly historyItemChangeEnd: {
499 > readonly uri: URI;
500 > readonly historyItem: ISCMHistoryItem;
501 > };
502 > }
503 >
504 > export interface ITerminalVariableEntry extends IBaseChatRequestVariableEntry {
505 > readonly kind: 'terminalCommand';
506 > readonly value: string;
507 > readonly resource: URI;
508 > readonly command: string;
509 > readonly output?: string;
510 > readonly exitCode?: number;
511 > }
512 >
513 > export interface IDebugVariableEntry extends IBaseChatRequestVariableEntry {
514 > readonly kind: 'debugVariable';
515 > readonly value: string;
516 > readonly expression: string;
517 > readonly type?: string;
518 > }
519 >
520 > export interface IAgentFeedbackVariableEntry extends IBaseChatRequestVariableEntry {
521 > readonly kind: 'agentFeedback';
522 > readonly sessionResource: URI;
523 > /**
524 > * The agent-host annotations channel URI that backs these feedback items
525 > * (each item id is an annotation id on this channel). Set only for
526 > * agent-host sessions; used to emit {@link MessageAnnotationsAttachment}s
527 > * referencing the specific comments on the wire.
528 > */
529 > readonly annotationsResource?: URI;
530 > readonly feedbackItems: ReadonlyArray<{
531 > readonly id: string;
532 > readonly text: string;
533 > readonly resourceUri: URI;
534 > readonly range: IRange;
535 > readonly codeSelection?: string;
536 > readonly diffHunks?: string;
537 > /** When this item was converted from a PR review comment, the original thread ID. */
538 > readonly sourcePRReviewCommentId?: string;
539 > /** Additional replies that belong to the same comment thread as {@link text}. */
540 > readonly replies?: readonly string[];
541 > }>;
542 > }
543 >
544 > export interface IChatRequestDebugEventsVariableEntry extends IBaseChatRequestVariableEntry {
545 > readonly kind: 'debugEvents';
546 > /** Timestamp when the debug events were snapshotted. */
547 > readonly snapshotTime: number;
548 > /** The session resource these debug events belong to. */
549 > readonly sessionResource: URI;
550 > }
551 >
552 > export interface IChatRequestSessionReferenceVariableEntry extends IBaseChatRequestVariableEntry {
553 > readonly kind: 'sessionReference';
554 > readonly value: URI;
555 > }
556 >
557 > export interface IBrowserViewVariableEntry extends IBaseChatRequestVariableEntry {
558 > readonly kind: 'browserView';
559 > readonly value: URI;
560 > readonly browserId: string;
561 > }
562 >
563 > export function isBrowserViewVariableEntry(entry: IChatRequestVariableEntry): entry is IBrowserViewVariableEntry {
564 return entry.kind === 'browserView';
565 }
567 > export type IChatRequestVariableEntry = IGenericChatRequestVariableEntry | IChatRequestImplicitVariableEntry | IChatRequestPasteVariableEntry
568 > | ISymbolVariableEntry | ICommandResultVariableEntry | IDiagnosticVariableEntry | IImageVariableEntry
569 > | IChatRequestToolEntry | IChatRequestToolSetEntry
570 > | IChatRequestDirectoryEntry | IChatRequestFileEntry | INotebookOutputVariableEntry | IElementVariableEntry
571 > | IPromptFileVariableEntry | IPromptTextVariableEntry
572 > | ISCMHistoryItemVariableEntry | ISCMHistoryItemChangeVariableEntry | ISCMHistoryItemChangeRangeVariableEntry | ITerminalVariableEntry
573 > | IChatRequestStringVariableEntry | IChatRequestWorkspaceVariableEntry | IDebugVariableEntry | IAgentFeedbackVariableEntry
574 > | IChatRequestDebugEventsVariableEntry | IChatRequestSessionReferenceVariableEntry | IBrowserViewVariableEntry;
575 >
576 > export namespace IChatRequestVariableEntry {
577 >
578 > /**
579 > * Returns URI of the passed variant entry. Return undefined if not found.
580 > */
581 > export function toUri(entry: IChatRequestVariableEntry): URI | undefined {
582 return URI.isUri(entry.value)
583 ? entry.value
586 : undefined;
587 }
589 > export function toExport(v: IChatRequestVariableEntry): IChatRequestVariableEntry {
590 if (v.value instanceof Uint8Array) {
591 // 'dup' here is needed otherwise TS complains about the narrowed `value` in a spread operation
597 return v;
598 }
600 > export function fromExport(v: IChatRequestVariableEntry): IChatRequestVariableEntry {
601 // Old variables format
602 // eslint-disable-next-line local/code-no-in-operator
623 }
624 }
626 >
627 > export function isImplicitVariableEntry(obj: IChatRequestVariableEntry): obj is IChatRequestImplicitVariableEntry {
628 return obj.kind === 'implicit';
629 }
631 > export function isStringVariableEntry(obj: IChatRequestVariableEntry): obj is IChatRequestStringVariableEntry {
632 return obj.kind === 'string';
633 }
635 > export function isTerminalVariableEntry(obj: IChatRequestVariableEntry): obj is ITerminalVariableEntry {
636 return obj.kind === 'terminalCommand';
637 }
639 > export function isDebugVariableEntry(obj: IChatRequestVariableEntry): obj is IDebugVariableEntry {
640 return obj.kind === 'debugVariable';
641 }
643 > export function isAgentFeedbackVariableEntry(obj: IChatRequestVariableEntry): obj is IAgentFeedbackVariableEntry {
644 return obj.kind === 'agentFeedback';
645 }
647 > export function isPasteVariableEntry(obj: IChatRequestVariableEntry): obj is IChatRequestPasteVariableEntry {
648 return obj.kind === 'paste';
649 }
651 > export function isWorkspaceVariableEntry(obj: IChatRequestVariableEntry): obj is IChatRequestWorkspaceVariableEntry {
652 return obj.kind === 'workspace';
653 }
655 > export function isImageVariableEntry(obj: IChatRequestVariableEntry): obj is IImageVariableEntry {
656 return obj.kind === 'image';
657 }
659 > export function isExplicitFileOrImageVariableEntry(obj: IChatRequestVariableEntry): obj is IChatRequestFileEntry | IChatRequestDirectoryEntry | IImageVariableEntry {
660 return obj.kind === 'file' || obj.kind === 'directory' || obj.kind === 'image';
661 }
663 > export function getExplicitFileOrImageAttachmentSummary(entries: readonly IChatRequestVariableEntry[]): string | undefined {
664 const fileOrImageEntries = entries.filter(isExplicitFileOrImageVariableEntry);
665 if (!fileOrImageEntries.length) {
677 : localize('chat.attachmentSummary.file.many', "Attached {0} files", fileOrImageEntries.length);
678 }
680 > export function isNotebookOutputVariableEntry(obj: IChatRequestVariableEntry): obj is INotebookOutputVariableEntry {
681 return obj.kind === 'notebookOutput';
682 }
684 > export function isElementVariableEntry(obj: IChatRequestVariableEntry): obj is IElementVariableEntry {
685 return obj.kind === 'element';
686 }
688 > export function isDiagnosticsVariableEntry(obj: IChatRequestVariableEntry): obj is IDiagnosticVariableEntry {
689 return obj.kind === 'diagnostic';
690 }
692 > export function isChatRequestFileEntry(obj: IChatRequestVariableEntry): obj is IChatRequestFileEntry {
693 return obj.kind === 'file';
694 }
696 > export function isPromptFileVariableEntry(obj: IChatRequestVariableEntry): obj is IPromptFileVariableEntry {
697 return obj.kind === 'promptFile';
698 }
700 > export function isPromptTextVariableEntry(obj: IChatRequestVariableEntry): obj is IPromptTextVariableEntry {
701 return obj.kind === 'promptText';
702 }
704 > export function isChatRequestVariableEntry(obj: unknown): obj is IChatRequestVariableEntry {
705 const entry = obj as IChatRequestVariableEntry;
706 return typeof entry === 'object' &&
709 typeof entry.name === 'string';
710 }
712 > export function isSCMHistoryItemVariableEntry(obj: IChatRequestVariableEntry): obj is ISCMHistoryItemVariableEntry {
713 return obj.kind === 'scmHistoryItem';
714 }
716 > export function isSCMHistoryItemChangeVariableEntry(obj: IChatRequestVariableEntry): obj is ISCMHistoryItemChangeVariableEntry {
717 return obj.kind === 'scmHistoryItemChange';
718 }
720 > export function isSCMHistoryItemChangeRangeVariableEntry(obj: IChatRequestVariableEntry): obj is ISCMHistoryItemChangeRangeVariableEntry {
721 return obj.kind === 'scmHistoryItemChangeRange';
722 }
724 > export function isStringImplicitContextValue(value: unknown): value is StringChatContextValue {
725 const asStringImplicitContextValue = value as Partial<StringChatContextValue>;
726 return (
736 );
737 }
739 > export enum PromptFileVariableKind {
740 > Instruction = 'vscode.instructions.file.root',
741 > InstructionReference = `vscode.instructions.file.reference`,
742 > PromptFile = 'vscode.prompt.file',
743 > }
744 >
745 > /**
746 > * Utility to convert a {@link uri} to a chat variable entry.
747 > * The `id` of the chat variable can be one of the following:
748 > *
749 > * - `vscode.instructions.file.reference__<URI>`: for all non-root prompt instructions references
750 > * - `vscode.instructions.file.root__<URI>`: for *root* prompt instructions references
751 > * - `vscode.prompt.file__<URI>`: for prompt file references
752 > *
753 > * @param uri A resource URI that points to a prompt instructions file.
754 > * @param kind The kind of the prompt file variable entry.
755 > */
756 > export function toPromptFileVariableEntry(uri: URI, kind: PromptFileVariableKind, originLabel?: string, automaticallyAdded = false, toolReferences?: ChatRequestToolReferenceEntry[]): IPromptFileVariableEntry {
757 // `id` for all `prompt files` starts with the well-defined part that the copilot extension(or other chatbot) can rely on
758 return {
768 };
769 }
771 > enum PromptTextVariableKind {
772 > CustomizationsIndex = 'vscode.customizations.index',
773 > }
774 >
775 > export function toPromptTextVariableEntry(content: string, automaticallyAdded = false, toolReferences?: ChatRequestToolReferenceEntry[]): IPromptTextVariableEntry {
776 return {
777 id: PromptTextVariableKind.CustomizationsIndex,
784 };
785 }
787 > export function toFileVariableEntry(uri: URI, range?: IRange): IChatRequestFileEntry {
788 return {
789 kind: 'file',
793 };
794 }
796 > export function toToolVariableEntry(entry: IToolData, range?: IOffsetRange): IChatRequestToolEntry {
797 return {
798 kind: 'tool',
804 };
805 }
807 > export function toToolSetVariableEntry(entry: IToolSet, range?: IOffsetRange): IChatRequestToolSetEntry {
808 return {
809 kind: 'toolset',
815 };
816 }
818 > export class ChatRequestVariableSet {
819 > private _ids = new Set<string>();
820 > private _entries: IChatRequestVariableEntry[] = [];
821 >
822 > constructor(entries?: IChatRequestVariableEntry[]) {
823 if (entries) {
824 this.add(...entries);
825 }
826 }
828 > public add(...entry: IChatRequestVariableEntry[]): void {
829 for (const e of entry) {
830 if (!this._ids.has(e.id)) {
834 }
835 }
837 > public insertFirst(entry: IChatRequestVariableEntry): void {
838 if (!this._ids.has(entry.id)) {
839 this._ids.add(entry.id);
841 }
842 }
844 > public remove(entry: IChatRequestVariableEntry): void {
845 this._ids.delete(entry.id);
846 this._entries = this._entries.filter(e => e.id !== entry.id);
847 }
849 > public has(entry: IChatRequestVariableEntry): boolean {
850 return this._ids.has(entry.id);
851 }
853 > public asArray(): IChatRequestVariableEntry[] {
854 return this._entries.slice(0); // return a copy
855 }
857 > public get length(): number {
858 return this._entries.length;
859 }
src/vs/base/common/lifecycle.ts 505 covered LOC · 109 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- lifecycle.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { compareBy, numberComparator } from './arrays.js';
7 > import { groupBy } from './collections.js';
8 > import { SetMap, ResourceMap } from './map.js';
9 > import { URI } from './uri.js';
10 > import { createSingleCallFunction } from './functional.js';
11 > import { Iterable } from './iterator.js';
12 > import { BugIndicatingError, onUnexpectedError } from './errors.js';
13 >
14 > // #region Disposable Tracking
15 >
16 > /**
17 > * Enables logging of potentially leaked disposables.
18 > *
19 > * A disposable is considered leaked if it is not disposed or not registered as the child of
20 > * another disposable. This tracking is very simple an only works for classes that either
21 > * extend Disposable or use a DisposableStore. This means there are a lot of false positives.
22 > */
23 > const TRACK_DISPOSABLES = false;
24 > let disposableTracker: IDisposableTracker | null = null;
25 >
26 > export interface IDisposableTracker {
27 > /**
28 > * Is called on construction of a disposable.
29 > */
30 > trackDisposable(disposable: IDisposable): void;
31 >
32 > /**
33 > * Is called when a disposable is registered as child of another disposable (e.g. {@link DisposableStore}).
34 > * If parent is `null`, the disposable is removed from its former parent.
35 > */
36 > setParent(child: IDisposable, parent: IDisposable | null): void;
37 >
38 > /**
39 > * Is called after a disposable is disposed.
40 > */
41 > markAsDisposed(disposable: IDisposable): void;
42 >
43 > /**
44 > * Indicates that the given object is a singleton which does not need to be disposed.
45 > */
46 > markAsSingleton(disposable: IDisposable): void;
47 > }
48 >
49 > export class GCBasedDisposableTracker implements IDisposableTracker {
50
51 private readonly _registry = new FinalizationRegistry<string>(heldValue => {
52 console.warn(`[LEAKED DISPOSABLE] ${heldValue}`);
53 });
55 > trackDisposable(disposable: IDisposable): void {
56 const stack = new Error('CREATED via:').stack!;
57 this._registry.register(disposable, stack, disposable);
58 }
60 > setParent(child: IDisposable, parent: IDisposable | null): void {
61 if (parent) {
62 this._registry.unregister(child);
65 }
66 }
68 > markAsDisposed(disposable: IDisposable): void {
69 this._registry.unregister(disposable);
70 }
72 > markAsSingleton(disposable: IDisposable): void {
73 this._registry.unregister(disposable);
74 }
75 > } lifecycle.ts
76 >
77 > export interface DisposableInfo {
78 > value: IDisposable;
79 > source: string | null;
80 > parent: IDisposable | null;
81 > isSingleton: boolean;
82 > idx: number;
83 > }
84 >
85 > export class DisposableTracker implements IDisposableTracker {
86 > private static idx = 0; lifecycle.ts
87 >
88 > private readonly livingDisposables = new Map<IDisposable, DisposableInfo>();
90 > private getDisposableData(d: IDisposable): DisposableInfo {
91 let val = this.livingDisposables.get(d);
92 if (!val) {
96 return val;
97 }
99 > trackDisposable(d: IDisposable): void {
100 const data = this.getDisposableData(d);
101 if (!data.source) {
104 }
105 }
106 > lifecycle.ts
107 > setParent(child: IDisposable, parent: IDisposable | null): void {
108 const data = this.getDisposableData(child);
109 data.parent = parent;
110 }
111 > lifecycle.ts
112 > markAsDisposed(x: IDisposable): void {
113 > this.livingDisposables.delete(x); lifecycle.ts
114 > }
115 > lifecycle.ts
116 > markAsSingleton(disposable: IDisposable): void {
117 this.getDisposableData(disposable).isSingleton = true;
118 }
119 > lifecycle.ts
120 > private getRootParent(data: DisposableInfo, cache: Map<DisposableInfo, DisposableInfo>): DisposableInfo {
121 const cacheValue = cache.get(data);
122 if (cacheValue) {
128 return result;
129 }
130 > lifecycle.ts
131 > getTrackedDisposables(): IDisposable[] {
132 const rootParentCache = new Map<DisposableInfo, DisposableInfo>();
133
138 return leaking;
139 }
140 > lifecycle.ts
141 > computeLeakingDisposables(maxReported = 10, preComputedLeaks?: DisposableInfo[]): { leaks: DisposableInfo[]; details: string } | undefined {
142 > let uncoveredLeakingObjs: DisposableInfo[] | undefined; lifecycle.ts
143 > if (preComputedLeaks) {
144 uncoveredLeakingObjs = preComputedLeaks;
145 > } else { lifecycle.ts
146 > const rootParentCache = new Map<DisposableInfo, DisposableInfo>();
147 >
148 > const leakingObjects = [...this.livingDisposables.values()]
149 > .filter((info) => info.source !== null && !this.getRootParent(info, rootParentCache).isSingleton);
150 >
151 > if (leakingObjects.length === 0) {
152 > return; lifecycle.ts
153 > }
154 const leakingObjsSet = new Set(leakingObjects.map(o => o.value));
155
162 throw new Error('There are cyclic diposable chains!');
163 }
164 > } lifecycle.ts
165
166 if (!uncoveredLeakingObjs) {
224
225 return { leaks: uncoveredLeakingObjs, details: message };
226 > } lifecycle.ts
227 > } lifecycle.ts
228 >
229 > export function setDisposableTracker(tracker: IDisposableTracker | null): void {
230 > disposableTracker = tracker; lifecycle.ts
231 > }
232 > lifecycle.ts
233 > if (TRACK_DISPOSABLES) {
234 const __is_disposable_tracked__ = '__is_disposable_tracked__';
235 setDisposableTracker(new class implements IDisposableTracker {
268 });
269 }
270 > lifecycle.ts
271 > export function trackDisposable<T extends IDisposable>(x: T): T {
272 > disposableTracker?.trackDisposable(x); lifecycle.ts
273 > return x;
274 > }
275 > lifecycle.ts
276 > export function markAsDisposed(disposable: IDisposable): void {
277 > disposableTracker?.markAsDisposed(disposable); lifecycle.ts
278 > }
279 > lifecycle.ts
280 > function setParentOfDisposable(child: IDisposable, parent: IDisposable | null): void { 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)) {
334 const errors: any[] = [];
356 }
357 }
358 > lifecycle.ts
359 > export function disposeIfDisposable<T extends IDisposable | object>(disposables: Array<T>): Array<T> {
360 for (const d of disposables) {
361 if (isDisposable(d)) {
365 return [];
366 }
367 > lifecycle.ts
368 > /**
369 > * Combine multiple disposable values into a single {@link IDisposable}.
370 > */
371 > export function combinedDisposable(...disposables: IDisposable[]): IDisposable {
372 const parent = toDisposable(() => dispose(disposables));
373 setParentOfDisposables(disposables, parent);
374 return parent;
375 }
376 > lifecycle.ts
377 > class FunctionDisposable implements IDisposable {
378 > private _isDisposed: boolean;
379 > private readonly _fn: () => void;
380 >
381 > constructor(fn: () => void) {
382 > this._isDisposed = false; 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; lifecycle.ts
455 > }
456
457 try {
460 this._toDispose.clear();
461 }
462 > } lifecycle.ts
463 > lifecycle.ts
464 > /**
465 > * Add a new {@link IDisposable disposable} to the collection.
466 > */
467 > public add<T extends IDisposable>(o: T): T {
468 > if (!o || o === Disposable.None) { 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);
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/extensions/common/extensions.ts 486 covered LOC · 25 ranges

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 Severity from '../../../base/common/severity.js';
7 > import * as strings from '../../../base/common/strings.js';
8 > import { URI } from '../../../base/common/uri.js';
9 > import { ILocalizedString } from '../../action/common/action.js';
10 > import { ExtensionKind } from '../../environment/common/environment.js';
11 > import { createDecorator } from '../../instantiation/common/instantiation.js';
12 > import { getRemoteName } from '../../remote/common/remoteHosts.js';
13 >
14 > export const USER_MANIFEST_CACHE_FILE = 'extensions.user.cache';
15 > export const BUILTIN_MANIFEST_CACHE_FILE = 'extensions.builtin.cache';
16 > export const UNDEFINED_PUBLISHER = 'undefined_publisher';
17 >
18 > export interface ICommand {
19 > command: string;
20 > title: string | ILocalizedString;
21 > category?: string | ILocalizedString;
22 > }
23 >
24 > export interface IDebugger {
25 > label?: string;
26 > type: string;
27 > runtime?: string;
28 > }
29 >
30 > export interface IGrammar {
31 > language?: string;
32 > }
33 >
34 > export interface IJSONValidation {
35 > fileMatch: string | string[];
36 > url: string;
37 > }
38 >
39 > export interface IJSONValidationRegistry {
40 > url: string;
41 > }
42 >
43 > export interface IKeyBinding {
44 > command: string;
45 > key: string;
46 > when?: string;
47 > mac?: string;
48 > linux?: string;
49 > win?: string;
50 > }
51 >
52 > export interface ILanguage {
53 > id: string;
54 > extensions: string[];
55 > aliases: string[];
56 > }
57 >
58 > export interface IMenu {
59 > command: string;
60 > alt?: string;
61 > when?: string;
62 > group?: string;
63 > }
64 >
65 > export interface ISnippet {
66 > language: string;
67 > }
68 >
69 > export interface ITheme {
70 > label: string;
71 > }
72 >
73 > export interface IViewContainer {
74 > id: string;
75 > title: string;
76 > }
77 >
78 > export interface IView {
79 > id: string;
80 > name: string;
81 > }
82 >
83 > export interface IColor {
84 > id: string;
85 > description: string;
86 > defaults: { light: string; dark: string; highContrast: string };
87 > }
88 >
89 > interface IWebviewEditor {
90 > readonly viewType: string;
91 > readonly priority: string;
92 > readonly selector: readonly {
93 > readonly filenamePattern?: string;
94 > }[];
95 > }
96 >
97 > export interface ICodeActionContributionAction {
98 > readonly kind: string;
99 > readonly title: string;
100 > readonly description?: string;
101 > }
102 >
103 > export interface ICodeActionContribution {
104 > readonly languages: readonly string[];
105 > readonly actions: readonly ICodeActionContributionAction[];
106 > }
107 >
108 > export interface IAuthenticationContribution {
109 > readonly id: string;
110 > readonly label: string;
111 > readonly authorizationServerGlobs?: string[];
112 > }
113 >
114 > export interface IWalkthroughStep {
115 > readonly id: string;
116 > readonly title: string;
117 > readonly description: string | undefined;
118 > readonly media:
119 > | { image: string | { dark: string; light: string; hc: string }; altText: string; markdown?: never; svg?: never; video?: never }
120 > | { markdown: string; image?: never; svg?: never; video?: never }
121 > | { svg: string; altText: string; markdown?: never; image?: never; video?: never }
122 > | { video: string | { dark: string; light: string; hc: string }; poster: string | { dark: string; light: string; hc: string }; altText: string; markdown?: never; image?: never; svg?: never };
123 > readonly completionEvents?: string[];
124 > /** @deprecated use `completionEvents: 'onCommand:...'` */
125 > readonly doneOn?: { command: string };
126 > readonly when?: string;
127 > }
128 >
129 > export interface IWalkthrough {
130 > readonly id: string;
131 > readonly title: string;
132 > readonly icon?: string;
133 > readonly description: string;
134 > readonly steps: IWalkthroughStep[];
135 > readonly featuredFor: string[] | undefined;
136 > readonly when?: string;
137 > }
138 >
139 > export interface IStartEntry {
140 > readonly title: string;
141 > readonly description: string;
142 > readonly command: string;
143 > readonly when?: string;
144 > readonly category: 'file' | 'folder' | 'notebook';
145 > }
146 >
147 > export interface INotebookEntry {
148 > readonly type: string;
149 > readonly displayName: string;
150 > }
151 >
152 > export interface INotebookRendererContribution {
153 > readonly id: string;
154 > readonly displayName: string;
155 > readonly mimeTypes: string[];
156 > }
157 >
158 > export interface IDebugVisualizationContribution {
159 > readonly id: string;
160 > readonly when: string;
161 > }
162 >
163 > export interface ITranslation {
164 > id: string;
165 > path: string;
166 > }
167 >
168 > export interface ILocalizationContribution {
169 > languageId: string;
170 > languageName?: string;
171 > localizedLanguageName?: string;
172 > translations: ITranslation[];
173 > minimalTranslations?: { [key: string]: string };
174 > }
175 >
176 > export interface IChatParticipantContribution {
177 > id: string;
178 > name: string;
179 > fullName: string;
180 > description?: string;
181 > isDefault?: boolean;
182 > commands?: { name: string }[];
183 > }
184 >
185 > export interface IToolContribution {
186 > name: string;
187 > displayName: string;
188 > modelDescription: string;
189 > userDescription?: string;
190 > }
191 >
192 > export interface IToolSetContribution {
193 > name: string;
194 > referenceName: string;
195 > description: string;
196 > icon?: string;
197 > tools: string[];
198 > }
199 >
200 > export interface IMcpCollectionContribution {
201 > readonly id: string;
202 > readonly label: string;
203 > readonly when?: string;
204 > }
205 >
206 > export interface IChatFileContribution {
207 > readonly path: string;
208 > readonly name?: string;
209 > readonly description?: string;
210 > readonly when?: string;
211 > readonly sessionTypes?: readonly string[];
212 > }
213 >
214 > export interface IExtensionContributions {
215 > commands?: ICommand[];
216 > configuration?: any;
217 > configurationDefaults?: any;
218 > debuggers?: IDebugger[];
219 > grammars?: IGrammar[];
220 > jsonValidation?: IJSONValidation[];
221 > jsonValidationRegistry?: IJSONValidationRegistry[];
222 > keybindings?: IKeyBinding[];
223 > languages?: ILanguage[];
224 > menus?: { [context: string]: IMenu[] };
225 > snippets?: ISnippet[];
226 > themes?: ITheme[];
227 > iconThemes?: ITheme[];
228 > productIconThemes?: ITheme[];
229 > viewsContainers?: { [location: string]: IViewContainer[] };
230 > views?: { [location: string]: IView[] };
231 > colors?: IColor[];
232 > localizations?: ILocalizationContribution[];
233 > readonly customEditors?: readonly IWebviewEditor[];
234 > readonly codeActions?: readonly ICodeActionContribution[];
235 > authentication?: IAuthenticationContribution[];
236 > walkthroughs?: IWalkthrough[];
237 > startEntries?: IStartEntry[];
238 > readonly notebooks?: INotebookEntry[];
239 > readonly notebookRenderer?: INotebookRendererContribution[];
240 > readonly debugVisualizers?: IDebugVisualizationContribution[];
241 > readonly chatParticipants?: ReadonlyArray<IChatParticipantContribution>;
242 > readonly chatPromptFiles?: ReadonlyArray<IChatFileContribution>;
243 > readonly chatInstructions?: ReadonlyArray<IChatFileContribution>;
244 > readonly chatAgents?: ReadonlyArray<IChatFileContribution>;
245 > readonly chatSkills?: ReadonlyArray<IChatFileContribution>;
246 > readonly chatPlugins?: ReadonlyArray<IChatFileContribution>;
247 > readonly languageModelTools?: ReadonlyArray<IToolContribution>;
248 > readonly languageModelToolSets?: ReadonlyArray<IToolSetContribution>;
249 > readonly mcpServerDefinitionProviders?: ReadonlyArray<IMcpCollectionContribution>;
250 > }
251 >
252 > export interface IExtensionCapabilities {
253 > readonly virtualWorkspaces?: ExtensionVirtualWorkspaceSupport;
254 > readonly untrustedWorkspaces?: ExtensionUntrustedWorkspaceSupport;
255 > }
256 >
257 >
258 > export const ALL_EXTENSION_KINDS: readonly ExtensionKind[] = ['ui', 'workspace', 'web'];
259 >
260 > export type LimitedWorkspaceSupportType = 'limited';
261 > export type ExtensionUntrustedWorkspaceSupportType = boolean | LimitedWorkspaceSupportType;
262 > export type ExtensionUntrustedWorkspaceSupport = { supported: true } | { supported: false; description: string } | { supported: LimitedWorkspaceSupportType; description: string; restrictedConfigurations?: string[] };
263 >
264 > export type ExtensionVirtualWorkspaceSupportType = boolean | LimitedWorkspaceSupportType;
265 > export type ExtensionVirtualWorkspaceSupport = boolean | { supported: true } | { supported: false | LimitedWorkspaceSupportType; description: string };
266 >
267 > export function getWorkspaceSupportTypeMessage(supportType: ExtensionUntrustedWorkspaceSupport | ExtensionVirtualWorkspaceSupport | undefined): string | undefined {
268 if (typeof supportType === 'object' && supportType !== null) {
269 if (supportType.supported !== true) {
273 return undefined;
274 }
276 >
277 > export interface IExtensionIdentifier {
278 > id: string;
279 > uuid?: string;
280 > }
281 >
282 > export const EXTENSION_CATEGORIES = [
283 > 'AI',
284 > 'Azure',
285 > 'Chat',
286 > 'Data Science',
287 > 'Debuggers',
288 > 'Extension Packs',
289 > 'Education',
290 > 'Formatters',
291 > 'Keymaps',
292 > 'Language Packs',
293 > 'Linters',
294 > 'Machine Learning',
295 > 'Notebooks',
296 > 'Programming Languages',
297 > 'SCM Providers',
298 > 'Snippets',
299 > 'Testing',
300 > 'Themes',
301 > 'Visualization',
302 > 'Other',
303 > ];
304 >
305 > export interface IRelaxedExtensionManifest {
306 > name: string;
307 > displayName?: string;
308 > publisher: string;
309 > version: string;
310 > engines: { readonly vscode: string };
311 > description?: string;
312 > main?: string;
313 > type?: string;
314 > browser?: string;
315 > preview?: boolean;
316 > // For now this only supports pointing to l10n bundle files
317 > // but it will be used for package.l10n.json files in the future
318 > l10n?: string;
319 > icon?: string;
320 > categories?: string[];
321 > keywords?: string[];
322 > activationEvents?: readonly string[];
323 > extensionDependencies?: string[];
324 > extensionAffinity?: string[];
325 > extensionPack?: string[];
326 > extensionKind?: ExtensionKind | ExtensionKind[];
327 > contributes?: IExtensionContributions;
328 > repository?: { url: string };
329 > bugs?: { url: string };
330 > originalEnabledApiProposals?: readonly string[];
331 > enabledApiProposals?: readonly string[];
332 > api?: string;
333 > scripts?: { [key: string]: string };
334 > capabilities?: IExtensionCapabilities;
335 > }
336 >
337 > export type IExtensionManifest = Readonly<IRelaxedExtensionManifest>;
338 >
339 > export const enum ExtensionType {
340 > System,
341 > User
342 > }
343 >
344 > export const enum TargetPlatform {
345 > WIN32_X64 = 'win32-x64',
346 > WIN32_ARM64 = 'win32-arm64',
347 >
348 > LINUX_X64 = 'linux-x64',
349 > LINUX_ARM64 = 'linux-arm64',
350 > LINUX_ARMHF = 'linux-armhf',
351 >
352 > ALPINE_X64 = 'alpine-x64',
353 > ALPINE_ARM64 = 'alpine-arm64',
354 >
355 > DARWIN_X64 = 'darwin-x64',
356 > DARWIN_ARM64 = 'darwin-arm64',
357 >
358 > WEB = 'web',
359 >
360 > UNIVERSAL = 'universal',
361 > UNKNOWN = 'unknown',
362 > UNDEFINED = 'undefined',
363 > }
364 >
365 > export interface IExtension {
366 > readonly type: ExtensionType;
367 > readonly isBuiltin: boolean;
368 > readonly identifier: IExtensionIdentifier;
369 > readonly manifest: IExtensionManifest;
370 > readonly location: URI;
371 > readonly targetPlatform: TargetPlatform;
372 > readonly publisherDisplayName?: string;
373 > readonly readmeUrl?: URI;
374 > readonly changelogUrl?: URI;
375 > readonly isValid: boolean;
376 > readonly validations: readonly [Severity, string][];
377 > readonly preRelease: boolean;
378 > }
379 >
380 > /**
381 > * **!Do not construct directly!**
382 > *
383 > * **!Only static methods because it gets serialized!**
384 > *
385 > * This represents the "canonical" version for an extension identifier. Extension ids
386 > * have to be case-insensitive (due to the marketplace), but we must ensure case
387 > * preservation because the extension API is already public at this time.
388 > *
389 > * For example, given an extension with the publisher `"Hello"` and the name `"World"`,
390 > * its canonical extension identifier is `"Hello.World"`. This extension could be
391 > * referenced in some other extension's dependencies using the string `"hello.world"`.
392 > *
393 > * To make matters more complicated, an extension can optionally have an UUID. When two
394 > * extensions have the same UUID, they are considered equal even if their identifier is different.
395 > */
396 > export class ExtensionIdentifier {
397 > public readonly value: string;
398 >
399 > /**
400 > * Do not use directly. This is public to avoid mangling and thus
401 > * allow compatibility between running from source and a built version.
402 > */
403 > readonly _lower: string;
404 >
405 > constructor(value: string) {
406 > this.value = value; extensions.ts
407 > this._lower = value.toLowerCase();
408 > }
410 > public static equals(a: ExtensionIdentifier | string | null | undefined, b: ExtensionIdentifier | string | null | undefined) {
411 if (typeof a === 'undefined' || a === null) {
412 return (typeof b === 'undefined' || b === null);
426 return (a._lower === b._lower);
427 }
429 > /**
430 > * Gives the value by which to index (for equality).
431 > */
432 > public static toKey(id: ExtensionIdentifier | string): string {
433 if (typeof id === 'string') {
434 return id.toLowerCase();
436 return id._lower;
437 }
438 > } extensions.ts
439 >
440 > export class ExtensionIdentifierSet {
441 >
442 > private readonly _set = new Set<string>();
443 >
444 > public get size(): number {
445 > return this._set.size;
446 > }
447 >
448 > constructor(iterable?: Iterable<ExtensionIdentifier | string>) {
449 if (iterable) {
450 for (const value of iterable) {
453 }
454 }
456 > public add(id: ExtensionIdentifier | string): void {
457 this._set.add(ExtensionIdentifier.toKey(id));
458 }
460 > public delete(extensionId: ExtensionIdentifier): boolean {
461 return this._set.delete(ExtensionIdentifier.toKey(extensionId));
462 }
464 > public has(id: ExtensionIdentifier | string): boolean {
465 return this._set.has(ExtensionIdentifier.toKey(id));
466 }
467 > } extensions.ts
468 >
469 > export class ExtensionIdentifierMap<T> {
470
471 private readonly _map = new Map<string, T>();
473 > public clear(): void {
474 this._map.clear();
475 }
477 > public delete(id: ExtensionIdentifier | string): void {
478 this._map.delete(ExtensionIdentifier.toKey(id));
479 }
481 > public get(id: ExtensionIdentifier | string): T | undefined {
482 return this._map.get(ExtensionIdentifier.toKey(id));
483 }
485 > public has(id: ExtensionIdentifier | string): boolean {
486 return this._map.has(ExtensionIdentifier.toKey(id));
487 }
489 > public set(id: ExtensionIdentifier | string, value: T): void {
490 this._map.set(ExtensionIdentifier.toKey(id), value);
491 }
493 > public values(): IterableIterator<T> {
494 return this._map.values();
495 }
497 > forEach(callbackfn: (value: T, key: string, map: Map<string, T>) => void): void {
498 this._map.forEach(callbackfn);
499 }
501 > [Symbol.iterator](): IterableIterator<[string, T]> {
502 return this._map[Symbol.iterator]();
503 }
504 > } extensions.ts
505 >
506 > /**
507 > * An error that is clearly from an extension, identified by the `ExtensionIdentifier`
508 > */
509 > export class ExtensionError extends Error {
510 >
511 > readonly extension: ExtensionIdentifier;
512 >
513 > constructor(extensionIdentifier: ExtensionIdentifier, cause: Error, message?: string) {
514 const detail = message && cause?.message ? `${message}: ${cause.message}` : (message ?? cause?.message);
515 super(`Error in extension ${ExtensionIdentifier.toKey(extensionIdentifier)}: ${detail}`, { cause });
523 }
524 }
525 > } extensions.ts
526 >
527 > export interface IRelaxedExtensionDescription extends IRelaxedExtensionManifest {
528 > id?: string;
529 > identifier: ExtensionIdentifier;
530 > uuid?: string;
531 > publisherDisplayName?: string;
532 > targetPlatform: TargetPlatform;
533 > isBuiltin: boolean;
534 > isUserBuiltin: boolean;
535 > isUnderDevelopment: boolean;
536 > extensionLocation: URI;
537 > preRelease: boolean;
538 > }
539 >
540 > export type IExtensionDescription = Readonly<IRelaxedExtensionDescription>;
541 >
542 > export function isApplicationScopedExtension(manifest: IExtensionManifest): boolean {
543 return isLanguagePackExtension(manifest);
544 }
546 > export function isLanguagePackExtension(manifest: IExtensionManifest): boolean {
547 return manifest.contributes && manifest.contributes.localizations ? manifest.contributes.localizations.length > 0 : false;
548 }
550 > export function isAuthenticationProviderExtension(manifest: IExtensionManifest): boolean {
551 return manifest.contributes && manifest.contributes.authentication ? manifest.contributes.authentication.length > 0 : false;
552 }
554 > export function isResolverExtension(manifest: IExtensionManifest, remoteAuthority: string | undefined): boolean {
555 if (remoteAuthority) {
556 const activationEvent = `onResolveRemoteAuthority:${getRemoteName(remoteAuthority)}`;
559 return false;
560 }
562 > export function parseEnabledApiProposalNames(enabledApiProposals: string[]): string[] {
563 return enabledApiProposals.map(proposal => proposal.split('@')[0]);
564 }
566 > export const IBuiltinExtensionsScannerService = createDecorator<IBuiltinExtensionsScannerService>('IBuiltinExtensionsScannerService');
567 > export interface IBuiltinExtensionsScannerService {
568 > readonly _serviceBrand: undefined;
569 > scanBuiltinExtensions(): Promise<IExtension[]>;
570 > }
src/vs/workbench/services/extensions/common/extensions.ts 476 covered LOC · 23 ranges

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 { Event } from '../../../../base/common/event.js';
7 > import { Disposable, IDisposable, toDisposable } from '../../../../base/common/lifecycle.js';
8 > import { raceTimeout } from '../../../../base/common/async.js';
9 > import Severity from '../../../../base/common/severity.js';
10 > import { URI } from '../../../../base/common/uri.js';
11 > import { IMessagePassingProtocol } from '../../../../base/parts/ipc/common/ipc.js';
12 > import { IAssignmentService } from '../../../../platform/assignment/common/assignment.js';
13 > import { getExtensionId, getGalleryExtensionId } from '../../../../platform/extensionManagement/common/extensionManagementUtil.js';
14 > import { ImplicitActivationEvents } from '../../../../platform/extensionManagement/common/implicitActivationEvents.js';
15 > import { ExtensionIdentifier, ExtensionIdentifierMap, ExtensionIdentifierSet, ExtensionType, IExtension, IExtensionContributions, IExtensionDescription, TargetPlatform } from '../../../../platform/extensions/common/extensions.js';
16 > import { ApiProposalName } from '../../../../platform/extensions/common/extensionsApiProposals.js';
17 > import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
18 > import { IV8Profile } from '../../../../platform/profiling/common/profiling.js';
19 > import { ExtensionHostKind } from './extensionHostKind.js';
20 > import { IExtensionDescriptionDelta, IExtensionDescriptionSnapshot } from './extensionHostProtocol.js';
21 > import { ExtensionRunningLocation } from './extensionRunningLocation.js';
22 > import { IExtensionPoint } from './extensionsRegistry.js';
23 >
24 > export const nullExtensionDescription = Object.freeze<IExtensionDescription>({
25 > identifier: new ExtensionIdentifier('nullExtensionDescription'),
26 > name: 'Null Extension Description',
27 > version: '0.0.0',
28 > publisher: 'vscode',
29 > engines: { vscode: '' },
30 > extensionLocation: URI.parse('void:location'),
31 > isBuiltin: false,
32 > targetPlatform: TargetPlatform.UNDEFINED,
33 > isUserBuiltin: false,
34 > isUnderDevelopment: false,
35 > preRelease: false,
36 > });
37 >
38 > export type WebWorkerExtHostConfigValue = boolean | 'auto';
39 > export const webWorkerExtHostConfig = 'extensions.webWorker';
40 >
41 > export const IExtensionService = createDecorator<IExtensionService>('extensionService');
42 >
43 > export interface IMessage {
44 > type: Severity;
45 > message: string;
46 > extensionId: ExtensionIdentifier;
47 > extensionPointId: string;
48 > }
49 >
50 > export interface IExtensionsStatus {
51 > id: ExtensionIdentifier;
52 > messages: IMessage[];
53 > activationStarted: boolean;
54 > activationTimes: ActivationTimes | undefined;
55 > runtimeErrors: Error[];
56 > runningLocation: ExtensionRunningLocation | null;
57 > }
58 >
59 > export class MissingExtensionDependency {
60 > constructor(readonly dependency: string) { }
61 > }
62 >
63 > /**
64 > * e.g.
65 > * ```
66 > * {
67 > * startTime: 1511954813493000,
68 > * endTime: 1511954835590000,
69 > * deltas: [ 100, 1500, 123456, 1500, 100000 ],
70 > * ids: [ 'idle', 'self', 'extension1', 'self', 'idle' ]
71 > * }
72 > * ```
73 > */
74 > export interface IExtensionHostProfile {
75 > /**
76 > * Profiling start timestamp in microseconds.
77 > */
78 > startTime: number;
79 > /**
80 > * Profiling end timestamp in microseconds.
81 > */
82 > endTime: number;
83 > /**
84 > * Duration of segment in microseconds.
85 > */
86 > deltas: number[];
87 > /**
88 > * Segment identifier: extension id or one of the four known strings.
89 > */
90 > ids: ProfileSegmentId[];
91 >
92 > /**
93 > * Get the information as a .cpuprofile.
94 > */
95 > data: IV8Profile;
96 >
97 > /**
98 > * Get the aggregated time per segmentId
99 > */
100 > getAggregatedTimes(): Map<ProfileSegmentId, number>;
101 > }
102 >
103 > export const enum ExtensionHostStartup {
104 > /**
105 > * The extension host should be launched immediately and doesn't require a `$startExtensionHost` call.
106 > */
107 > EagerAutoStart = 1,
108 > /**
109 > * The extension host should be launched immediately and needs a `$startExtensionHost` call.
110 > */
111 > EagerManualStart = 2,
112 > /**
113 > * The extension host should be launched lazily and only when it has extensions it needs to host. It doesn't require a `$startExtensionHost` call.
114 > */
115 > LazyAutoStart = 3,
116 > }
117 >
118 > export interface IExtensionInspectInfo {
119 > readonly port: number;
120 > readonly host: string;
121 > readonly devtoolsUrl?: string;
122 > readonly devtoolsLabel?: string;
123 > }
124 >
125 > export interface IExtensionHost {
126 > readonly pid: number | null;
127 > readonly runningLocation: ExtensionRunningLocation;
128 > readonly remoteAuthority: string | null;
129 > readonly startup: ExtensionHostStartup;
130 > /**
131 > * A collection of extensions which includes information about which
132 > * extension will execute or is executing on this extension host.
133 > * **NOTE**: this will reflect extensions correctly only after `start()` resolves.
134 > */
135 > readonly extensions: ExtensionHostExtensions | null;
136 > readonly onExit: Event<[number, string | null]>;
137 >
138 > start(): Promise<IMessagePassingProtocol>;
139 > getInspectPort(): IExtensionInspectInfo | undefined;
140 > enableInspectPort(): Promise<boolean>;
141 > disconnect?(): Promise<void>;
142 > dispose(): void;
143 > }
144 >
145 > export class ExtensionHostExtensions {
146 > private _versionId: number;
147 > private _allExtensions: IExtensionDescription[];
148 > private _myExtensions: ExtensionIdentifier[];
149 > private _myActivationEvents: Set<string> | null;
150 >
151 > public get versionId(): number {
152 return this._versionId;
153 }
155 > public get allExtensions(): IExtensionDescription[] {
156 return this._allExtensions;
157 }
159 > public get myExtensions(): ExtensionIdentifier[] {
160 return this._myExtensions;
161 }
163 > constructor(versionId: number, allExtensions: readonly IExtensionDescription[], myExtensions: ExtensionIdentifier[]) {
164 this._versionId = versionId;
165 this._allExtensions = allExtensions.slice(0);
167 this._myActivationEvents = null;
168 }
170 > toSnapshot(): IExtensionDescriptionSnapshot {
171 return {
172 versionId: this._versionId,
176 };
177 }
179 > public set(versionId: number, allExtensions: IExtensionDescription[], myExtensions: ExtensionIdentifier[]): IExtensionDescriptionDelta {
180 if (this._versionId > versionId) {
181 throw new Error(`ExtensionHostExtensions: invalid versionId ${versionId} (current: ${this._versionId})`);
245 return delta;
246 }
248 > public delta(extensionsDelta: IExtensionDescriptionDelta): IExtensionDescriptionDelta | null {
249 if (this._versionId >= extensionsDelta.versionId) {
250 // ignore older deltas
281 return extensionsDelta;
282 }
284 > public containsExtension(extensionId: ExtensionIdentifier): boolean {
285 for (const myExtensionId of this._myExtensions) {
286 if (ExtensionIdentifier.equals(myExtensionId, extensionId)) {
290 return false;
291 }
293 > public containsActivationEvent(activationEvent: string): boolean {
294 if (!this._myActivationEvents) {
295 this._myActivationEvents = this._readMyActivationEvents();
297 return this._myActivationEvents.has(activationEvent);
298 }
300 > private _readMyActivationEvents(): Set<string> {
301 const result = new Set<string>();
302
314 return result;
315 }
316 > } extensions.ts
317 >
318 function extensionDescriptionArrayToMap(extensions: IExtensionDescription[]): ExtensionIdentifierMap<IExtensionDescription> {
319 const result = new ExtensionIdentifierMap<IExtensionDescription>();
323 return result;
324 }
326 > export function isProposedApiEnabled(extension: IExtensionDescription, proposal: ApiProposalName): boolean {
327 if (!extension.enabledApiProposals) {
328 return false;
339 return enabled;
340 }
342 > export interface IProposedApiUsage {
343 > /**
344 > * The identifier of the extension that attempted to use the proposal.
345 > */
346 > readonly extensionId: string;
347 > /**
348 > * The name of the API proposal that the extension is not allowed to use.
349 > */
350 > readonly proposalName: ApiProposalName;
351 > }
352 >
353 > type ProposedApiUsageReporter = (usage: IProposedApiUsage) => void;
354 >
355 > let _proposedApiUsageReporter: ProposedApiUsageReporter | undefined;
356 > const _reportedProposedApiUsages = new Set<string>();
357 >
358 > /**
359 > * Registers a reporter that is invoked whenever an extension attempts to use a proposed API
360 > * that it has not declared via its `enabledApiProposals`-property. This is used to gather
361 > * telemetry about extensions that rely on proposed API they are not entitled to use.
362 > *
363 > * Each unique extension/proposal combination is reported at most once per session in order to
364 > * avoid flooding telemetry from the (potentially hot) call sites of {@link isProposedApiEnabled}.
365 > */
366 > export function setProposedApiUsageReporter(reporter: ProposedApiUsageReporter): IDisposable {
367 _proposedApiUsageReporter = reporter;
368 return toDisposable(() => {
372 });
373 }
375 function reportDisabledProposedApiUsage(extension: IExtensionDescription, proposal: ApiProposalName): void {
376 const reporter = _proposedApiUsageReporter;
385 reporter({ extensionId: extension.identifier.value, proposalName: proposal });
386 }
388 > type ProposedApiEnabledResolver = (extension: IExtensionDescription, proposal: ApiProposalName) => boolean;
389 >
390 > let _proposedApiEnabledResolver: ProposedApiEnabledResolver | undefined;
391 >
392 > /**
393 > * The name of the experiment ("treatment") that can grant proposed API access to
394 > * extension/proposal combinations that have not declared the proposal themselves.
395 > */
396 > export const enabledApiProposalsFallbackExperimentName = 'extensionEnabledApiProposalsFallback';
397 >
398 > /**
399 > * Experiment value that explicitly blocks all proposals reaching the fallback.
400 > */
401 > export const enabledApiProposalsFallbackNone = 'none';
402 >
403 > /**
404 > * Resolves the value of the {@link enabledApiProposalsFallbackExperimentName}-experiment, or
405 > * `undefined` when it does not apply (non-`stable` quality) or cannot be read in time.
406 > */
407 export async function resolveEnabledApiProposalsFallbackExperiment(assignmentService: IAssignmentService, quality: string | undefined): Promise<string | undefined> {
408 if (quality !== 'stable') {
419 }
420 }
422 > /**
423 > * Enables the {@link enabledApiProposalsFallbackExperimentName}-experiment which can grant proposed
424 > * API access to extension/proposal combinations that have not declared the proposal via their
425 > * `enabledApiProposals`-property. It only takes effect on `stable` builds.
426 > *
427 > * Note that the experiment only applies to extensions that already declare at least one proposal:
428 > * an extension with no `enabledApiProposals` at all is never granted access.
429 > *
430 > * @param value A comma-separated list of `publisher.extension:proposalName` entries. Any combination
431 > * that appears here will have {@link isProposedApiEnabled} return `true` even when the extension has
432 > * not declared that particular proposal. When unset, all proposals are allowed;
433 > * {@link enabledApiProposalsFallbackNone} blocks all proposals that reach the fallback.
434 > * @param quality The product quality. The experiment only takes effect when this is `stable`.
435 > */
436 > export function setEnabledApiProposalsFallbackExperiment(value: string | undefined, quality: string | undefined): IDisposable {
437 if (quality !== 'stable') {
438 return Disposable.None;
463 });
464 }
466 > export function checkProposedApiEnabled(extension: IExtensionDescription, proposal: ApiProposalName): void {
467 if (!isProposedApiEnabled(extension, proposal)) {
468 throw new Error(`Extension '${extension.identifier.value}' CANNOT use API proposal: ${proposal}.\nIts package.json#enabledApiProposals-property declares: ${extension.enabledApiProposals?.join(', ') ?? '[]'} but NOT ${proposal}.\n The missing proposal MUST be added and you must start in extension development mode or use the following command line switch: --enable-proposed-api ${extension.identifier.value}`);
469 }
470 }
472 >
473 > /**
474 > * Extension id or one of the four known program states.
475 > */
476 > export type ProfileSegmentId = string | 'idle' | 'program' | 'gc' | 'self';
477 >
478 > export interface ExtensionActivationReason {
479 > readonly startup: boolean;
480 > readonly extensionId: ExtensionIdentifier;
481 > readonly activationEvent: string;
482 > }
483 >
484 > export class ActivationTimes {
485 > constructor(
486 public readonly codeLoadingTime: number,
487 public readonly activateCallTime: number,
490 ) {
491 }
492 > } extensions.ts
493 >
494 > export class ExtensionPointContribution<T> {
495 > readonly description: IExtensionDescription;
496 > readonly value: T;
497 >
498 > constructor(description: IExtensionDescription, value: T) {
499 this.description = description;
500 this.value = value;
501 }
502 > } extensions.ts
503 >
504 > export interface IWillActivateEvent {
505 > readonly event: string;
506 > readonly activation: Promise<void>;
507 > readonly activationKind: ActivationKind;
508 > }
509 >
510 > export interface IResponsiveStateChangeEvent {
511 > extensionHostKind: ExtensionHostKind;
512 > isResponsive: boolean;
513 > /**
514 > * Return the inspect port or `0`. `0` means inspection is not possible.
515 > */
516 > getInspectListener(tryEnableInspector: boolean): Promise<IExtensionInspectInfo | undefined>;
517 > }
518 >
519 > export const enum ActivationKind {
520 > Normal = 0,
521 > Immediate = 1
522 > }
523 >
524 > export interface WillStopExtensionHostsEvent {
525 >
526 > /**
527 > * A human readable reason for stopping the extension hosts
528 > * that e.g. can be shown in a confirmation dialog to the
529 > * user.
530 > */
531 > readonly reason: string;
532 >
533 > /**
534 > * A flag to indicate if the operation was triggered automatically
535 > */
536 > readonly auto: boolean;
537 >
538 > /**
539 > * Allows to veto the stopping of extension hosts. The veto can be a long running
540 > * operation.
541 > *
542 > * @param reason a human readable reason for vetoing the extension host stop in case
543 > * where the resolved `value: true`.
544 > */
545 > veto(value: boolean | Promise<boolean>, reason: string): void;
546 > }
547 >
548 > export interface IExtensionService {
549 > readonly _serviceBrand: undefined;
550 >
551 > /**
552 > * An event emitted when extensions are registered after their extension points got handled.
553 > *
554 > * This event will also fire on startup to signal the installed extensions.
555 > *
556 > * @returns the extensions that got registered
557 > */
558 > readonly onDidRegisterExtensions: Event<void>;
559 >
560 > /**
561 > * @event
562 > * Fired when extensions status changes.
563 > * The event contains the ids of the extensions that have changed.
564 > */
565 > readonly onDidChangeExtensionsStatus: Event<ExtensionIdentifier[]>;
566 >
567 > /**
568 > * Fired when the available extensions change (i.e. when extensions are added or removed).
569 > */
570 > readonly onDidChangeExtensions: Event<{ readonly added: readonly IExtensionDescription[]; readonly removed: readonly IExtensionDescription[] }>;
571 >
572 > /**
573 > * All registered extensions.
574 > * - List will be empty initially during workbench startup and will be filled with extensions as they are registered
575 > * - Listen to `onDidChangeExtensions` event for any changes to the extensions list. It will change as extensions get registered or de-reigstered.
576 > * - Listen to `onDidRegisterExtensions` event or wait for `whenInstalledExtensionsRegistered` promise to get the initial list of registered extensions.
577 > */
578 > readonly extensions: readonly IExtensionDescription[];
579 >
580 > /**
581 > * An event that is fired when activation happens.
582 > */
583 > readonly onWillActivateByEvent: Event<IWillActivateEvent>;
584 >
585 > /**
586 > * An event that is fired when an extension host changes its
587 > * responsive-state.
588 > */
589 > readonly onDidChangeResponsiveChange: Event<IResponsiveStateChangeEvent>;
590 >
591 > /**
592 > * Fired before stop of extension hosts happens. Allows listeners to veto against the
593 > * stop to prevent it from happening.
594 > */
595 > readonly onWillStop: Event<WillStopExtensionHostsEvent>;
596 >
597 > /**
598 > * Send an activation event and activate interested extensions.
599 > *
600 > * This will wait for the normal startup of the extension host(s).
601 > *
602 > * In extraordinary circumstances, if the activation event needs to activate
603 > * one or more extensions before the normal startup is finished, then you can use
604 > * `ActivationKind.Immediate`. Please do not use this flag unless really necessary
605 > * and you understand all consequences.
606 > */
607 > activateByEvent(activationEvent: string, activationKind?: ActivationKind): Promise<void>;
608 >
609 > /**
610 > * Send an activation ID and activate interested extensions.
611 > *
612 > */
613 > activateById(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<void>;
614 >
615 > /**
616 > * Determine if `activateByEvent(activationEvent)` has resolved already.
617 > *
618 > * i.e. the activation event is finished and all interested extensions are already active.
619 > */
620 > activationEventIsDone(activationEvent: string): boolean;
621 >
622 > /**
623 > * An promise that resolves when the installed extensions are registered after
624 > * their extension points got handled.
625 > */
626 > whenInstalledExtensionsRegistered(): Promise<boolean>;
627 >
628 > /**
629 > * Return a specific extension
630 > * @param id An extension id
631 > */
632 > getExtension(id: string): Promise<IExtensionDescription | undefined>;
633 >
634 > /**
635 > * Returns `true` if the given extension can be added. Otherwise `false`.
636 > * @param extension An extension
637 > */
638 > canAddExtension(extension: IExtensionDescription): boolean;
639 >
640 > /**
641 > * Returns `true` if the given extension can be removed. Otherwise `false`.
642 > * @param extension An extension
643 > */
644 > canRemoveExtension(extension: IExtensionDescription): boolean;
645 >
646 > /**
647 > * Read all contributions to an extension point.
648 > */
649 > readExtensionPointContributions<T extends IExtensionContributions[keyof IExtensionContributions]>(extPoint: IExtensionPoint<T>): Promise<ExtensionPointContribution<T>[]>;
650 >
651 > /**
652 > * Get information about extensions status.
653 > */
654 > getExtensionsStatus(): { [id: string]: IExtensionsStatus };
655 >
656 > /**
657 > * Return the inspect ports (if inspection is possible) for extension hosts of kind `extensionHostKind`.
658 > */
659 > getInspectPorts(extensionHostKind: ExtensionHostKind, tryEnableInspector: boolean): Promise<IExtensionInspectInfo[]>;
660 >
661 > /**
662 > * Stops the extension hosts.
663 > *
664 > * @param reason a human readable reason for stopping the extension hosts. This maybe
665 > * can be presented to the user when showing dialogs.
666 > *
667 > * @param auto indicates if the operation was triggered by an automatic action
668 > *
669 > * @returns a promise that resolves to `true` if the extension hosts were stopped, `false`
670 > * if the operation was vetoed by listeners of the `onWillStop` event.
671 > */
672 > stopExtensionHosts(reason: string, auto?: boolean): Promise<boolean>;
673 >
674 > /**
675 > * Starts the extension hosts. If updates are provided, the extension hosts are started with the given updates.
676 > */
677 > startExtensionHosts(updates?: { readonly toAdd: readonly IExtension[]; readonly toRemove: readonly string[] }): Promise<void>;
678 >
679 > /**
680 > * Modify the environment of the remote extension host
681 > * @param env New properties for the remote extension host
682 > */
683 > setRemoteEnvironment(env: { [key: string]: string | null }): Promise<void>;
684 > }
685 >
686 > export interface IInternalExtensionService {
687 > _activateById(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<void>;
688 > _onWillActivateExtension(extensionId: ExtensionIdentifier): void;
689 > _onDidActivateExtension(extensionId: ExtensionIdentifier, codeLoadingTime: number, activateCallTime: number, activateResolvedTime: number, activationReason: ExtensionActivationReason): void;
690 > _onDidActivateExtensionError(extensionId: ExtensionIdentifier, error: Error): void;
691 > _onExtensionRuntimeError(extensionId: ExtensionIdentifier, err: Error): void;
692 > }
693 >
694 > export interface ProfileSession {
695 > stop(): Promise<IExtensionHostProfile>;
696 > }
697 >
698 > export function toExtension(extensionDescription: IExtensionDescription): IExtension {
699 return {
700 type: extensionDescription.isBuiltin ? ExtensionType.System : ExtensionType.User,
710 };
711 }
713 > export function toExtensionDescription(extension: IExtension, isUnderDevelopment?: boolean): IExtensionDescription {
714 const id = getExtensionId(extension.manifest.publisher, extension.manifest.name);
715 return {
727 };
728 }
730 >
731 > export class NullExtensionService implements IExtensionService {
732 declare readonly _serviceBrand: undefined;
733 readonly onDidRegisterExtensions: Event<void> = Event.None;
738 readonly onWillStop: Event<WillStopExtensionHostsEvent> = Event.None;
739 readonly extensions = [];
740 > activateByEvent(_activationEvent: string): Promise<void> { return Promise.resolve(undefined); } extensions.ts
741 > activateById(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<void> { return Promise.resolve(undefined); }
742 > activationEventIsDone(_activationEvent: string): boolean { return false; }
743 > whenInstalledExtensionsRegistered(): Promise<boolean> { return Promise.resolve(true); }
744 > getExtension() { return Promise.resolve(undefined); }
745 > readExtensionPointContributions<T>(_extPoint: IExtensionPoint<T>): Promise<ExtensionPointContribution<T>[]> { return Promise.resolve(Object.create(null)); }
746 > getExtensionsStatus(): { [id: string]: IExtensionsStatus } { return Object.create(null); }
747 > getInspectPorts(_extensionHostKind: ExtensionHostKind, _tryEnableInspector: boolean): Promise<IExtensionInspectInfo[]> { return Promise.resolve([]); }
748 > async stopExtensionHosts(): Promise<boolean> { return true; }
749 > async startExtensionHosts(): Promise<void> { }
750 > async setRemoteEnvironment(_env: { [key: string]: string | null }): Promise<void> { }
751 > canAddExtension(): boolean { return false; }
752 > canRemoveExtension(): boolean { return false; }
753 > }
src/vs/platform/notification/common/notification.ts 464 covered LOC · 3 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 {
457
458 readonly progress = new NoOpProgress();
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/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/platform/storage/common/storage.ts 451 covered LOC · 41 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- storage.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { Promises, RunOnceScheduler, runWhenGlobalIdle } from '../../../base/common/async.js';
7 > import { Emitter, Event, PauseableEmitter } from '../../../base/common/event.js';
8 > import { Disposable, DisposableStore, dispose, MutableDisposable } from '../../../base/common/lifecycle.js';
9 > import { mark } from '../../../base/common/performance.js';
10 > import { isUndefinedOrNull } from '../../../base/common/types.js';
11 > import { InMemoryStorageDatabase, IStorage, IStorageChangeEvent, Storage, StorageHint, StorageValue } from '../../../base/parts/storage/common/storage.js';
12 > import { createDecorator } from '../../instantiation/common/instantiation.js';
13 > import { isUserDataProfile, IUserDataProfile } from '../../userDataProfile/common/userDataProfile.js';
14 > import { IAnyWorkspaceIdentifier } from '../../workspace/common/workspace.js';
15 >
16 > export const IS_NEW_KEY = '__$__isNewStorageMarker';
17 > export const TARGET_KEY = '__$__targetStorageMarker';
18 >
19 > export const IStorageService = createDecorator<IStorageService>('storageService');
20 >
21 > export enum WillSaveStateReason {
22 >
23 > /**
24 > * No specific reason to save state.
25 > */
26 > NONE,
27 >
28 > /**
29 > * A hint that the workbench is about to shutdown.
30 > */
31 > SHUTDOWN
32 > }
33 >
34 > export interface IWillSaveStateEvent {
35 > readonly reason: WillSaveStateReason;
36 > }
37 >
38 > export interface IStorageEntry {
39 > readonly key: string;
40 > readonly value: StorageValue;
41 > readonly scope: StorageScope;
42 > readonly target: StorageTarget;
43 > }
44 >
45 > export interface IWorkspaceStorageValueChangeEvent extends IStorageValueChangeEvent {
46 > readonly scope: StorageScope.WORKSPACE;
47 > }
48 >
49 > export interface IProfileStorageValueChangeEvent extends IStorageValueChangeEvent {
50 > readonly scope: StorageScope.PROFILE;
51 > }
52 >
53 > export interface IApplicationStorageValueChangeEvent extends IStorageValueChangeEvent {
54 > readonly scope: StorageScope.APPLICATION;
55 > }
56 >
57 > export interface IApplicationSharedStorageValueChangeEvent extends IStorageValueChangeEvent {
58 > readonly scope: StorageScope.APPLICATION_SHARED;
59 > }
60 >
61 > export interface IStorageService {
62 >
63 > readonly _serviceBrand: undefined;
64 >
65 > /**
66 > * Emitted whenever data is updated or deleted on the given
67 > * scope and optional key.
68 > *
69 > * @param scope the `StorageScope` to listen to changes
70 > * @param key the optional key to filter for or all keys of
71 > * the scope if `undefined`
72 > */
73 > onDidChangeValue(scope: StorageScope.WORKSPACE, key: string | undefined, disposable: DisposableStore): Event<IWorkspaceStorageValueChangeEvent>;
74 > onDidChangeValue(scope: StorageScope.PROFILE, key: string | undefined, disposable: DisposableStore): Event<IProfileStorageValueChangeEvent>;
75 > onDidChangeValue(scope: StorageScope.APPLICATION, key: string | undefined, disposable: DisposableStore): Event<IApplicationStorageValueChangeEvent>;
76 > onDidChangeValue(scope: StorageScope.APPLICATION_SHARED, key: string | undefined, disposable: DisposableStore): Event<IApplicationSharedStorageValueChangeEvent>;
77 > onDidChangeValue(scope: StorageScope, key: string | undefined, disposable: DisposableStore): Event<IStorageValueChangeEvent>;
78 >
79 > /**
80 > * Emitted whenever target of a storage entry changes.
81 > */
82 > readonly onDidChangeTarget: Event<IStorageTargetChangeEvent>;
83 >
84 > /**
85 > * Emitted when the storage is about to persist. This is the right time
86 > * to persist data to ensure it is stored before the application shuts
87 > * down.
88 > *
89 > * The will save state event allows to optionally ask for the reason of
90 > * saving the state, e.g. to find out if the state is saved due to a
91 > * shutdown.
92 > *
93 > * Note: this event may be fired many times, not only on shutdown to prevent
94 > * loss of state in situations where the shutdown is not sufficient to
95 > * persist the data properly.
96 > */
97 > readonly onWillSaveState: Event<IWillSaveStateEvent>;
98 >
99 > /**
100 > * Retrieve an element stored with the given key from storage. Use
101 > * the provided `defaultValue` if the element is `null` or `undefined`.
102 > *
103 > * @param scope allows to define the scope of the storage operation
104 > * to either the current workspace only, all workspaces or all profiles.
105 > */
106 > get(key: string, scope: StorageScope, fallbackValue: string): string;
107 > get(key: string, scope: StorageScope, fallbackValue?: string): string | undefined;
108 >
109 > /**
110 > * Retrieve an element stored with the given key from storage. Use
111 > * the provided `defaultValue` if the element is `null` or `undefined`.
112 > * The element will be converted to a `boolean`.
113 > *
114 > * @param scope allows to define the scope of the storage operation
115 > * to either the current workspace only, all workspaces or all profiles.
116 > */
117 > getBoolean(key: string, scope: StorageScope, fallbackValue: boolean): boolean;
118 > getBoolean(key: string, scope: StorageScope, fallbackValue?: boolean): boolean | undefined;
119 >
120 > /**
121 > * Retrieve an element stored with the given key from storage. Use
122 > * the provided `defaultValue` if the element is `null` or `undefined`.
123 > * The element will be converted to a `number` using `parseInt` with a
124 > * base of `10`.
125 > *
126 > * @param scope allows to define the scope of the storage operation
127 > * to either the current workspace only, all workspaces or all profiles.
128 > */
129 > getNumber(key: string, scope: StorageScope, fallbackValue: number): number;
130 > getNumber(key: string, scope: StorageScope, fallbackValue?: number): number | undefined;
131 >
132 > /**
133 > * Retrieve an element stored with the given key from storage. Use
134 > * the provided `defaultValue` if the element is `null` or `undefined`.
135 > * The element will be converted to a `object` using `JSON.parse`.
136 > *
137 > * @param scope allows to define the scope of the storage operation
138 > * to either the current workspace only, all workspaces or all profiles.
139 > */
140 > getObject<T extends object>(key: string, scope: StorageScope, fallbackValue: T): T;
141 > getObject<T extends object>(key: string, scope: StorageScope, fallbackValue?: T): T | undefined;
142 >
143 > /**
144 > * Store a value under the given key to storage. The value will be
145 > * converted to a `string`. Storing either `undefined` or `null` will
146 > * remove the entry under the key.
147 > *
148 > * @param scope allows to define the scope of the storage operation
149 > * to either the current workspace only, all workspaces or all profiles.
150 > *
151 > * @param target allows to define the target of the storage operation
152 > * to either the current machine or user.
153 > */
154 > store(key: string, value: StorageValue, scope: StorageScope, target: StorageTarget): void;
155 >
156 > /**
157 > * Allows to store multiple values in a bulk operation. Events will only
158 > * be emitted when all values have been stored.
159 > *
160 > * @param external a hint to indicate the source of the operation is external,
161 > * such as settings sync or profile changes.
162 > */
163 > storeAll(entries: Array<IStorageEntry>, external: boolean): void;
164 >
165 > /**
166 > * Delete an element stored under the provided key from storage.
167 > *
168 > * The scope argument allows to define the scope of the storage
169 > * operation to either the current workspace only, all workspaces
170 > * or all profiles.
171 > */
172 > remove(key: string, scope: StorageScope): void;
173 >
174 > /**
175 > * Returns all the keys used in the storage for the provided `scope`
176 > * and `target`.
177 > *
178 > * Note: this will NOT return all keys stored in the storage layer.
179 > * Some keys may not have an associated `StorageTarget` and thus
180 > * will be excluded from the results.
181 > *
182 > * @param scope allows to define the scope for the keys
183 > * to either the current workspace only, all workspaces or all profiles.
184 > *
185 > * @param target allows to define the target for the keys
186 > * to either the current machine or user.
187 > */
188 > keys(scope: StorageScope, target: StorageTarget): string[];
189 >
190 > /**
191 > * Log the contents of the storage to the console.
192 > */
193 > log(): void;
194 >
195 > /**
196 > * Returns true if the storage service handles the provided scope.
197 > */
198 > hasScope(scope: IAnyWorkspaceIdentifier | IUserDataProfile): boolean;
199 >
200 > /**
201 > * Switch storage to another workspace or profile. Optionally preserve the
202 > * current data to the new storage.
203 > */
204 > switch(to: IAnyWorkspaceIdentifier | IUserDataProfile, preserveData: boolean): Promise<void>;
205 >
206 > /**
207 > * Whether the storage for the given scope was created during this session or
208 > * existed before.
209 > */
210 > isNew(scope: StorageScope): boolean;
211 >
212 > /**
213 > * Attempts to reduce the DB size via optimization commands if supported.
214 > */
215 > optimize(scope: StorageScope): Promise<void>;
216 >
217 > /**
218 > * Allows to flush state, e.g. in cases where a shutdown is
219 > * imminent. This will send out the `onWillSaveState` to ask
220 > * everyone for latest state.
221 > *
222 > * @returns a `Promise` that can be awaited on when all updates
223 > * to the underlying storage have been flushed.
224 > */
225 > flush(reason?: WillSaveStateReason): Promise<void>;
226 > }
227 >
228 > export const enum StorageScope {
229 >
230 > /**
231 > * The stored data will be scoped to all workspaces across all profiles
232 > * and shared across VS Code and Sessions app.
233 > */
234 > APPLICATION_SHARED = -2,
235 >
236 > /**
237 > * The stored data will be scoped to all workspaces across all profiles.
238 > */
239 > APPLICATION = -1,
240 >
241 > /**
242 > * The stored data will be scoped to all workspaces of the same profile.
243 > */
244 > PROFILE = 0,
245 >
246 > /**
247 > * The stored data will be scoped to the current workspace.
248 > */
249 > WORKSPACE = 1
250 > }
251 >
252 > export const enum StorageTarget {
253 >
254 > /**
255 > * The stored data is user specific and applies across machines.
256 > */
257 > USER,
258 >
259 > /**
260 > * The stored data is machine specific.
261 > */
262 > MACHINE
263 > }
264 >
265 > export interface IStorageValueChangeEvent {
266 >
267 > /**
268 > * The scope for the storage entry that changed
269 > * or was removed.
270 > */
271 > readonly scope: StorageScope;
272 >
273 > /**
274 > * The `key` of the storage entry that was changed
275 > * or was removed.
276 > */
277 > readonly key: string;
278 >
279 > /**
280 > * The `target` can be `undefined` if a key is being
281 > * removed.
282 > */
283 > readonly target: StorageTarget | undefined;
284 >
285 > /**
286 > * A hint how the storage change event was triggered. If
287 > * `true`, the storage change was triggered by an external
288 > * source, such as:
289 > * - another process (for example another window)
290 > * - operations such as settings sync or profiles change
291 > */
292 > readonly external?: boolean;
293 > }
294 >
295 > export interface IStorageTargetChangeEvent {
296 >
297 > /**
298 > * The scope for the target that changed. Listeners
299 > * should use `keys(scope, target)` to get an updated
300 > * list of keys for the given `scope` and `target`.
301 > */
302 > readonly scope: StorageScope;
303 > }
304 >
305 > interface IKeyTargets {
306 > [key: string]: StorageTarget;
307 > }
308 >
309 > export interface IStorageServiceOptions {
310 > readonly flushInterval: number;
311 > }
312 >
313 > export function loadKeyTargets(storage: IStorage): IKeyTargets {
314 const keysRaw = storage.get(TARGET_KEY);
315 if (keysRaw) {
323 return Object.create(null);
324 }
325 > storage.ts
326 > export abstract class AbstractStorageService extends Disposable implements IStorageService {
327 >
328 > declare readonly _serviceBrand: undefined;
329 >
330 > private static DEFAULT_FLUSH_INTERVAL = 60 * 1000; // every minute
331 >
332 > private readonly _onDidChangeValue = this._register(new PauseableEmitter<IStorageValueChangeEvent>());
333 >
334 > private readonly _onDidChangeTarget = this._register(new PauseableEmitter<IStorageTargetChangeEvent>());
335 > readonly onDidChangeTarget = this._onDidChangeTarget.event;
336 >
337 > private readonly _onWillSaveState = this._register(new Emitter<IWillSaveStateEvent>());
338 > readonly onWillSaveState = this._onWillSaveState.event;
339 >
340 > private initializationPromise: Promise<void> | undefined;
341 >
342 > private readonly flushWhenIdleScheduler: RunOnceScheduler;
343 > private readonly runFlushWhenIdle = this._register(new MutableDisposable());
344 >
345 > constructor(options: IStorageServiceOptions = { flushInterval: AbstractStorageService.DEFAULT_FLUSH_INTERVAL }) {
346 super();
347
348 this.flushWhenIdleScheduler = this._register(new RunOnceScheduler(() => this.doFlushWhenIdle(), options.flushInterval));
349 }
350 > storage.ts
351 > onDidChangeValue(scope: StorageScope.WORKSPACE, key: string | undefined, disposable: DisposableStore): Event<IWorkspaceStorageValueChangeEvent>;
352 > onDidChangeValue(scope: StorageScope.PROFILE, key: string | undefined, disposable: DisposableStore): Event<IProfileStorageValueChangeEvent>;
353 > onDidChangeValue(scope: StorageScope.APPLICATION, key: string | undefined, disposable: DisposableStore): Event<IApplicationStorageValueChangeEvent>;
354 > onDidChangeValue(scope: StorageScope.APPLICATION_SHARED, key: string | undefined, disposable: DisposableStore): Event<IApplicationSharedStorageValueChangeEvent>;
355 > onDidChangeValue(scope: StorageScope, key: string | undefined, disposable: DisposableStore): Event<IStorageValueChangeEvent> {
356 return Event.filter(this._onDidChangeValue.event, e => e.scope === scope && (key === undefined || e.key === key), disposable);
357 }
358 > storage.ts
359 > private doFlushWhenIdle(): void {
360 this.runFlushWhenIdle.value = runWhenGlobalIdle(() => {
361 if (this.shouldFlushWhenIdle()) {
367 });
368 }
369 > storage.ts
370 > protected shouldFlushWhenIdle(): boolean {
371 return true;
372 }
373 > storage.ts
374 > protected stopFlushWhenIdle(): void {
375 dispose([this.runFlushWhenIdle, this.flushWhenIdleScheduler]);
376 }
377 > storage.ts
378 > initialize(): Promise<void> {
379 if (!this.initializationPromise) {
380 this.initializationPromise = (async () => {
402 return this.initializationPromise;
403 }
404 > storage.ts
405 > protected emitDidChangeValue(scope: StorageScope, event: IStorageChangeEvent): void {
406 const { key, external } = event;
407
434 }
435 }
436 > storage.ts
437 > protected emitWillSaveState(reason: WillSaveStateReason): void {
438 this._onWillSaveState.fire({ reason });
439 }
440 > storage.ts
441 > get(key: string, scope: StorageScope, fallbackValue: string): string;
442 > get(key: string, scope: StorageScope): string | undefined;
443 > get(key: string, scope: StorageScope, fallbackValue?: string): string | undefined {
444 return this.getStorage(scope)?.get(key, fallbackValue);
445 }
446 > storage.ts
447 > getBoolean(key: string, scope: StorageScope, fallbackValue: boolean): boolean;
448 > getBoolean(key: string, scope: StorageScope): boolean | undefined;
449 > getBoolean(key: string, scope: StorageScope, fallbackValue?: boolean): boolean | undefined {
450 return this.getStorage(scope)?.getBoolean(key, fallbackValue);
451 }
452 > storage.ts
453 > getNumber(key: string, scope: StorageScope, fallbackValue: number): number;
454 > getNumber(key: string, scope: StorageScope): number | undefined;
455 > getNumber(key: string, scope: StorageScope, fallbackValue?: number): number | undefined {
456 return this.getStorage(scope)?.getNumber(key, fallbackValue);
457 }
458 > storage.ts
459 > getObject(key: string, scope: StorageScope, fallbackValue: object): object;
460 > getObject(key: string, scope: StorageScope): object | undefined;
461 > getObject(key: string, scope: StorageScope, fallbackValue?: object): object | undefined {
462 return this.getStorage(scope)?.getObject(key, fallbackValue);
463 }
464 > storage.ts
465 > storeAll(entries: Array<IStorageEntry>, external: boolean): void {
466 this.withPausedEmitters(() => {
467 for (const entry of entries) {
470 });
471 }
472 > storage.ts
473 > store(key: string, value: StorageValue, scope: StorageScope, target: StorageTarget, external = false): void {
474
475 // We remove the key for undefined/null values
489 });
490 }
491 > storage.ts
492 > remove(key: string, scope: StorageScope, external = false): void {
493
494 // Update our datastructures but send events only after
502 });
503 }
504 > storage.ts
505 > private withPausedEmitters(fn: Function): void {
506
507 // Pause emitters
518 }
519 }
520 > storage.ts
521 > keys(scope: StorageScope, target: StorageTarget): string[] {
522 const keys: string[] = [];
523
532 return keys;
533 }
534 > storage.ts
535 > private updateKeyTarget(key: string, scope: StorageScope, target: StorageTarget | undefined, external = false): void {
536
537 // Add
552 }
553 }
554 > storage.ts
555 > private _workspaceKeyTargets: IKeyTargets | undefined = undefined;
556 > private get workspaceKeyTargets(): IKeyTargets {
557 if (!this._workspaceKeyTargets) {
558 this._workspaceKeyTargets = this.loadKeyTargets(StorageScope.WORKSPACE);
561 return this._workspaceKeyTargets;
562 }
563 > storage.ts
564 > private _profileKeyTargets: IKeyTargets | undefined = undefined;
565 > private get profileKeyTargets(): IKeyTargets {
566 if (!this._profileKeyTargets) {
567 this._profileKeyTargets = this.loadKeyTargets(StorageScope.PROFILE);
570 return this._profileKeyTargets;
571 }
572 > storage.ts
573 > private _applicationKeyTargets: IKeyTargets | undefined = undefined;
574 > private get applicationKeyTargets(): IKeyTargets {
575 if (!this._applicationKeyTargets) {
576 this._applicationKeyTargets = this.loadKeyTargets(StorageScope.APPLICATION);
579 return this._applicationKeyTargets;
580 }
581 > storage.ts
582 > private _applicationSharedKeyTargets: IKeyTargets | undefined = undefined;
583 > private get applicationSharedKeyTargets(): IKeyTargets {
584 if (!this._applicationSharedKeyTargets) {
585 this._applicationSharedKeyTargets = this.loadKeyTargets(StorageScope.APPLICATION_SHARED);
588 return this._applicationSharedKeyTargets;
589 }
590 > storage.ts
591 > private getKeyTargets(scope: StorageScope): IKeyTargets {
592 switch (scope) {
593 case StorageScope.APPLICATION_SHARED:
601 }
602 }
603 > storage.ts
604 > private loadKeyTargets(scope: StorageScope): { [key: string]: StorageTarget } {
605 const storage = this.getStorage(scope);
606
607 return storage ? loadKeyTargets(storage) : Object.create(null);
608 }
609 > storage.ts
610 > isNew(scope: StorageScope): boolean {
611 return this.getBoolean(IS_NEW_KEY, scope) === true;
612 }
613 > storage.ts
614 > async flush(reason = WillSaveStateReason.NONE): Promise<void> {
615
616 // Signal event to collect changes
646 }
647 }
648 > storage.ts
649 > async log(): Promise<void> {
650 const applicationItems = this.getStorage(StorageScope.APPLICATION)?.items ?? new Map<string, string>();
651 const applicationSharedItems = this.getStorage(StorageScope.APPLICATION_SHARED)?.items ?? new Map<string, string>();
664 );
665 }
666 > storage.ts
667 > async optimize(scope: StorageScope): Promise<void> {
668
669 // Await pending data to be flushed to the DB
673 return this.getStorage(scope)?.optimize();
674 }
675 > storage.ts
676 > async switch(to: IAnyWorkspaceIdentifier | IUserDataProfile, preserveData: boolean): Promise<void> {
677
678 // Signal as event so that clients can store data before we switch
685 return this.switchToWorkspace(to, preserveData);
686 }
687 > storage.ts
688 > protected canSwitchProfile(from: IUserDataProfile, to: IUserDataProfile): boolean {
689 if (from.id === to.id) {
690 return false; // both profiles are same
697 return true;
698 }
699 > storage.ts
700 > protected switchData(oldStorage: Map<string, string>, newStorage: IStorage, scope: StorageScope): void {
701 this.withPausedEmitters(() => {
702 // Signal storage keys that have changed
718 });
719 }
720 > storage.ts
721 > // --- abstract
722 >
723 > abstract hasScope(scope: IAnyWorkspaceIdentifier | IUserDataProfile): boolean;
724 >
725 > protected abstract doInitialize(): Promise<void>;
726 >
727 > protected abstract getStorage(scope: StorageScope): IStorage | undefined;
728 >
729 > protected abstract getLogDetails(scope: StorageScope): string | undefined;
730 >
731 > protected abstract switchToProfile(toProfile: IUserDataProfile, preserveData: boolean): Promise<void>;
732 > protected abstract switchToWorkspace(toWorkspace: IAnyWorkspaceIdentifier | IUserDataProfile, preserveData: boolean): Promise<void>;
733 > }
734 >
735 > export function isProfileUsingDefaultStorage(profile: IUserDataProfile): boolean {
736 return profile.isDefault || !!profile.useDefaultFlags?.globalState;
737 }
738 > storage.ts
739 > export class InMemoryStorageService extends AbstractStorageService {
740 >
741 > private readonly applicationStorage = this._register(new Storage(new InMemoryStorageDatabase(), { hint: StorageHint.STORAGE_IN_MEMORY }));
742 > private readonly applicationSharedStorage = this._register(new Storage(new InMemoryStorageDatabase(), { hint: StorageHint.STORAGE_IN_MEMORY }));
743 > private readonly profileStorage = this._register(new Storage(new InMemoryStorageDatabase(), { hint: StorageHint.STORAGE_IN_MEMORY }));
744 > private readonly workspaceStorage = this._register(new Storage(new InMemoryStorageDatabase(), { hint: StorageHint.STORAGE_IN_MEMORY }));
745 >
746 > constructor() {
747 super();
748
752 this._register(this.applicationSharedStorage.onDidChangeStorage(e => this.emitDidChangeValue(StorageScope.APPLICATION_SHARED, e)));
753 }
754 > storage.ts
755 > protected getStorage(scope: StorageScope): IStorage {
756 switch (scope) {
757 case StorageScope.APPLICATION_SHARED:
765 }
766 }
767 > storage.ts
768 > protected getLogDetails(scope: StorageScope): string | undefined {
769 switch (scope) {
770 case StorageScope.APPLICATION_SHARED:
778 }
779 }
780 > storage.ts
781 > protected async doInitialize(): Promise<void> { }
782 >
783 > protected async switchToProfile(): Promise<void> {
784 // no-op when in-memory
785 }
786 > storage.ts
787 > protected async switchToWorkspace(): Promise<void> {
788 // no-op when in-memory
789 }
790 > storage.ts
791 > protected override shouldFlushWhenIdle(): boolean {
792 return false;
793 }
794 > storage.ts
795 > hasScope(scope: IAnyWorkspaceIdentifier | IUserDataProfile): boolean {
796 return false;
797 }
798 > } storage.ts
799 >
800 export async function logStorage(application: Map<string, string>, applicationShared: Map<string, string>, profile: Map<string, string>, workspace: Map<string, string>, applicationPath: string, applicationSharedPath: string, profilePath: string, workspacePath: string): Promise<void> {
801 const safeParse = (value: string) => {
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/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/workbench/services/textfile/common/encoding.ts 439 covered LOC · 21 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- encoding.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { Readable, ReadableStream, newWriteableStream, listenStream } from '../../../../base/common/stream.js';
7 > import { VSBuffer, VSBufferReadable, VSBufferReadableStream } from '../../../../base/common/buffer.js';
8 > import { importAMDNodeModule } from '../../../../amdX.js';
9 > import { CancellationTokenSource } from '../../../../base/common/cancellation.js';
10 > import { coalesce } from '../../../../base/common/arrays.js';
11 >
12 > export const UTF8 = 'utf8';
13 > export const UTF8_with_bom = 'utf8bom';
14 > export const UTF16be = 'utf16be';
15 > export const UTF16le = 'utf16le';
16 >
17 > export type UTF_ENCODING = typeof UTF8 | typeof UTF8_with_bom | typeof UTF16be | typeof UTF16le;
18 >
19 > export function isUTFEncoding(encoding: string): encoding is UTF_ENCODING {
20 return [UTF8, UTF8_with_bom, UTF16be, UTF16le].some(utfEncoding => utfEncoding === encoding);
21 }
23 > export const UTF16be_BOM = [0xFE, 0xFF];
24 > export const UTF16le_BOM = [0xFF, 0xFE];
25 > export const UTF8_BOM = [0xEF, 0xBB, 0xBF];
26 >
27 > const ZERO_BYTE_DETECTION_BUFFER_MAX_LEN = 512; // number of bytes to look at to decide about a file being binary or not
28 > const NO_ENCODING_GUESS_MIN_BYTES = 512; // when not auto guessing the encoding, small number of bytes are enough
29 > const AUTO_ENCODING_GUESS_MIN_BYTES = 512 * 8; // with auto guessing we want a lot more content to be read for guessing
30 > const AUTO_ENCODING_GUESS_MAX_BYTES = 512 * 128; // set an upper limit for the number of bytes we pass on to jschardet
31 >
32 > export interface IDecodeStreamOptions {
33 > acceptTextOnly: boolean;
34 > guessEncoding: boolean;
35 > candidateGuessEncodings: string[];
36 > minBytesRequiredForDetection?: number;
37 >
38 > overwriteEncoding(detectedEncoding: string | null): Promise<string>;
39 > }
40 >
41 > export interface IDecodeStreamResult {
42 > stream: ReadableStream<string>;
43 > detected: IDetectedEncodingResult;
44 > }
45 >
46 > export const enum DecodeStreamErrorKind {
47 >
48 > /**
49 > * Error indicating that the stream is binary even
50 > * though `acceptTextOnly` was specified.
51 > */
52 > STREAM_IS_BINARY = 1
53 > }
54 >
55 > export class DecodeStreamError extends Error {
56 >
57 > constructor(
58 message: string,
59 readonly decodeStreamErrorKind: DecodeStreamErrorKind
61 super(message);
62 }
63 > } encoding.ts
64 >
65 > export interface IDecoderStream {
66 > write(buffer: Uint8Array): string;
67 > end(): string | undefined;
68 > }
69 >
70 > class DecoderStream implements IDecoderStream {
71 >
72 > /**
73 > * This stream will only load iconv-lite lazily if the encoding
74 > * is not UTF-8. This ensures that for most common cases we do
75 > * not pay the price of loading the module from disk.
76 > *
77 > * We still need to be careful when converting UTF-8 to a string
78 > * though because we read the file in chunks of Buffer and thus
79 > * need to decode it via TextDecoder helper that is available
80 > * in browser and node.js environments.
81 > */
82 > static async create(encoding: string): Promise<DecoderStream> {
83 > let decoder: IDecoderStream | undefined = undefined;
84 > if (encoding !== UTF8) {
85 > const iconv = await importAMDNodeModule<typeof import('@vscode/iconv-lite-umd')>('@vscode/iconv-lite-umd', 'lib/iconv-lite-umd.js'); encoding.ts
86 > decoder = iconv.getDecoder(toNodeEncoding(encoding));
87 > } else { encoding.ts
88 > const utf8TextDecoder = new TextDecoder(); encoding.ts
89 > decoder = {
90 > write(buffer: Uint8Array): string {
91 > return utf8TextDecoder.decode(buffer, {
92 > // Signal to TextDecoder that potentially more data is coming
93 > // and that we are calling `decode` in the end to consume any
94 > // remainders
95 > stream: true
96 > });
97 > },
98 >
99 > end(): string | undefined {
100 > return utf8TextDecoder.decode();
101 > }
102 > };
103 > }
104 > encoding.ts
105 > return new DecoderStream(decoder);
106 > }
107 >
108 > private constructor(private iconvLiteDecoder: IDecoderStream) { }
109 >
110 > write(buffer: Uint8Array): string {
111 return this.iconvLiteDecoder.write(buffer);
112 }
113 > encoding.ts
114 > end(): string | undefined {
115 return this.iconvLiteDecoder.end();
116 }
117 > } encoding.ts
118 >
119 > export function toDecodeStream(source: VSBufferReadableStream, options: IDecodeStreamOptions): Promise<IDecodeStreamResult> {
120 const minBytesRequiredForDetection = options.minBytesRequiredForDetection ?? (options.guessEncoding ? AUTO_ENCODING_GUESS_MIN_BYTES : NO_ENCODING_GUESS_MIN_BYTES);
121
214 });
215 }
216 > encoding.ts
217 export async function toEncodeReadable(readable: Readable<string>, encoding: string, options?: { addBOM?: boolean }): Promise<VSBufferReadable> {
218 const iconv = await importAMDNodeModule<typeof import('@vscode/iconv-lite-umd')>('@vscode/iconv-lite-umd', 'lib/iconv-lite-umd.js');
263 };
264 }
265 > encoding.ts
266 export async function encodingExists(encoding: string): Promise<boolean> {
267 const iconv = await importAMDNodeModule<typeof import('@vscode/iconv-lite-umd')>('@vscode/iconv-lite-umd', 'lib/iconv-lite-umd.js');
269 return iconv.encodingExists(toNodeEncoding(encoding));
270 }
271 > encoding.ts
272 > export function toNodeEncoding(enc: string | null): string {
273 if (enc === UTF8_with_bom || enc === null) {
274 return UTF8; // iconv does not distinguish UTF 8 with or without BOM, so we need to help it
277 return enc;
278 }
279 > encoding.ts
280 > export function detectEncodingByBOMFromBuffer(buffer: VSBuffer | null, bytesRead: number): typeof UTF8_with_bom | typeof UTF16le | typeof UTF16be | null {
281 if (!buffer || bytesRead < UTF16be_BOM.length) {
282 return null;
309 return null;
310 }
311 > encoding.ts
312 > // we explicitly ignore a specific set of encodings from auto guessing
313 > // - ASCII: we never want this encoding (most UTF-8 files would happily detect as
314 > // ASCII files and then you could not type non-ASCII characters anymore)
315 > // - UTF-16: we have our own detection logic for UTF-16
316 > // - UTF-32: we do not support this encoding in VSCode
317 > const IGNORE_ENCODINGS = ['ascii', 'utf-16', 'utf-32'];
318 >
319 > /**
320 > * Guesses the encoding from buffer.
321 > */
322 async function guessEncodingByBuffer(buffer: VSBuffer, candidateGuessEncodings?: string[]): Promise<string | null> {
323 const jschardet = await importAMDNodeModule<typeof import('jschardet')>('jschardet', 'dist/jschardet.min.js');
357 return toIconvLiteEncoding(guessed.encoding);
358 }
359 > encoding.ts
360 > const JSCHARDET_TO_ICONV_ENCODINGS: { [name: string]: string } = {
361 > 'ibm866': 'cp866',
362 > 'big5': 'cp950'
363 > };
364 >
365 function normalizeEncoding(encodingName: string): string {
366 return encodingName.replace(/[^a-zA-Z0-9]/g, '').toLowerCase();
367 }
368 > encoding.ts
369 function toIconvLiteEncoding(encodingName: string): string {
370 const normalizedEncodingName = normalizeEncoding(encodingName);
373 return mapped || normalizedEncodingName;
374 }
375 > encoding.ts
376 function toJschardetEncoding(encodingName: string): string | undefined {
377 const normalizedEncodingName = normalizeEncoding(encodingName);
380 return mapped ? mapped.guessableName : undefined;
381 }
382 > encoding.ts
383 function encodeLatin1(buffer: Uint8Array): string {
384 let result = '';
389 return result;
390 }
391 > encoding.ts
392 > /**
393 > * The encodings that are allowed in a settings file don't match the canonical encoding labels specified by WHATWG.
394 > * See https://encoding.spec.whatwg.org/#names-and-labels
395 > * Iconv-lite strips all non-alphanumeric characters, but ripgrep doesn't. For backcompat, allow these labels.
396 > */
397 > export function toCanonicalName(enc: string): string {
398 switch (enc) {
399 case 'shiftjis':
427 }
428 }
429 > encoding.ts
430 > export interface IDetectedEncodingResult {
431 > encoding: string | null;
432 > seemsBinary: boolean;
433 > }
434 >
435 > export interface IReadResult {
436 > buffer: VSBuffer | null;
437 > bytesRead: number;
438 > }
439 >
440 > export function detectEncodingFromBuffer(readResult: IReadResult, autoGuessEncoding?: false, candidateGuessEncodings?: string[]): IDetectedEncodingResult;
441 > export function detectEncodingFromBuffer(readResult: IReadResult, autoGuessEncoding?: boolean, candidateGuessEncodings?: string[]): Promise<IDetectedEncodingResult>;
442 > export function detectEncodingFromBuffer({ buffer, bytesRead }: IReadResult, autoGuessEncoding?: boolean, candidateGuessEncodings?: string[]): Promise<IDetectedEncodingResult> | IDetectedEncodingResult {
443
444 // Always first check for BOM to find out about encoding
507 return { seemsBinary, encoding };
508 }
509 > encoding.ts
510 > type EncodingsMap = { [encoding: string]: { labelLong: string; labelShort: string; order: number; encodeOnly?: boolean; alias?: string; guessableName?: string } };
511 >
512 > export const SUPPORTED_ENCODINGS: EncodingsMap = {
513 > utf8: {
514 > labelLong: 'UTF-8',
515 > labelShort: 'UTF-8',
516 > order: 1,
517 > alias: 'utf8bom',
518 > guessableName: 'UTF-8'
519 > },
520 > utf8bom: {
521 > labelLong: 'UTF-8 with BOM',
522 > labelShort: 'UTF-8 with BOM',
523 > encodeOnly: true,
524 > order: 2,
525 > alias: 'utf8'
526 > },
527 > utf16le: {
528 > labelLong: 'UTF-16 LE',
529 > labelShort: 'UTF-16 LE',
530 > order: 3,
531 > guessableName: 'UTF-16LE'
532 > },
533 > utf16be: {
534 > labelLong: 'UTF-16 BE',
535 > labelShort: 'UTF-16 BE',
536 > order: 4,
537 > guessableName: 'UTF-16BE'
538 > },
539 > windows1252: {
540 > labelLong: 'Western (Windows 1252)',
541 > labelShort: 'Windows 1252',
542 > order: 5,
543 > guessableName: 'windows-1252'
544 > },
545 > iso88591: {
546 > labelLong: 'Western (ISO 8859-1)',
547 > labelShort: 'ISO 8859-1',
548 > order: 6
549 > },
550 > iso88593: {
551 > labelLong: 'Western (ISO 8859-3)',
552 > labelShort: 'ISO 8859-3',
553 > order: 7
554 > },
555 > iso885915: {
556 > labelLong: 'Western (ISO 8859-15)',
557 > labelShort: 'ISO 8859-15',
558 > order: 8
559 > },
560 > macroman: {
561 > labelLong: 'Western (Mac Roman)',
562 > labelShort: 'Mac Roman',
563 > order: 9
564 > },
565 > cp437: {
566 > labelLong: 'DOS (CP 437)',
567 > labelShort: 'CP437',
568 > order: 10
569 > },
570 > windows1256: {
571 > labelLong: 'Arabic (Windows 1256)',
572 > labelShort: 'Windows 1256',
573 > order: 11
574 > },
575 > iso88596: {
576 > labelLong: 'Arabic (ISO 8859-6)',
577 > labelShort: 'ISO 8859-6',
578 > order: 12
579 > },
580 > windows1257: {
581 > labelLong: 'Baltic (Windows 1257)',
582 > labelShort: 'Windows 1257',
583 > order: 13
584 > },
585 > iso88594: {
586 > labelLong: 'Baltic (ISO 8859-4)',
587 > labelShort: 'ISO 8859-4',
588 > order: 14
589 > },
590 > iso885914: {
591 > labelLong: 'Celtic (ISO 8859-14)',
592 > labelShort: 'ISO 8859-14',
593 > order: 15
594 > },
595 > windows1250: {
596 > labelLong: 'Central European (Windows 1250)',
597 > labelShort: 'Windows 1250',
598 > order: 16,
599 > guessableName: 'windows-1250'
600 > },
601 > iso88592: {
602 > labelLong: 'Central European (ISO 8859-2)',
603 > labelShort: 'ISO 8859-2',
604 > order: 17,
605 > guessableName: 'ISO-8859-2'
606 > },
607 > cp852: {
608 > labelLong: 'Central European (CP 852)',
609 > labelShort: 'CP 852',
610 > order: 18
611 > },
612 > windows1251: {
613 > labelLong: 'Cyrillic (Windows 1251)',
614 > labelShort: 'Windows 1251',
615 > order: 19,
616 > guessableName: 'windows-1251'
617 > },
618 > cp866: {
619 > labelLong: 'Cyrillic (CP 866)',
620 > labelShort: 'CP 866',
621 > order: 20,
622 > guessableName: 'IBM866'
623 > },
624 > cp1125: {
625 > labelLong: 'Cyrillic (CP 1125)',
626 > labelShort: 'CP 1125',
627 > order: 21,
628 > guessableName: 'IBM1125'
629 > },
630 > iso88595: {
631 > labelLong: 'Cyrillic (ISO 8859-5)',
632 > labelShort: 'ISO 8859-5',
633 > order: 22,
634 > guessableName: 'ISO-8859-5'
635 > },
636 > koi8r: {
637 > labelLong: 'Cyrillic (KOI8-R)',
638 > labelShort: 'KOI8-R',
639 > order: 23,
640 > guessableName: 'KOI8-R'
641 > },
642 > koi8u: {
643 > labelLong: 'Cyrillic (KOI8-U)',
644 > labelShort: 'KOI8-U',
645 > order: 24
646 > },
647 > iso885913: {
648 > labelLong: 'Estonian (ISO 8859-13)',
649 > labelShort: 'ISO 8859-13',
650 > order: 25
651 > },
652 > windows1253: {
653 > labelLong: 'Greek (Windows 1253)',
654 > labelShort: 'Windows 1253',
655 > order: 26,
656 > guessableName: 'windows-1253'
657 > },
658 > iso88597: {
659 > labelLong: 'Greek (ISO 8859-7)',
660 > labelShort: 'ISO 8859-7',
661 > order: 27,
662 > guessableName: 'ISO-8859-7'
663 > },
664 > windows1255: {
665 > labelLong: 'Hebrew (Windows 1255)',
666 > labelShort: 'Windows 1255',
667 > order: 28,
668 > guessableName: 'windows-1255'
669 > },
670 > iso88598: {
671 > labelLong: 'Hebrew (ISO 8859-8)',
672 > labelShort: 'ISO 8859-8',
673 > order: 29,
674 > guessableName: 'ISO-8859-8'
675 > },
676 > iso885910: {
677 > labelLong: 'Nordic (ISO 8859-10)',
678 > labelShort: 'ISO 8859-10',
679 > order: 30
680 > },
681 > iso885916: {
682 > labelLong: 'Romanian (ISO 8859-16)',
683 > labelShort: 'ISO 8859-16',
684 > order: 31
685 > },
686 > windows1254: {
687 > labelLong: 'Turkish (Windows 1254)',
688 > labelShort: 'Windows 1254',
689 > order: 32
690 > },
691 > iso88599: {
692 > labelLong: 'Turkish (ISO 8859-9)',
693 > labelShort: 'ISO 8859-9',
694 > order: 33
695 > },
696 > cp857: {
697 > labelLong: 'Turkish (CP 857)',
698 > labelShort: 'CP 857',
699 > order: 34
700 > },
701 > windows1258: {
702 > labelLong: 'Vietnamese (Windows 1258)',
703 > labelShort: 'Windows 1258',
704 > order: 35
705 > },
706 > gbk: {
707 > labelLong: 'Simplified Chinese (GBK)',
708 > labelShort: 'GBK',
709 > order: 36
710 > },
711 > gb18030: {
712 > labelLong: 'Simplified Chinese (GB18030)',
713 > labelShort: 'GB18030',
714 > order: 37
715 > },
716 > cp950: {
717 > labelLong: 'Traditional Chinese (Big5)',
718 > labelShort: 'Big5',
719 > order: 38,
720 > guessableName: 'Big5'
721 > },
722 > big5hkscs: {
723 > labelLong: 'Traditional Chinese (Big5-HKSCS)',
724 > labelShort: 'Big5-HKSCS',
725 > order: 39
726 > },
727 > shiftjis: {
728 > labelLong: 'Japanese (Shift JIS)',
729 > labelShort: 'Shift JIS',
730 > order: 40,
731 > guessableName: 'SHIFT_JIS'
732 > },
733 > eucjp: {
734 > labelLong: 'Japanese (EUC-JP)',
735 > labelShort: 'EUC-JP',
736 > order: 41,
737 > guessableName: 'EUC-JP'
738 > },
739 > euckr: {
740 > labelLong: 'Korean (EUC-KR)',
741 > labelShort: 'EUC-KR',
742 > order: 42,
743 > guessableName: 'EUC-KR'
744 > },
745 > windows874: {
746 > labelLong: 'Thai (Windows 874)',
747 > labelShort: 'Windows 874',
748 > order: 43
749 > },
750 > iso885911: {
751 > labelLong: 'Latin/Thai (ISO 8859-11)',
752 > labelShort: 'ISO 8859-11',
753 > order: 44
754 > },
755 > koi8ru: {
756 > labelLong: 'Cyrillic (KOI8-RU)',
757 > labelShort: 'KOI8-RU',
758 > order: 45
759 > },
760 > koi8t: {
761 > labelLong: 'Tajik (KOI8-T)',
762 > labelShort: 'KOI8-T',
763 > order: 46
764 > },
765 > gb2312: {
766 > labelLong: 'Simplified Chinese (GB 2312)',
767 > labelShort: 'GB 2312',
768 > order: 47,
769 > guessableName: 'GB2312'
770 > },
771 > cp865: {
772 > labelLong: 'Nordic DOS (CP 865)',
773 > labelShort: 'CP 865',
774 > order: 48
775 > },
776 > cp850: {
777 > labelLong: 'Western European DOS (CP 850)',
778 > labelShort: 'CP 850',
779 > order: 49
780 > }
781 > };
782 >
783 > export const GUESSABLE_ENCODINGS: EncodingsMap = (() => {
784 > const guessableEncodings: EncodingsMap = {};
785 > for (const encoding in SUPPORTED_ENCODINGS) {
786 > if (SUPPORTED_ENCODINGS[encoding].guessableName) {
787 > guessableEncodings[encoding] = SUPPORTED_ENCODINGS[encoding];
788 > }
789 > }
790 >
791 > return guessableEncodings;
792 > })();
src/vs/workbench/api/common/extHostTerminalService.ts 423 covered LOC · 109 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostTerminalService.ts
2 > * Copyright (c) Microsoft 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 * as vscode from 'vscode';
7 > import { Event, Emitter } from '../../../base/common/event.js';
8 > import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, ITerminalDimensionsDto, ITerminalLinkDto, ExtHostTerminalIdentifier, ICommandDto, ITerminalQuickFixOpenerDto, ITerminalQuickFixTerminalCommandDto, TerminalCommandMatchResultDto, ITerminalCommandDto, ITerminalCompletionContextDto, TerminalCompletionListDto } from './extHost.protocol.js';
9 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
10 > import { URI } from '../../../base/common/uri.js';
11 > import { IExtHostRpcService } from './extHostRpcService.js';
12 > import { IDisposable, DisposableStore, Disposable, MutableDisposable } from '../../../base/common/lifecycle.js';
13 > import { Disposable as VSCodeDisposable, EnvironmentVariableMutatorType, TerminalExitReason, TerminalCompletionItem } from './extHostTypes.js';
14 > import { IExtensionDescription } from '../../../platform/extensions/common/extensions.js';
15 > import { localize } from '../../../nls.js';
16 > import { NotSupportedError } from '../../../base/common/errors.js';
17 > import { serializeEnvironmentDescriptionMap, serializeEnvironmentVariableCollection } from '../../../platform/terminal/common/environmentVariableShared.js';
18 > import { CancellationTokenSource } from '../../../base/common/cancellation.js';
19 > import { generateUuid } from '../../../base/common/uuid.js';
20 > import { IEnvironmentVariableCollectionDescription, IEnvironmentVariableMutator, ISerializableEnvironmentVariableCollection } from '../../../platform/terminal/common/environmentVariable.js';
21 > import { ICreateContributedTerminalProfileOptions, IProcessReadyEvent, IShellLaunchConfigDto, ITerminalChildProcess, ITerminalLaunchError, ITerminalProfile, TerminalIcon, TerminalLocation, IProcessProperty, ProcessPropertyType, IProcessPropertyMap, TerminalShellType, WindowsShellType } from '../../../platform/terminal/common/terminal.js';
22 > import { TerminalDataBufferer } from '../../../platform/terminal/common/terminalDataBuffering.js';
23 > import { ThemeColor } from '../../../base/common/themables.js';
24 > import { Promises } from '../../../base/common/async.js';
25 > import { EditorGroupColumn } from '../../services/editor/common/editorGroupColumn.js';
26 > import { TerminalCompletionList, TerminalQuickFix, ViewColumn } from './extHostTypeConverters.js';
27 > import { IExtHostCommands } from './extHostCommands.js';
28 > import { IExtHostInitDataService } from './extHostInitDataService.js';
29 > import { MarshalledId } from '../../../base/common/marshallingIds.js';
30 > import { ISerializedTerminalInstanceContext } from '../../contrib/terminal/common/terminal.js';
31 > import { isWindows } from '../../../base/common/platform.js';
32 > import { hasKey } from '../../../base/common/types.js';
33 > import { isProposedApiEnabled } from '../../services/extensions/common/extensions.js';
34 >
35 > export interface IExtHostTerminalService extends ExtHostTerminalServiceShape, IDisposable {
36 >
37 > readonly _serviceBrand: undefined;
38 >
39 > activeTerminal: vscode.Terminal | undefined;
40 > terminals: vscode.Terminal[];
41 >
42 > readonly onDidCloseTerminal: Event<vscode.Terminal>;
43 > readonly onDidOpenTerminal: Event<vscode.Terminal>;
44 > readonly onDidChangeActiveTerminal: Event<vscode.Terminal | undefined>;
45 > readonly onDidChangeTerminalDimensions: Event<vscode.TerminalDimensionsChangeEvent>;
46 > readonly onDidChangeTerminalState: Event<vscode.Terminal>;
47 > readonly onDidWriteTerminalData: Event<vscode.TerminalDataWriteEvent>;
48 > readonly onDidExecuteTerminalCommand: Event<vscode.TerminalExecutedCommand>;
49 > readonly onDidChangeShell: Event<string>;
50 >
51 > createTerminal(name?: string, shellPath?: string, shellArgs?: readonly string[] | string): vscode.Terminal;
52 > createTerminalFromOptions(options: vscode.TerminalOptions, internalOptions?: ITerminalInternalOptions): vscode.Terminal;
53 > createExtensionTerminal(options: vscode.ExtensionTerminalOptions): vscode.Terminal;
54 > attachPtyToTerminal(id: number, pty: vscode.Pseudoterminal): void;
55 > getDefaultShell(useAutomationShell: boolean): string;
56 > getDefaultShellArgs(useAutomationShell: boolean): string[] | string;
57 > registerLinkProvider(provider: vscode.TerminalLinkProvider): vscode.Disposable;
58 > registerProfileProvider(extension: IExtensionDescription, id: string, provider: vscode.TerminalProfileProvider): vscode.Disposable;
59 > registerTerminalQuickFixProvider(id: string, extensionId: string, provider: vscode.TerminalQuickFixProvider): vscode.Disposable;
60 > getEnvironmentVariableCollection(extension: IExtensionDescription): IEnvironmentVariableCollection;
61 > getTerminalById(id: number): ExtHostTerminal | null;
62 > getTerminalIdByApiObject(apiTerminal: vscode.Terminal): number | null;
63 > registerTerminalCompletionProvider(extension: IExtensionDescription, provider: vscode.TerminalCompletionProvider<vscode.TerminalCompletionItem>, ...triggerCharacters: string[]): vscode.Disposable;
64 > }
65 >
66 > interface IEnvironmentVariableCollection extends vscode.EnvironmentVariableCollection {
67 > getScoped(scope: vscode.EnvironmentVariableScope): vscode.EnvironmentVariableCollection;
68 > }
69 >
70 > export interface ITerminalInternalOptions {
71 > cwd?: string | URI;
72 > isFeatureTerminal?: boolean;
73 > forceShellIntegration?: boolean;
74 > useShellEnvironment?: boolean;
75 > resolvedExtHostIdentifier?: ExtHostTerminalIdentifier;
76 > /**
77 > * This location is different from the API location because it can include splitActiveTerminal,
78 > * a property we resolve internally
79 > */
80 > location?: TerminalLocation | { viewColumn: number; preserveState?: boolean } | { splitActiveTerminal: boolean };
81 > }
82 >
83 > export const IExtHostTerminalService = createDecorator<IExtHostTerminalService>('IExtHostTerminalService');
84 >
85 > export class ExtHostTerminal extends Disposable {
86 > private _disposed: boolean = false;
87 > private _pidPromise: Promise<number | undefined>;
88 > private _cols: number | undefined;
89 > private _pidPromiseComplete: ((value: number | undefined) => unknown) | undefined;
90 > private _rows: number | undefined;
91 > private _exitStatus: vscode.TerminalExitStatus | undefined;
92 > private _state: vscode.TerminalState = { isInteractedWith: false, shell: undefined };
93 > private _selection: string | undefined;
94 >
95 > shellIntegration: vscode.TerminalShellIntegration | undefined;
96 >
97 > public isOpen: boolean = false;
98 >
99 > readonly value: vscode.Terminal;
100 >
101 > protected readonly _onWillDispose = this._register(new Emitter<void>());
102 > readonly onWillDispose = this._onWillDispose.event;
103 >
104 > constructor(
105 private _proxy: MainThreadTerminalServiceShape,
106 public _id: ExtHostTerminalIdentifier,
165 };
166 }
168 > override dispose(): void {
169 this._onWillDispose.fire();
170 super.dispose();
171 }
173 > public async create(
174 options: vscode.TerminalOptions,
175 internalOptions?: ITerminalInternalOptions,
199 });
200 }
202 >
203 > public async createExtensionTerminal(location?: TerminalLocation | vscode.TerminalEditorLocationOptions | vscode.TerminalSplitLocationOptions, internalOptions?: ITerminalInternalOptions, parentTerminal?: ExtHostTerminalIdentifier, iconPath?: TerminalIcon, color?: ThemeColor, shellIntegrationNonce?: string, titleTemplate?: string): Promise<number> {
204 if (typeof this._id !== 'string') {
205 throw new Error('Terminal has already been created');
221 return this._id;
222 }
224 > private _serializeParentTerminal(location?: TerminalLocation | vscode.TerminalEditorLocationOptions | vscode.TerminalSplitLocationOptions, parentTerminal?: ExtHostTerminalIdentifier): TerminalLocation | { viewColumn: EditorGroupColumn; preserveFocus?: boolean } | { parentTerminal: ExtHostTerminalIdentifier } | undefined {
225 if (typeof location === 'object') {
226 if (hasKey(location, { parentTerminal: true }) && location.parentTerminal && parentTerminal) {
237 return location;
238 }
240 > private _checkDisposed() {
241 if (this._disposed) {
242 throw new Error('Terminal has already been disposed');
243 }
244 }
246 > public set name(name: string) {
247 this._name = name;
248 }
250 > public setExitStatus(code: number | undefined, reason: TerminalExitReason) {
251 this._exitStatus = Object.freeze({ code, reason });
252 }
254 > public setDimensions(cols: number, rows: number): boolean {
255 if (cols === this._cols && rows === this._rows) {
256 // Nothing changed
264 return true;
265 }
267 > public setInteractedWith(): boolean {
268 if (!this._state.isInteractedWith) {
269 this._state = {
275 return false;
276 }
278 > public setShellType(shellType: TerminalShellType | undefined): boolean {
279
280 if (this._state.shell !== shellType) {
287 return false;
288 }
290 > public setSelection(selection: string | undefined): void {
291 this._selection = selection;
292 }
294 > public _setProcessId(processId: number | undefined): void {
295 // The event may fire 2 times when the panel is restored
296 if (this._pidPromiseComplete) {
306 }
307 }
309 >
310 > class ExtHostPseudoterminal implements ITerminalChildProcess {
311 > readonly id = 0;
312 > readonly shouldPersist = false;
313 >
314 > private readonly _onProcessData = new Emitter<string>();
315 > public readonly onProcessData: Event<string> = this._onProcessData.event;
316 > private readonly _onProcessReady = new Emitter<IProcessReadyEvent>();
317 > public get onProcessReady(): Event<IProcessReadyEvent> { return this._onProcessReady.event; }
318 > private readonly _onDidChangeProperty = new Emitter<IProcessProperty>();
319 > public readonly onDidChangeProperty = this._onDidChangeProperty.event;
320 > private readonly _onProcessExit = new Emitter<number | undefined>();
321 > public readonly onProcessExit: Event<number | undefined> = this._onProcessExit.event;
322 >
323 > constructor(private readonly _pty: vscode.Pseudoterminal) { }
324 >
325 > refreshProperty<T extends ProcessPropertyType>(property: ProcessPropertyType): Promise<IProcessPropertyMap[T]> {
326 throw new Error(`refreshProperty is not suppported in extension owned terminals. property: ${property}`);
327 }
329 > updateProperty<T extends ProcessPropertyType>(property: ProcessPropertyType, value: IProcessPropertyMap[T]): Promise<void> {
330 throw new Error(`updateProperty is not suppported in extension owned terminals. property: ${property}, value: ${value}`);
331 }
333 > async start(): Promise<undefined> {
334 return undefined;
335 }
337 > shutdown(): void {
338 this._pty.close();
339 }
341 > input(data: string): void {
342 this._pty.handleInput?.(data);
343 }
345 > sendSignal(signal: string): void {
346 // Extension owned terminals don't support sending signals directly to processes
347 // This could be extended in the future if the pseudoterminal API is enhanced
348 }
350 > resize(cols: number, rows: number): void {
351 this._pty.setDimensions?.({ columns: cols, rows });
352 }
354 > clearBuffer(): void {
355 // no-op
356 }
358 > async processBinary(data: string): Promise<void> {
359 // No-op, processBinary is not supported in extension owned terminals.
360 }
362 > acknowledgeDataEvent(charCount: number): void {
363 // No-op, flow control is not supported in extension owned terminals. If this is ever
364 // implemented it will need new pause and resume VS Code APIs.
365 }
367 > async setUnicodeVersion(version: '6' | '11'): Promise<void> {
368 // No-op, xterm-headless isn't used for extension owned terminals.
369 }
371 > getInitialCwd(): Promise<string> {
372 return Promise.resolve('');
373 }
375 > getCwd(): Promise<string> {
376 return Promise.resolve('');
377 }
379 > startSendingEvents(initialDimensions: ITerminalDimensionsDto | undefined): void {
380 // Attach the listeners
381 this._pty.onDidWrite(e => this._onProcessData.fire(e));
400 this._onProcessReady.fire({ pid: -1, cwd: '', windowsPty: undefined });
401 }
403 >
404 > let nextLinkId = 1;
405 >
406 > interface ICachedLinkEntry {
407 > provider: vscode.TerminalLinkProvider;
408 > link: vscode.TerminalLink;
409 > }
410 >
411 > export abstract class BaseExtHostTerminalService extends Disposable implements IExtHostTerminalService, ExtHostTerminalServiceShape {
412 >
413 > readonly _serviceBrand: undefined;
414 >
415 > protected _proxy: MainThreadTerminalServiceShape;
416 > protected _activeTerminal: ExtHostTerminal | undefined;
417 > protected _terminals: ExtHostTerminal[] = [];
418 > protected _terminalProcesses: Map<number, ITerminalChildProcess> = new Map();
419 > protected _terminalProcessDisposables: { [id: number]: IDisposable } = {};
420 > protected _extensionTerminalAwaitingStart: { [id: number]: { initialDimensions: ITerminalDimensionsDto | undefined } | undefined } = {};
421 > protected _getTerminalPromises: { [id: number]: Promise<ExtHostTerminal | undefined> } = {};
422 > protected _environmentVariableCollections: Map<string, UnifiedEnvironmentVariableCollection> = new Map();
423 > private _defaultProfile: ITerminalProfile | undefined;
424 > private _defaultAutomationProfile: ITerminalProfile | undefined;
425 > private readonly _lastQuickFixCommands: MutableDisposable<IDisposable> = this._register(new MutableDisposable());
426 >
427 > private readonly _bufferer: TerminalDataBufferer;
428 > private readonly _linkProviders: Set<vscode.TerminalLinkProvider> = new Set();
429 > private readonly _completionProviders: Map<string, vscode.TerminalCompletionProvider<vscode.TerminalCompletionItem>> = new Map();
430 > private readonly _profileProviders: Map<string, { provider: vscode.TerminalProfileProvider; extension: IExtensionDescription }> = new Map();
431 > private readonly _quickFixProviders: Map<string, vscode.TerminalQuickFixProvider> = new Map();
432 > private readonly _terminalLinkCache: Map<number, Map<number, ICachedLinkEntry>> = new Map();
433 > private readonly _terminalLinkCancellationSource: Map<number, CancellationTokenSource> = new Map();
434 >
435 > public get activeTerminal(): vscode.Terminal | undefined { return this._activeTerminal?.value; }
436 > public get terminals(): vscode.Terminal[] { return this._terminals.map(term => term.value); }
437 >
438 > protected readonly _onDidCloseTerminal = new Emitter<vscode.Terminal>();
439 > readonly onDidCloseTerminal = this._onDidCloseTerminal.event;
440 > protected readonly _onDidOpenTerminal = new Emitter<vscode.Terminal>();
441 > readonly onDidOpenTerminal = this._onDidOpenTerminal.event;
442 > protected readonly _onDidChangeActiveTerminal = new Emitter<vscode.Terminal | undefined>();
443 > readonly onDidChangeActiveTerminal = this._onDidChangeActiveTerminal.event;
444 > protected readonly _onDidChangeTerminalDimensions = new Emitter<vscode.TerminalDimensionsChangeEvent>();
445 > readonly onDidChangeTerminalDimensions = this._onDidChangeTerminalDimensions.event;
446 > protected readonly _onDidChangeTerminalState = new Emitter<vscode.Terminal>();
447 > readonly onDidChangeTerminalState = this._onDidChangeTerminalState.event;
448 > protected readonly _onDidChangeShell = new Emitter<string>();
449 > readonly onDidChangeShell = this._onDidChangeShell.event;
450 >
451 > protected readonly _onDidWriteTerminalData = new Emitter<vscode.TerminalDataWriteEvent>({
452 > onWillAddFirstListener: () => this._proxy.$startSendingDataEvents(),
453 > onDidRemoveLastListener: () => this._proxy.$stopSendingDataEvents()
454 > });
455 > readonly onDidWriteTerminalData = this._onDidWriteTerminalData.event;
456 > protected readonly _onDidExecuteCommand = new Emitter<vscode.TerminalExecutedCommand>({
457 > onWillAddFirstListener: () => this._proxy.$startSendingCommandEvents(),
458 > onDidRemoveLastListener: () => this._proxy.$stopSendingCommandEvents()
459 > });
460 > readonly onDidExecuteTerminalCommand = this._onDidExecuteCommand.event;
461 >
462 > constructor(
463 supportsProcesses: boolean,
464 @IExtHostCommands private readonly _extHostCommands: IExtHostCommands,
501 });
502 }
504 > public abstract createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal;
505 > public abstract createTerminalFromOptions(options: vscode.TerminalOptions, internalOptions?: ITerminalInternalOptions): vscode.Terminal;
506 >
507 > public getDefaultShell(useAutomationShell: boolean): string {
508 const profile = useAutomationShell ? this._defaultAutomationProfile : this._defaultProfile;
509 return profile?.path || '';
510 }
512 > public getDefaultShellArgs(useAutomationShell: boolean): string[] | string {
513 const profile = useAutomationShell ? this._defaultAutomationProfile : this._defaultProfile;
514 return profile?.args || [];
515 }
517 > public createExtensionTerminal(options: vscode.ExtensionTerminalOptions, internalOptions?: ITerminalInternalOptions): vscode.Terminal {
518 const terminal = new ExtHostTerminal(this._proxy, generateUuid(), options, options.name);
519 const p = new ExtHostPseudoterminal(options.pty);
525 return terminal.value;
526 }
528 > protected _serializeParentTerminal(options: vscode.TerminalOptions, internalOptions?: ITerminalInternalOptions): ITerminalInternalOptions {
529 internalOptions = internalOptions ? internalOptions : {};
530 if (options.location && typeof options.location === 'object' && hasKey(options.location, { parentTerminal: true })) {
543 return internalOptions;
544 }
546 > public attachPtyToTerminal(id: number, pty: vscode.Pseudoterminal): void {
547 const terminal = this.getTerminalById(id);
548 if (!terminal) {
553 this._terminalProcessDisposables[id] = disposable;
554 }
556 > public async $acceptActiveTerminalChanged(id: number | null): Promise<void> {
557 const original = this._activeTerminal;
558 if (id === null) {
571 }
572 }
574 > public async $acceptTerminalProcessData(id: number, data: string): Promise<void> {
575 const terminal = this.getTerminalById(id);
576 if (terminal) {
578 }
579 }
581 > public async $acceptTerminalDimensions(id: number, cols: number, rows: number): Promise<void> {
582 const terminal = this.getTerminalById(id);
583 if (terminal) {
590 }
591 }
593 > public async $acceptDidExecuteCommand(id: number, command: ITerminalCommandDto): Promise<void> {
594 const terminal = this.getTerminalById(id);
595 if (terminal) {
597 }
598 }
600 > public async $acceptTerminalMaximumDimensions(id: number, cols: number, rows: number): Promise<void> {
601 // Extension pty terminal only - when virtual process resize fires it means that the
602 // terminal's maximum dimensions changed
603 this._terminalProcesses.get(id)?.resize(cols, rows);
604 }
606 > public async $acceptTerminalTitleChange(id: number, name: string): Promise<void> {
607 const terminal = this.getTerminalById(id);
608 if (terminal) {
610 }
611 }
613 > public async $acceptTerminalClosed(id: number, exitCode: number | undefined, exitReason: TerminalExitReason): Promise<void> {
614 // Release any cached terminal links and cancel in-flight link providers for this terminal
615 this._terminalLinkCache.delete(id);
627 }
628 }
630 > public $acceptTerminalOpened(id: number, extHostTerminalId: string | undefined, name: string, shellLaunchConfigDto: IShellLaunchConfigDto): void {
631 if (extHostTerminalId) {
632 // Resolve with the renderer generated id
655 terminal.isOpen = true;
656 }
658 > public async $acceptTerminalProcessId(id: number, processId: number): Promise<void> {
659 const terminal = this.getTerminalById(id);
660 terminal?._setProcessId(processId);
661 }
663 > public async $startExtensionTerminal(id: number, initialDimensions: ITerminalDimensionsDto | undefined): Promise<ITerminalLaunchError | undefined> {
664 // Make sure the ExtHostTerminal exists so onDidOpenTerminal has fired before we call
665 // Pseudoterminal.start
692 return undefined;
693 }
695 > protected _setupExtHostProcessListeners(id: number, p: ITerminalChildProcess): IDisposable {
696 const disposables = new DisposableStore();
697 disposables.add(p.onProcessReady(e => this._proxy.$sendProcessReady(id, e.pid, e.cwd, e.windowsPty)));
711 return disposables;
712 }
714 > public $acceptProcessAckDataEvent(id: number, charCount: number): void {
715 this._terminalProcesses.get(id)?.acknowledgeDataEvent(charCount);
716 }
718 > public $acceptProcessInput(id: number, data: string): void {
719 this._terminalProcesses.get(id)?.input(data);
720 }
722 > public $acceptTerminalInteraction(id: number): void {
723 const terminal = this.getTerminalById(id);
724 if (terminal?.setInteractedWith()) {
726 }
727 }
729 > public $acceptTerminalSelection(id: number, selection: string | undefined): void {
730 this.getTerminalById(id)?.setSelection(selection);
731 }
733 > public $acceptProcessResize(id: number, cols: number, rows: number): void {
734 try {
735 this._terminalProcesses.get(id)?.resize(cols, rows);
741 }
742 }
744 > public $acceptProcessShutdown(id: number, immediate: boolean): void {
745 this._terminalProcesses.get(id)?.shutdown(immediate);
746 }
748 > public $acceptProcessRequestInitialCwd(id: number): void {
749 this._terminalProcesses.get(id)?.getInitialCwd().then(initialCwd => this._proxy.$sendProcessProperty(id, { type: ProcessPropertyType.InitialCwd, value: initialCwd }));
750 }
752 > public $acceptProcessRequestCwd(id: number): void {
753 this._terminalProcesses.get(id)?.getCwd().then(cwd => this._proxy.$sendProcessProperty(id, { type: ProcessPropertyType.Cwd, value: cwd }));
754 }
756 > public $acceptProcessRequestLatency(id: number): Promise<number> {
757 return Promise.resolve(id);
758 }
760 >
761 > public registerProfileProvider(extension: IExtensionDescription, id: string, provider: vscode.TerminalProfileProvider): vscode.Disposable {
762 if (this._profileProviders.has(id)) {
763 throw new Error(`Terminal profile provider "${id}" already registered`);
770 });
771 }
773 > public registerTerminalCompletionProvider(extension: IExtensionDescription, provider: vscode.TerminalCompletionProvider<TerminalCompletionItem>, ...triggerCharacters: string[]): vscode.Disposable {
774 if (this._completionProviders.has(extension.identifier.value)) {
775 throw new Error(`Terminal completion provider "${extension.identifier.value}" already registered`);
782 });
783 }
785 > public async $provideTerminalCompletions(id: string, options: ITerminalCompletionContextDto): Promise<TerminalCompletionListDto | undefined> {
786 const token = new CancellationTokenSource().token;
787 if (token.isCancellationRequested || !this.activeTerminal) {
801 return TerminalCompletionList.from(completions, pathSeparator);
802 }
804 > public $acceptTerminalShellType(id: number, shellType: TerminalShellType | undefined): void {
805 const terminal = this.getTerminalById(id);
806 if (terminal?.setShellType(shellType)) {
808 }
809 }
811 > public registerTerminalQuickFixProvider(id: string, extensionId: string, provider: vscode.TerminalQuickFixProvider): vscode.Disposable {
812 if (this._quickFixProviders.has(id)) {
813 throw new Error(`Terminal quick fix provider "${id}" is already registered`);
820 });
821 }
823 > public async $provideTerminalQuickFixes(id: string, matchResult: TerminalCommandMatchResultDto): Promise<(ITerminalQuickFixTerminalCommandDto | ITerminalQuickFixOpenerDto | ICommandDto)[] | ITerminalQuickFixTerminalCommandDto | ITerminalQuickFixOpenerDto | ICommandDto | undefined> {
824 const token = new CancellationTokenSource().token;
825 if (token.isCancellationRequested) {
853 return result;
854 }
856 > public async $createContributedProfileTerminal(id: string, options: ICreateContributedTerminalProfileOptions): Promise<void> {
857 const token = new CancellationTokenSource().token;
858 const profileProviderData = this._profileProviders.get(id);
893 this.createTerminalFromOptions(profileOptions, options);
894 }
896 > public registerLinkProvider(provider: vscode.TerminalLinkProvider): vscode.Disposable {
897 this._linkProviders.add(provider);
898 if (this._linkProviders.size === 1) {
906 });
907 }
909 > public async $provideLinks(terminalId: number, line: string): Promise<ITerminalLinkDto[]> {
910 const terminal = this.getTerminalById(terminalId);
911 if (!terminal) {
969 return result;
970 }
972 > $activateLink(terminalId: number, linkId: number): void {
973 const cachedLink = this._terminalLinkCache.get(terminalId)?.get(linkId);
974 if (!cachedLink) {
977 cachedLink.provider.handleTerminalLink(cachedLink.link);
978 }
980 > private _onProcessExit(id: number, exitCode: number | undefined): void {
981 this._bufferer.stopBuffering(id);
982
994 this._proxy.$sendProcessExit(id, exitCode);
995 }
997 > public getTerminalById(id: number): ExtHostTerminal | null {
998 return this._getTerminalObjectById(this._terminals, id);
999 }
1001 > public getTerminalIdByApiObject(terminal: vscode.Terminal): number | null {
1002 const index = this._terminals.findIndex(item => {
1003 return item.value === terminal;
1005 return index >= 0 ? index : null;
1006 }
1008 > private _getTerminalObjectById<T extends ExtHostTerminal>(array: T[], id: number): T | null {
1009 const index = this._getTerminalObjectIndexById(array, id);
1010 return index !== null ? array[index] : null;
1011 }
1013 > private _getTerminalObjectIndexById<T extends ExtHostTerminal>(array: T[], id: ExtHostTerminalIdentifier): number | null {
1014 const index = array.findIndex(item => {
1015 return item._id === id;
1017 return index >= 0 ? index : null;
1018 }
1020 > public getEnvironmentVariableCollection(extension: IExtensionDescription): IEnvironmentVariableCollection {
1021 let collection = this._environmentVariableCollections.get(extension.identifier.value);
1022 if (!collection) {
1026 return collection.getScopedEnvironmentVariableCollection(undefined);
1027 }
1029 > private _syncEnvironmentVariableCollection(extensionIdentifier: string, collection: UnifiedEnvironmentVariableCollection): void {
1030 const serialized = serializeEnvironmentVariableCollection(collection.map);
1031 const serializedDescription = serializeEnvironmentDescriptionMap(collection.descriptionMap);
1032 this._proxy.$setEnvironmentVariableCollection(extensionIdentifier, collection.persistent, serialized.length === 0 ? undefined : serialized, serializedDescription);
1033 }
1035 > public $initEnvironmentVariableCollections(collections: [string, ISerializableEnvironmentVariableCollection][]): void {
1036 collections.forEach(entry => {
1037 const extensionIdentifier = entry[0];
1040 });
1041 }
1043 > public $acceptDefaultProfile(profile: ITerminalProfile, automationProfile: ITerminalProfile): void {
1044 const oldProfile = this._defaultProfile;
1045 this._defaultProfile = profile;
1049 }
1050 }
1052 > private _setEnvironmentVariableCollection(extensionIdentifier: string, collection: UnifiedEnvironmentVariableCollection): void {
1053 this._environmentVariableCollections.set(extensionIdentifier, collection);
1054 this._register(collection.onDidChangeCollection(() => {
1060 }));
1061 }
1063 >
1064 > /**
1065 > * Unified environment variable collection carrying information for all scopes, for a specific extension.
1066 > */
1067 > class UnifiedEnvironmentVariableCollection extends Disposable {
1068 > readonly map: Map<string, IEnvironmentVariableMutator> = new Map();
1069 > private readonly scopedCollections: Map<string, ScopedEnvironmentVariableCollection> = new Map();
1070 > readonly descriptionMap: Map<string, IEnvironmentVariableCollectionDescription> = new Map();
1071 > private _persistent: boolean = true;
1072 >
1073 > public get persistent(): boolean { return this._persistent; }
1074 > public set persistent(value: boolean) {
1075 this._persistent = value;
1076 this._onDidChangeCollection.fire();
1077 }
1079 > protected readonly _onDidChangeCollection: Emitter<void> = this._register(new Emitter<void>());
1080 > get onDidChangeCollection(): Event<void> { return this._onDidChangeCollection && this._onDidChangeCollection.event; }
1081 >
1082 > constructor(
1083 serialized?: ISerializableEnvironmentVariableCollection
1084 ) {
1086 this.map = new Map(serialized);
1087 }
1089 > getScopedEnvironmentVariableCollection(scope: vscode.EnvironmentVariableScope | undefined): IEnvironmentVariableCollection {
1090 const scopedCollectionKey = this.getScopeKey(scope);
1091 let scopedCollection = this.scopedCollections.get(scopedCollectionKey);
1097 return scopedCollection;
1098 }
1100 > replace(variable: string, value: string, options: vscode.EnvironmentVariableMutatorOptions | undefined, scope: vscode.EnvironmentVariableScope | undefined): void {
1101 this._setIfDiffers(variable, { value, type: EnvironmentVariableMutatorType.Replace, options: options ?? { applyAtProcessCreation: true }, scope });
1102 }
1104 > append(variable: string, value: string, options: vscode.EnvironmentVariableMutatorOptions | undefined, scope: vscode.EnvironmentVariableScope | undefined): void {
1105 this._setIfDiffers(variable, { value, type: EnvironmentVariableMutatorType.Append, options: options ?? { applyAtProcessCreation: true }, scope });
1106 }
1108 > prepend(variable: string, value: string, options: vscode.EnvironmentVariableMutatorOptions | undefined, scope: vscode.EnvironmentVariableScope | undefined): void {
1109 this._setIfDiffers(variable, { value, type: EnvironmentVariableMutatorType.Prepend, options: options ?? { applyAtProcessCreation: true }, scope });
1110 }
1112 > private _setIfDiffers(variable: string, mutator: vscode.EnvironmentVariableMutator & { scope: vscode.EnvironmentVariableScope | undefined }): void {
1113 if (mutator.options && mutator.options.applyAtProcessCreation === false && !mutator.options.applyAtShellIntegration) {
1114 throw new Error('EnvironmentVariableMutatorOptions must apply at either process creation or shell integration');
1140 }
1141 }
1143 > get(variable: string, scope: vscode.EnvironmentVariableScope | undefined): vscode.EnvironmentVariableMutator | undefined {
1144 const key = this.getKey(variable, scope);
1145 const value = this.map.get(key);
1147 return value ? convertMutator(value) : undefined;
1148 }
1150 > private getKey(variable: string, scope: vscode.EnvironmentVariableScope | undefined) {
1151 const scopeKey = this.getScopeKey(scope);
1152 return scopeKey.length ? `${variable}:::${scopeKey}` : variable;
1153 }
1155 > private getScopeKey(scope: vscode.EnvironmentVariableScope | undefined): string {
1156 return this.getWorkspaceKey(scope?.workspaceFolder) ?? '';
1157 }
1159 > private getWorkspaceKey(workspaceFolder: vscode.WorkspaceFolder | undefined): string | undefined {
1160 return workspaceFolder ? workspaceFolder.uri.toString() : undefined;
1161 }
1163 > public getVariableMap(scope: vscode.EnvironmentVariableScope | undefined): Map<string, vscode.EnvironmentVariableMutator> {
1164 const map = new Map<string, vscode.EnvironmentVariableMutator>();
1165 for (const [_, value] of this.map) {
1170 return map;
1171 }
1173 > delete(variable: string, scope: vscode.EnvironmentVariableScope | undefined): void {
1174 const key = this.getKey(variable, scope);
1175 this.map.delete(key);
1176 this._onDidChangeCollection.fire();
1177 }
1179 > clear(scope: vscode.EnvironmentVariableScope | undefined): void {
1180 if (scope?.workspaceFolder) {
1181 for (const [key, mutator] of this.map) {
1191 this._onDidChangeCollection.fire();
1192 }
1194 > setDescription(description: string | vscode.MarkdownString | undefined, scope: vscode.EnvironmentVariableScope | undefined): void {
1195 const key = this.getScopeKey(scope);
1196 const current = this.descriptionMap.get(key);
1208 }
1209 }
1211 > public getDescription(scope: vscode.EnvironmentVariableScope | undefined): string | vscode.MarkdownString | undefined {
1212 const key = this.getScopeKey(scope);
1213 return this.descriptionMap.get(key)?.description;
1214 }
1216 > private clearDescription(scope: vscode.EnvironmentVariableScope | undefined): void {
1217 const key = this.getScopeKey(scope);
1218 this.descriptionMap.delete(key);
1219 }
1221 >
1222 > class ScopedEnvironmentVariableCollection implements IEnvironmentVariableCollection {
1223 > public get persistent(): boolean { return this.collection.persistent; }
1224 > public set persistent(value: boolean) {
1225 this.collection.persistent = value;
1226 }
1228 > protected readonly _onDidChangeCollection = new Emitter<void>();
1229 > get onDidChangeCollection(): Event<void> { return this._onDidChangeCollection && this._onDidChangeCollection.event; }
1230 >
1231 > constructor(
1232 private readonly collection: UnifiedEnvironmentVariableCollection,
1233 private readonly scope: vscode.EnvironmentVariableScope | undefined
1234 ) {
1235 }
1237 > getScoped(scope: vscode.EnvironmentVariableScope | undefined) {
1238 return this.collection.getScopedEnvironmentVariableCollection(scope);
1239 }
1241 > replace(variable: string, value: string, options?: vscode.EnvironmentVariableMutatorOptions | undefined): void {
1242 this.collection.replace(variable, value, options, this.scope);
1243 }
1245 > append(variable: string, value: string, options?: vscode.EnvironmentVariableMutatorOptions | undefined): void {
1246 this.collection.append(variable, value, options, this.scope);
1247 }
1249 > prepend(variable: string, value: string, options?: vscode.EnvironmentVariableMutatorOptions | undefined): void {
1250 this.collection.prepend(variable, value, options, this.scope);
1251 }
1253 > get(variable: string): vscode.EnvironmentVariableMutator | undefined {
1254 return this.collection.get(variable, this.scope);
1255 }
1257 > forEach(callback: (variable: string, mutator: vscode.EnvironmentVariableMutator, collection: vscode.EnvironmentVariableCollection) => unknown, thisArg?: unknown): void {
1258 this.collection.getVariableMap(this.scope).forEach((value, variable) => callback.call(thisArg, variable, value, this), this.scope);
1259 }
1261 > [Symbol.iterator](): IterableIterator<[variable: string, mutator: vscode.EnvironmentVariableMutator]> {
1262 return this.collection.getVariableMap(this.scope).entries();
1263 }
1265 > delete(variable: string): void {
1266 this.collection.delete(variable, this.scope);
1267 this._onDidChangeCollection.fire(undefined);
1268 }
1270 > clear(): void {
1271 this.collection.clear(this.scope);
1272 }
1274 > set description(description: string | vscode.MarkdownString | undefined) {
1275 this.collection.setDescription(description, this.scope);
1276 }
1278 > get description(): string | vscode.MarkdownString | undefined {
1279 return this.collection.getDescription(this.scope);
1280 }
1282 >
1283 > export class WorkerExtHostTerminalService extends BaseExtHostTerminalService {
1284 >
1285 > private readonly _hasRemoteAuthority: boolean;
1286 >
1287 > constructor(
1288 @IExtHostCommands extHostCommands: IExtHostCommands,
1289 @IExtHostRpcService extHostRpc: IExtHostRpcService,
1293 this._hasRemoteAuthority = !!initData.remote.authority;
1294 }
1296 > public createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal {
1297 if (!this._hasRemoteAuthority) {
1298 throw new NotSupportedError();
1300 return this.createTerminalFromOptions({ name, shellPath, shellArgs });
1301 }
1303 > public createTerminalFromOptions(options: vscode.TerminalOptions, internalOptions?: ITerminalInternalOptions): vscode.Terminal {
1304 if (!this._hasRemoteAuthority) {
1305 throw new NotSupportedError();
1310 return terminal.value;
1311 }
1313 >
1314 function asTerminalIcon(iconPath?: vscode.Uri | { light: vscode.Uri; dark: vscode.Uri } | vscode.ThemeIcon): TerminalIcon | undefined {
1315 if (!iconPath || typeof iconPath === 'string') {
1326 };
1327 }
1329 function asTerminalColor(color?: vscode.ThemeColor): ThemeColor | undefined {
1330 return ThemeColor.isThemeColor(color) ? color as ThemeColor : undefined;
1331 }
1333 function convertMutator(mutator: IEnvironmentVariableMutator): vscode.EnvironmentVariableMutator {
1334 const newMutator = { ...mutator };
src/vs/workbench/api/common/extHostMcp.ts 422 covered LOC · 61 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostMcp.ts
2 > * Copyright (c) Microsoft 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 vscode from 'vscode';
7 > import { DeferredPromise, raceCancellationError, Sequencer, timeout } from '../../../base/common/async.js';
8 > import { CancellationToken, CancellationTokenSource } from '../../../base/common/cancellation.js';
9 > import { CancellationError } from '../../../base/common/errors.js';
10 > import { Emitter, Event } from '../../../base/common/event.js';
11 > import { Disposable, DisposableMap, DisposableStore, IDisposable, toDisposable } from '../../../base/common/lifecycle.js';
12 > import { AUTH_SCOPE_SEPARATOR, fetchAuthorizationServerMetadata, fetchResourceMetadata, getDefaultMetadataForUrl, IAuthorizationProtectedResourceMetadata, IAuthorizationServerMetadata, parseWWWAuthenticateHeader, scopesMatch } from '../../../base/common/oauth.js';
13 > import { SSEParser } from '../../../base/common/sseParser.js';
14 > import { URI, UriComponents } from '../../../base/common/uri.js';
15 > import { vArray, vNumber, vObj, vObjAny, vOptionalProp, vString } from '../../../base/common/validation.js';
16 > import { ConfigurationTarget } from '../../../platform/configuration/common/configuration.js';
17 > import { ExtensionIdentifier, IExtensionDescription } from '../../../platform/extensions/common/extensions.js';
18 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
19 > import { canLog, ILogService, LogLevel } from '../../../platform/log/common/log.js';
20 > import product from '../../../platform/product/common/product.js';
21 > import { StorageScope } from '../../../platform/storage/common/storage.js';
22 > import { extensionPrefixedIdentifier, McpCollectionDefinition, McpConnectionState, McpServerDefinition, McpServerLaunch, McpServerStaticMetadata, McpServerStaticToolAvailability, McpServerTransportHTTP, McpServerTransportType, UserInteractionRequiredError } from '../../contrib/mcp/common/mcpTypes.js';
23 > import { MCP } from '../../contrib/mcp/common/modelContextProtocol.js';
24 > import { checkProposedApiEnabled, isProposedApiEnabled } from '../../services/extensions/common/extensions.js';
25 > import { ExtHostMcpShape, IMcpAuthenticationDetails, IAuthMetadataSource, IStartMcpOptions, MainContext, MainThreadMcpShape, IAuthResourceMetadataSource, IAuthServerMetadataSource } from './extHost.protocol.js';
26 > import { IExtHostInitDataService } from './extHostInitDataService.js';
27 > import { IExtHostRpcService } from './extHostRpcService.js';
28 > import * as Convert from './extHostTypeConverters.js';
29 > import { McpHttpServerDefinition, McpStdioServerDefinition, McpToolAvailability } from './extHostTypes.js';
30 > import { IExtHostVariableResolverProvider } from './extHostVariableResolverService.js';
31 > import { IExtHostWorkspace } from './extHostWorkspace.js';
32 >
33 > export const IExtHostMpcService = createDecorator<IExtHostMpcService>('IExtHostMpcService');
34 >
35 > export interface IExtHostMpcService extends ExtHostMcpShape {
36 > registerMcpConfigurationProvider(extension: IExtensionDescription, id: string, provider: vscode.McpServerDefinitionProvider): IDisposable;
37 >
38 > /** Event that fires when the set of MCP server definitions changes. */
39 > readonly onDidChangeMcpServerDefinitions: Event<void>;
40 >
41 > /** Returns all MCP server definitions known to the editor. */
42 > readonly mcpServerDefinitions: readonly vscode.McpServerDefinition[];
43 >
44 > /** Starts an MCP gateway that exposes MCP servers via HTTP endpoints. */
45 > startMcpGateway(chatSessionResource?: URI): Promise<vscode.McpGateway | undefined>;
46 > }
47 >
48 > const serverDataValidation = vObj({
49 > label: vString(),
50 > version: vOptionalProp(vString()),
51 > metadata: vOptionalProp(vObj({
52 > capabilities: vOptionalProp(vObjAny()),
53 > serverInfo: vOptionalProp(vObjAny()),
54 > tools: vOptionalProp(vArray(vObj({
55 > availability: vNumber(),
56 > definition: vObjAny(),
57 > }))),
58 > })),
59 > authentication: vOptionalProp(vObj({
60 > providerId: vString(),
61 > scopes: vArray(vString()),
62 > }))
63 > });
64 >
65 > // Can be validated with:
66 > // declare const _serverDataValidationTest: vscode.McpStdioServerDefinition | vscode.McpHttpServerDefinition;
67 > // const _serverDataValidationProd: ValidatorType<typeof serverDataValidation> = _serverDataValidationTest;
68 >
69 > export class ExtHostMcpService extends Disposable implements IExtHostMpcService {
70 > protected _proxy: MainThreadMcpShape;
71 > private readonly _initialProviderPromises = new Set<Promise<void>>();
72 > protected readonly _sseEventSources = this._register(new DisposableMap<number, McpHTTPHandle>());
73 > private readonly _unresolvedMcpServers = new Map</* collectionId */ string, {
74 > provider: vscode.McpServerDefinitionProvider;
75 > servers: vscode.McpServerDefinition[];
76 > }>();
77 >
78 > // MCP server definitions synced from main thread
79 > private readonly _onDidChangeMcpServerDefinitions = this._register(new Emitter<void>());
80 > readonly onDidChangeMcpServerDefinitions: Event<void> = this._onDidChangeMcpServerDefinitions.event;
81 > private _mcpServerDefinitions: readonly vscode.McpServerDefinition[] = [];
82 >
83 > // Active gateways with their server emitters for dynamic updates
84 > private readonly _activeGateways = new Map<string, {
85 > servers: vscode.McpGatewayServer[];
86 > onDidChangeServers: Emitter<readonly vscode.McpGatewayServer[]>;
87 > }>();
88 >
89 > constructor(
90 @IExtHostRpcService extHostRpc: IExtHostRpcService,
91 @ILogService protected readonly _logService: ILogService,
97 this._proxy = extHostRpc.getProxy(MainContext.MainThreadMcp);
98 }
100 > /** Returns all MCP server definitions known to the editor. */
101 > get mcpServerDefinitions(): readonly vscode.McpServerDefinition[] {
102 return this._mcpServerDefinitions;
103 }
105 > /** Called by main thread to notify that MCP server definitions have changed. */
106 > $onDidChangeMcpServerDefinitions(servers: McpServerDefinition.Serialized[]): void {
107 this._mcpServerDefinitions = servers.map(dto => Convert.McpServerDefinition.to(dto));
108 this._onDidChangeMcpServerDefinitions.fire();
109 }
111 > $startMcp(id: number, opts: IStartMcpOptions): void {
112 this._startMcp(id, McpServerLaunch.fromSerialized(opts.launch), opts.defaultCwd && URI.revive(opts.defaultCwd), opts.errorOnUserInteraction);
113 }
115 > protected _startMcp(id: number, launch: McpServerLaunch, _defaultCwd?: URI, errorOnUserInteraction?: boolean): void {
116 if (launch.type === McpServerTransportType.HTTP) {
117 this._sseEventSources.set(id, new McpHTTPHandle(id, launch, this._proxy, this._logService, errorOnUserInteraction));
121 throw new Error('not implemented');
122 }
124 > async $substituteVariables<T>(_workspaceFolder: UriComponents | undefined, value: T): Promise<T> {
125 const folderURI = URI.revive(_workspaceFolder);
126 const folder = folderURI && await this._workspaceService.resolveWorkspaceFolder(folderURI);
132 }, value) as T;
133 }
135 > $stopMcp(id: number): void {
136 this._sseEventSources.get(id)
137 ?.close()
138 .then(() => this._didClose(id));
139 }
141 > private _didClose(id: number) {
142 this._sseEventSources.deleteAndDispose(id);
143 }
145 > $sendMessage(id: number, message: string): void {
146 this._sseEventSources.get(id)?.send(message);
147 }
149 > async $waitForInitialCollectionProviders(): Promise<void> {
150 await Promise.all(this._initialProviderPromises);
151 }
153 > async $resolveMcpLaunch(collectionId: string, label: string): Promise<McpServerLaunch.Serialized | undefined> {
154 const rec = this._unresolvedMcpServers.get(collectionId);
155 if (!rec) {
168 return resolved ? Convert.McpServerDefinition.from(resolved) : undefined;
169 }
171 > /** {@link vscode.lm.registerMcpServerDefinitionProvider} */
172 > public registerMcpConfigurationProvider(extension: IExtensionDescription, id: string, provider: vscode.McpServerDefinitionProvider): IDisposable {
173 const store = new DisposableStore();
174
263 return store;
264 }
266 > /** {@link vscode.lm.startMcpGateway} */
267 > public async startMcpGateway(chatSessionResource?: URI): Promise<vscode.McpGateway | undefined> {
268 const result = await this._proxy.$startMcpGateway(chatSessionResource?.toJSON());
269 if (!result) {
290 };
291 }
293 > /** Called by main thread to notify that a gateway's server set has changed. */
294 > $onDidChangeGatewayServers(gatewayId: string, newServers: { label: string; address: UriComponents }[]): void {
295 const gateway = this._activeGateways.get(gatewayId);
296 if (!gateway) {
306 gateway.onDidChangeServers.fire(servers);
307 }
308 > } extHostMcp.ts
309 >
310 function stringifyError(err: unknown): string {
311 if (!(err instanceof Error)) {
320 return msg;
321 }
323 > const enum HttpMode {
324 > Unknown,
325 > Http,
326 > SSE,
327 > }
328 >
329 > type HttpModeT =
330 > | { value: HttpMode.Unknown }
331 > | { value: HttpMode.Http; sessionId: string | undefined }
332 > | { value: HttpMode.SSE; endpoint: string };
333 >
334 > const MAX_FOLLOW_REDIRECTS = 5;
335 > const REDIRECT_STATUS_CODES = [301, 302, 303, 307, 308];
336 > // MCP server URLs are restricted to http(s) at configuration time; the redirect
337 > // path must enforce the same so a Location header cannot reach unix://, pipe://,
338 > // file://, etc.
339 > const ALLOWED_REDIRECT_PROTOCOLS = new Set(['http:', 'https:']);
340 > // Credential-bearing headers that must not be replayed to a different origin
341 > // after a redirect (matches browser fetch / curl behavior). Compared case-insensitively.
342 > const CROSS_ORIGIN_STRIPPED_HEADERS = new Set(['authorization', 'cookie', 'proxy-authorization', 'mcp-session-id']);
343 >
344 function setHostHeader(headers: Record<string, string>, name: string, value: string): void {
345 for (const configuredName of Object.keys(headers)) {
350 headers[name] = value;
351 }
353 > /**
354 > * Implementation of both MCP HTTP Streaming as well as legacy SSE.
355 > *
356 > * The first request will POST to the endpoint, assuming HTTP streaming. If the
357 > * server is legacy SSE, it should return some 4xx status in that case,
358 > * and we'll automatically fall back to SSE and res
359 > */
360 > export class McpHTTPHandle extends Disposable {
361 > private readonly _requestSequencer = new Sequencer();
362 > private readonly _postEndpoint = new DeferredPromise<{ url: string; transport: McpServerTransportHTTP }>();
363 > private _mode: HttpModeT = { value: HttpMode.Unknown };
364 > private readonly _cts = new CancellationTokenSource();
365 > private readonly _abortCtrl = new AbortController();
366 > private _authMetadata?: AuthMetadata;
367 > private _didSendClose = false;
368 >
369 > constructor(
370 private readonly _id: number,
371 private readonly _launch: McpServerTransportHTTP,
382 this._proxy.$onDidChangeState(this._id, { state: McpConnectionState.Kind.Running });
383 }
385 > async send(message: string) {
386 try {
387 if (this._mode.value === HttpMode.Unknown) {
395 }
396 }
398 > async close() {
399 if (this._mode.value === HttpMode.Http && this._mode.sessionId && !this._didSendClose) {
400 this._didSendClose = true;
408 this._proxy.$onDidChangeState(this._id, { state: McpConnectionState.Kind.Stopped });
409 }
411 > private async _closeSession(sessionId: string) {
412 const headers: Record<string, string> = {
413 ...Object.fromEntries(this._launch.headers),
432 );
433 }
435 > private _send(message: string) {
436 if (this._mode.value === HttpMode.SSE) {
437 return this._sendLegacySSE(this._mode.endpoint, message);
440 }
441 }
443 > /**
444 > * Sends a streamable-HTTP request.
445 > * 1. Posts to the endpoint
446 > * 2. Updates internal state as needed. Falls back to SSE if appropriate.
447 > * 3. If the response body is empty, JSON, or a JSON stream, handle it appropriately.
448 > */
449 > private async _sendStreamableHttp(message: string, sessionId: string | undefined) {
450 const asBytes = new TextEncoder().encode(message) as Uint8Array<ArrayBuffer>;
451 const headers: Record<string, string> = {
511 await this._handleSuccessfulStreamableHttp(res, message);
512 }
514 > private async _sseFallbackWithMessage(message: string) {
515 const endpoint = await this._attachSSE();
516 if (endpoint) {
519 }
520 }
522 > private async _handleSuccessfulStreamableHttp(res: CommonResponse, message: string) {
523 if (res.status === 202) {
524 return; // no body
554 }
555 }
557 > /**
558 > * Attaches the SSE backchannel that streamable HTTP servers can use
559 > * for async notifications. This is a "MAY" support, so if the server gives
560 > * us a 4xx code, we'll stop trying to connect..
561 > */
562 > private async _attachStreamableBackchannel() {
563 let lastEventId: string | undefined;
564 let canReconnectAt: number | undefined;
629 }
630 }
632 > /**
633 > * Starts a legacy SSE attachment, where the SSE response is the session lifetime.
634 > * Unlike `_attachStreamableBackchannel`, this fails the server if it disconnects.
635 > */
636 > private async _attachSSE(): Promise<string | undefined> {
637 const postEndpoint = new DeferredPromise<string>();
638 const headers: Record<string, string> = {
676 return postEndpoint.p;
677 }
679 > /**
680 > * Sends a legacy SSE message to the server. The response is always empty and
681 > * is otherwise received in {@link _attachSSE}'s loop.
682 > */
683 > private async _sendLegacySSE(url: string, message: string) {
684 const asBytes = new TextEncoder().encode(message) as Uint8Array<ArrayBuffer>;
685 const headers: Record<string, string> = {
698 }
699 }
701 > /** Generic handle to pipe a response into an SSE parser. */
702 > private async _doSSE(parser: SSEParser, res: CommonResponse) {
703 if (!res.body) {
704 return;
724 } while (!chunk.done);
725 }
727 > private async _addAuthHeader(headers: Record<string, string>, options?: { forceNewRegistration?: boolean; errorOnUserInteraction?: boolean }) {
728 const errorOnUserInteraction = options?.errorOnUserInteraction ?? this._errorOnUserInteraction;
729 if (this._authMetadata) {
782 return headers;
783 }
785 > private _log(level: LogLevel, message: string) {
786 if (!this._store.isDisposed) {
787 this._proxy.$onDidPublishLog(this._id, level, message);
788 }
789 }
791 > private async _getErrText(res: CommonResponse) {
792 try {
793 return await res.text();
796 }
797 }
799 > /**
800 > * Helper method to perform fetch with authentication retry logic.
801 > * If the initial request returns an auth error and we don't have auth metadata,
802 > * it will populate the auth metadata and retry once.
803 > * If we already have auth metadata, check if the scopes changed and update them.
804 > */
805 > private async _fetchWithAuthRetry(mcpUrl: string, init: MinimalRequestInit, headers: Record<string, string>): Promise<CommonResponse> {
806 const doFetch = () => this._fetch(mcpUrl, init);
807
845 return res;
846 }
848 > private async _fetch(url: string, init: MinimalRequestInit): Promise<CommonResponse> {
849 setHostHeader(init.headers, 'user-agent', `${product.nameLong}/${product.version}`);
850
921 return response;
922 }
924 > protected _fetchInternal(url: string, init?: CommonRequestInit): Promise<CommonResponse> {
925 return fetch(url, init);
926 }
927 > } extHostMcp.ts
928 >
929 > interface MinimalRequestInit {
930 > method: string;
931 > headers: Record<string, string>;
932 > body?: Uint8Array<ArrayBuffer>;
933 > }
934 >
935 > export interface CommonRequestInit extends MinimalRequestInit {
936 > signal?: AbortSignal;
937 > redirect?: RequestRedirect;
938 > }
939 >
940 > export interface CommonResponse {
941 > status: number;
942 > statusText: string;
943 > headers: Headers;
944 > body?: ReadableStream | null;
945 > url: string;
946 > json(): Promise<any>;
947 > text(): Promise<string>;
948 > }
949 >
950 function isJSON(str: string): boolean {
951 try {
956 }
957 }
959 function isAuthStatusCode(status: number): boolean {
960 return status === 401 || status === 403;
961 }
963 >
964 > //#region AuthMetadata
965 >
966 > /**
967 > * Logger callback type for AuthMetadata operations.
968 > */
969 > export type AuthMetadataLogger = (level: LogLevel, message: string) => void;
970 >
971 > /**
972 > * Interface for authentication metadata that can be updated when scopes change.
973 > */
974 > export interface IAuthMetadata {
975 > readonly authorizationServer: URI;
976 > readonly serverMetadata: IAuthorizationServerMetadata;
977 > readonly resourceMetadata: IAuthorizationProtectedResourceMetadata | undefined;
978 > readonly scopes: string[] | undefined;
979 > /** Telemetry data about how auth metadata was discovered */
980 > readonly telemetry: IAuthMetadataSource;
981 >
982 > /**
983 > * Updates the scopes based on the WWW-Authenticate header in the response.
984 > * @param response The HTTP response containing potential scope challenges
985 > * @returns true if scopes were updated, false otherwise
986 > */
987 > update(responseHeaders: Headers): boolean;
988 > }
989 >
990 > /**
991 > * Concrete implementation of IAuthMetadata that manages OAuth authentication metadata.
992 > * Consumers should use {@link createAuthMetadata} to create instances.
993 > */
994 > class AuthMetadata implements IAuthMetadata {
995 > private _scopes: string[] | undefined;
996 >
997 > constructor(
998 > public readonly authorizationServer: URI, extHostMcp.ts
999 > public readonly serverMetadata: IAuthorizationServerMetadata,
1000 > public readonly resourceMetadata: IAuthorizationProtectedResourceMetadata | undefined,
1001 > scopes: string[] | undefined,
1002 > public readonly telemetry: IAuthMetadataSource,
1003 > private readonly _log: AuthMetadataLogger,
1004 > ) {
1005 > this._scopes = scopes;
1006 > }
1007 > extHostMcp.ts
1008 > get scopes(): string[] | undefined {
1009 > return this._scopes; extHostMcp.ts
1010 > }
1011 > extHostMcp.ts
1012 > update(responseHeaders: Headers): boolean {
1013 const scopesChallenge = this._parseScopesFromResponse(responseHeaders);
1014 if (!scopesMatch(scopesChallenge, this._scopes)) {
1019 return false;
1020 }
1021 > extHostMcp.ts
1022 > private _parseScopesFromResponse(responseHeaders: Headers): string[] | undefined {
1023 const authHeader = responseHeaders.get('WWW-Authenticate');
1024 if (!authHeader) {
1037 return undefined;
1038 }
1039 > } extHostMcp.ts
1040 >
1041 > /**
1042 > * Options for creating AuthMetadata.
1043 > */
1044 > export interface ICreateAuthMetadataOptions {
1045 > /** Headers to include when fetching metadata from the same origin as the resource server */
1046 > sameOriginHeaders?: Record<string, string>;
1047 > /** Fetch function to use for HTTP requests */
1048 > fetch: (url: string, init: MinimalRequestInit) => Promise<CommonResponse>;
1049 > /** Logger function for diagnostic output */
1050 > log: AuthMetadataLogger;
1051 > }
1052 >
1053 > /**
1054 > * Creates an AuthMetadata instance by discovering OAuth metadata from the server.
1055 > *
1056 > * This function:
1057 > * 1. Parses the WWW-Authenticate header for resource_metadata and scope challenges
1058 > * 2. Fetches OAuth protected resource metadata from well-known URIs or the challenge URL
1059 > * 3. Fetches authorization server metadata
1060 > * 4. Falls back to default metadata if discovery fails
1061 > *
1062 > * @param resourceUrl The resource server URL
1063 > * @param wwwAuthenticateValue The value of the WWW-Authenticate header from the original HTTP response
1064 > * @param options Configuration options including headers, fetch function, and logger
1065 > * @returns A new AuthMetadata instance
1066 > */
1067 > export async function createAuthMetadata( extHostMcp.ts
1068 > resourceUrl: string,
1069 > initialResponseHeaders: Headers,
1070 > options: ICreateAuthMetadataOptions
1071 > ): Promise<AuthMetadata> {
1072 > const { sameOriginHeaders, fetch, log } = options;
1073 >
1074 > // Track discovery sources for telemetry
1075 > let resourceMetadataSource = IAuthResourceMetadataSource.None;
1076 > let serverMetadataSource: IAuthServerMetadataSource | undefined;
1077 >
1078 > // Parse the WWW-Authenticate header for resource_metadata and scope challenges
1079 > const { resourceMetadataChallenge, scopesChallenge: scopesChallengeFromHeader } = parseWWWAuthenticateHeaderForChallenges(initialResponseHeaders.get('WWW-Authenticate') ?? undefined, log);
1080 >
1081 > // Fetch the resource metadata either from the challenge URL or from well-known URIs
1082 > let serverMetadataUrl: string | undefined;
1083 > let resource: IAuthorizationProtectedResourceMetadata | undefined;
1084 > let scopesChallenge = scopesChallengeFromHeader;
1085 >
1086 > try {
1087 > const { metadata, discoveryUrl, errors } = await fetchResourceMetadata(resourceUrl, resourceMetadataChallenge, {
1088 > sameOriginHeaders,
1089 > fetch: (url, init) => fetch(url, init as MinimalRequestInit)
1090 > });
1091 > for (const err of errors) { extHostMcp.ts
1092 log(LogLevel.Warning, `Error fetching resource metadata: ${err}`);
1093 }
1094 > log(LogLevel.Info, `Discovered resource metadata at ${discoveryUrl}`); extHostMcp.ts
1095 >
1096 > // Determine if resource metadata came from header or well-known
1097 > resourceMetadataSource = resourceMetadataChallenge ? IAuthResourceMetadataSource.Header : IAuthResourceMetadataSource.WellKnown; extHostMcp.ts
1098 >
1099 > // TODO:@TylerLeonhardt support multiple authorization servers
1100 > // Consider using one that has an auth provider first, over the dynamic flow
1101 > serverMetadataUrl = metadata.authorization_servers?.[0];
1102 > if (!serverMetadataUrl) {
1103 log(LogLevel.Warning, `No authorization_servers found in resource metadata ${discoveryUrl} - Is this resource metadata configured correctly?`);
1104 > } else { extHostMcp.ts
1105 > log(LogLevel.Info, `Using auth server metadata url: ${serverMetadataUrl}`);
1106 > serverMetadataSource = IAuthServerMetadataSource.ResourceMetadata;
1107 > }
1108 > scopesChallenge ??= metadata.scopes_supported;
1109 > resource = metadata;
1110 > } catch (e) { extHostMcp.ts
1111 log(LogLevel.Warning, `Could not fetch resource metadata: ${String(e)}`);
1112 }
1113 > extHostMcp.ts
1114 > const baseUrl = new URL(resourceUrl).origin;
1115 >
1116 > // If we are not given a resource_metadata, see if the well-known server metadata is available
1117 > // on the base url.
1118 > let additionalHeaders: Record<string, string> = {};
1119 > if (!serverMetadataUrl) {
1120 serverMetadataUrl = baseUrl;
1121 // Maintain the same origin headers when talking to the resource origin.
1124 }
1125 }
1126 > extHostMcp.ts
1127 > try {
1128 > log(LogLevel.Debug, `Fetching auth server metadata for: ${serverMetadataUrl} ...`);
1129 > const { metadata, discoveryUrl, errors } = await fetchAuthorizationServerMetadata(serverMetadataUrl, {
1130 > additionalHeaders,
1131 > fetch: (url, init) => fetch(url, init as MinimalRequestInit)
1132 > });
1133 > for (const err of errors) { extHostMcp.ts
1134 log(LogLevel.Warning, `Error fetching authorization server metadata: ${err}`);
1135 }
1136 > log(LogLevel.Info, `Discovered authorization server metadata at ${discoveryUrl}`); extHostMcp.ts
1137 >
1138 > // If serverMetadataSource is not yet defined, it means we fell back to baseUrl
1139 > // and successfully fetched from well-known
1140 > serverMetadataSource ??= IAuthServerMetadataSource.WellKnown;
1141 >
1142 > return new AuthMetadata(
1143 > URI.parse(serverMetadataUrl),
1144 > metadata,
1145 > resource,
1146 > scopesChallenge,
1147 > { resourceMetadataSource, serverMetadataSource },
1148 > log
1149 > );
1150 > } catch (e) { extHostMcp.ts
1151 log(LogLevel.Warning, `Error populating auth server metadata for ${serverMetadataUrl}: ${String(e)}`);
1152 }
1164 );
1165 }
1166 > extHostMcp.ts
1167 > /**
1168 > * Parses the WWW-Authenticate header for resource_metadata and scope challenges.
1169 > */
1170 > function parseWWWAuthenticateHeaderForChallenges( extHostMcp.ts
1171 > wwwAuthenticateValue: string | undefined,
1172 > log: AuthMetadataLogger
1173 > ): { resourceMetadataChallenge?: string; scopesChallenge?: string[] } {
1174 > if (!wwwAuthenticateValue) {
1175 return {};
1176 }
1177 > let resourceMetadataChallenge: string | undefined; extHostMcp.ts
1178 > let scopesChallenge: string[] | undefined;
1179 >
1180 > const challenges = parseWWWAuthenticateHeader(wwwAuthenticateValue);
1181 > for (const challenge of challenges) {
1182 > if (challenge.scheme === 'Bearer') {
1183 > if (!resourceMetadataChallenge && challenge.params['resource_metadata']) {
1184 resourceMetadataChallenge = challenge.params['resource_metadata'];
1185 log(LogLevel.Debug, `Found resource_metadata challenge in WWW-Authenticate header: ${resourceMetadataChallenge}`);
1186 }
1187 > if (!scopesChallenge && challenge.params['scope']) { extHostMcp.ts
1188 const scopes = challenge.params['scope'].split(AUTH_SCOPE_SEPARATOR).filter(s => s.trim().length);
1189 if (scopes.length) {
1192 }
1193 }
1194 > if (resourceMetadataChallenge && scopesChallenge) { extHostMcp.ts
1195 break;
1196 }
1197 > } extHostMcp.ts
1198 > }
1199 > return { resourceMetadataChallenge, scopesChallenge };
1200 > }
1201 > extHostMcp.ts
1202 > //#endregion
src/vs/platform/agentPlugins/common/pluginParsers.ts 410 covered LOC · 47 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- pluginParsers.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { parse as parseJSONC } from '../../../base/common/json.js';
7 > import { cloneAndChange, equals as objectEquals } from '../../../base/common/objects.js';
8 > import { isAbsolute } from '../../../base/common/path.js';
9 > import { basename, extname, isEqualOrParent, joinPath, normalizePath, isEqual as isURLEquals, dirname } from '../../../base/common/resources.js';
10 > import { escapeRegExpCharacters } from '../../../base/common/strings.js';
11 > import { hasKey, Mutable } from '../../../base/common/types.js';
12 > import { URI } from '../../../base/common/uri.js';
13 > import { IFileService } from '../../files/common/files.js';
14 > import { parseFrontMatter } from '../../../base/common/yaml.js';
15 > import { IMcpRemoteServerConfiguration, IMcpServerConfiguration, IMcpStdioServerConfiguration, McpServerType } from '../../mcp/common/mcpPlatformTypes.js';
16 > import { CustomizationType, McpServerStatus, type AgentCustomization, type HookCustomization, type McpServerCustomization, type RuleCustomization, type SkillCustomization } from '../../agentHost/common/state/protocol/state.js';
17 > import { DEFAULT_MCP_APP } from '../../agentHost/common/state/protocol/mcpAppDefaults.js';
18 > import { customizationId } from '../../agentHost/common/state/sessionState.js';
19 > import { readAgentPluginManifest } from './agentPluginParser.js';
20 >
21 > // ---------------------------------------------------------------------------
22 > // Types
23 > // ---------------------------------------------------------------------------
24 >
25 > /** A single hook command to execute. Platform resolution happens at conversion time. */
26 > export interface IParsedHookCommand {
27 > /** Cross-platform default command. */
28 > readonly command?: string;
29 > /** Windows-specific command. */
30 > readonly windows?: string;
31 > /** Linux-specific command. */
32 > readonly linux?: string;
33 > /** macOS-specific command. */
34 > readonly osx?: string;
35 > /** Working directory. */
36 > readonly cwd?: URI;
37 > /** Environment variables. */
38 > readonly env?: Record<string, string>;
39 > /** Timeout in seconds. */
40 > readonly timeout?: number;
41 > /** URI of the file this hook was defined in. */
42 > readonly sourceUri?: URI;
43 > }
44 >
45 > export namespace IParsedHookCommand {
46 > export function isEquals(a: IParsedHookCommand | undefined, b: IParsedHookCommand | undefined): boolean {
47 if (a === b) {
48 return true;
60 && isURLEquals(a.sourceUri, b.sourceUri);
61 }
63 >
64 > /** A group of hooks for a single lifecycle event. */
65 > export interface IParsedHookGroup {
66 > /** Canonical hook type identifier (e.g. `'SessionStart'`, `'PreToolUse'`). */
67 > readonly type: string;
68 > /** The commands to execute for this hook type. */
69 > readonly commands: readonly IParsedHookCommand[];
70 > /** URI where this hook is defined. */
71 > readonly uri: URI;
72 > /** Original key as it appears in the hook file. */
73 > readonly originalId: string;
74 > /**
75 > * Protocol-level projection of this hook group as a child customization.
76 > * Multiple groups parsed from the same file share the same `customization.id`
77 > * so consumers can dedupe by id when collecting customizations.
78 > */
79 > readonly customization: HookCustomization;
80 > }
81 >
82 > export interface IMcpServerDefinition {
83 > readonly name: string;
84 > readonly configuration: IMcpServerConfiguration;
85 > readonly uri: URI;
86 > /** Protocol-level projection of this MCP server as a child customization. */
87 > readonly customization: McpServerCustomization;
88 > }
89 >
90 > /** A named resource (skill, agent, command, or instruction) within a plugin. */
91 > export interface INamedPluginResource {
92 > readonly uri: URI;
93 > readonly name: string;
94 > /**
95 > * Optional short description, populated for resources whose readers
96 > * parse it from the file's YAML frontmatter (e.g. agents).
97 > */
98 > readonly description?: string;
99 > }
100 >
101 > /** A parsed agent paired with its protocol-level child customization. */
102 > export interface IParsedAgent extends INamedPluginResource {
103 > readonly customization: AgentCustomization;
104 > }
105 >
106 > /** A parsed skill paired with its protocol-level child customization. */
107 > export interface IParsedSkill extends INamedPluginResource {
108 > readonly customization: SkillCustomization;
109 > }
110 >
111 > /** A parsed rule (instruction) paired with its protocol-level child customization. */
112 > export interface IParsedRule extends INamedPluginResource {
113 > readonly customization: RuleCustomization;
114 > }
115 >
116 > /** The result of parsing a single plugin directory. */
117 > export interface IParsedPlugin {
118 > readonly format: PluginFormat;
119 > readonly hooks: readonly IParsedHookGroup[];
120 > readonly mcpServers: readonly IMcpServerDefinition[];
121 > readonly skills: readonly IParsedSkill[];
122 > readonly agents: readonly IParsedAgent[];
123 > readonly instructions: readonly IParsedRule[];
124 > }
125 >
126 > // ---------------------------------------------------------------------------
127 > // Plugin format detection
128 > // ---------------------------------------------------------------------------
129 >
130 > export const enum PluginFormat {
131 > Copilot,
132 > Claude,
133 > OpenPlugin,
134 > AgentPlugin,
135 > }
136 >
137 > export interface IPluginFormatConfig {
138 > readonly format: PluginFormat;
139 > readonly manifestPath: string;
140 > readonly hookConfigPath: string;
141 > readonly componentPaths?: Readonly<Partial<Record<PluginComponent, string | false>>>;
142 > readonly requiresManifest?: boolean;
143 > readonly pluginRootTokens: readonly string[];
144 > readonly pluginRootEnvVars: readonly string[];
145 > /** Parses hooks from a JSON object using the format's conventions. */
146 > parseHooks(hookUri: URI, json: unknown, pluginUri: URI, workspaceRoot: URI | undefined, userHome: URI): IParsedHookGroup[];
147 > }
148 >
149 > export type PluginComponent = 'commands' | 'skills' | 'agents' | 'rules' | 'hooks' | 'mcpServers';
150 >
151 > const COPILOT_FORMAT: IPluginFormatConfig = {
152 > format: PluginFormat.Copilot,
153 > manifestPath: 'plugin.json',
154 > hookConfigPath: 'hooks.json',
155 > pluginRootTokens: ['${PLUGIN_ROOT}', '${CLAUDE_PLUGIN_ROOT}'],
156 > pluginRootEnvVars: ['PLUGIN_ROOT', 'CLAUDE_PLUGIN_ROOT'],
157 > parseHooks(hookUri, json, _pluginUri, workspaceRoot, userHome) {
158 return parseHooksJson(hookUri, json, workspaceRoot, userHome);
159 },
160 > }; pluginParsers.ts
161 >
162 > const CLAUDE_FORMAT: IPluginFormatConfig = {
163 > format: PluginFormat.Claude,
164 > manifestPath: '.claude-plugin/plugin.json',
165 > hookConfigPath: 'hooks/hooks.json',
166 > pluginRootTokens: ['${PLUGIN_ROOT}', '${CLAUDE_PLUGIN_ROOT}'],
167 > pluginRootEnvVars: ['PLUGIN_ROOT', 'CLAUDE_PLUGIN_ROOT'],
168 > parseHooks(hookUri, json, pluginUri, workspaceRoot, userHome) {
169 return interpolateHookPluginRoot(hookUri, json, pluginUri, workspaceRoot, userHome, '${CLAUDE_PLUGIN_ROOT}', 'CLAUDE_PLUGIN_ROOT');
170 },
171 > }; pluginParsers.ts
172 >
173 > const OPEN_PLUGIN_FORMAT: IPluginFormatConfig = {
174 > format: PluginFormat.OpenPlugin,
175 > manifestPath: '.plugin/plugin.json',
176 > hookConfigPath: 'hooks/hooks.json',
177 > pluginRootTokens: ['${PLUGIN_ROOT}', '${CLAUDE_PLUGIN_ROOT}'],
178 > pluginRootEnvVars: ['PLUGIN_ROOT', 'CLAUDE_PLUGIN_ROOT'],
179 > parseHooks(hookUri, json, pluginUri, workspaceRoot, userHome) {
180 return interpolateHookPluginRoot(hookUri, json, pluginUri, workspaceRoot, userHome, '${PLUGIN_ROOT}', 'PLUGIN_ROOT');
181 },
182 > }; pluginParsers.ts
183 >
184 > const AGENT_PLUGIN_FORMAT: IPluginFormatConfig = {
185 > format: PluginFormat.AgentPlugin,
186 > manifestPath: 'plugin.json',
187 > hookConfigPath: '',
188 > componentPaths: {
189 > commands: false,
190 > skills: 'skills',
191 > agents: false,
192 > rules: false,
193 > hooks: false,
194 > mcpServers: 'mcp.json',
195 > },
196 > requiresManifest: true,
197 > pluginRootTokens: [],
198 > pluginRootEnvVars: [],
199 > parseHooks() {
200 return [];
201 },
202 > }; pluginParsers.ts
203 >
204 export async function detectPluginFormat(pluginUri: URI, fileService: IFileService): Promise<IPluginFormatConfig> {
205 if (await readAgentPluginManifest(pluginUri, fileService)) {
217 return COPILOT_FORMAT;
218 }
220 export async function readPluginManifest(pluginUri: URI, format: IPluginFormatConfig, fileService: IFileService): Promise<Record<string, unknown> | undefined> {
221 if (format.format === PluginFormat.AgentPlugin) {
226 return json && typeof json === 'object' && !Array.isArray(json) ? json as Record<string, unknown> : undefined;
227 }
229 > export function getPluginManifestComponent(format: IPluginFormatConfig, component: PluginComponent, manifest: Record<string, unknown> | undefined): unknown {
230 return format.componentPaths && Object.hasOwn(format.componentPaths, component) ? undefined : manifest?.[component];
231 }
233 > export function resolvePluginComponentDirs(
234 pluginUri: URI,
235 format: IPluginFormatConfig,
252 );
253 }
255 > // ---------------------------------------------------------------------------
256 > // Child customization helpers
257 > // ---------------------------------------------------------------------------
258 >
259 > /**
260 > * Mints a child-customization id from a source uri plus an optional opaque
261 > * disambiguator. Used when multiple customizations are declared inline in
262 > * a single file (e.g. two MCP servers in one `.mcp.json`, or two hook
263 > * lifecycle groups in one hook file).
264 > *
265 > * Percent-encodes any pre-existing `#` in the URI before appending the
266 > * disambiguating fragment so the resulting id can never collide with a
267 > * URI that happens to already contain a matching fragment.
268 > */
269 function buildChildId(uri: URI, disambiguator?: string): string {
270 const base = customizationId(uri.toString());
274 return `${base.replace(/#/g, '%23')}#${disambiguator}`;
275 }
277 function makeAgentCustomization(resource: INamedPluginResource): AgentCustomization {
278 const uri = resource.uri.toString();
285 };
286 }
288 function makeSkillCustomization(resource: INamedPluginResource): SkillCustomization {
289 const uri = resource.uri.toString();
296 };
297 }
299 function makeRuleCustomization(resource: INamedPluginResource): RuleCustomization {
300 const uri = resource.uri.toString();
307 };
308 }
310 function makeHookCustomization(hookUri: URI): HookCustomization {
311 return {
316 };
317 }
319 > /**
320 > * Builds the protocol {@link McpServerCustomization} for an MCP server
321 > * declared at `definitionUri` (the manifest / settings / `.mcp.json` file
322 > * the server is defined in). The id is disambiguated by server `name` so
323 > * multiple servers declared in one file get distinct ids, and the entry
324 > * carries {@link DEFAULT_MCP_APP} so MCP App support is advertised
325 > * consistently with every other MCP customization.
326 > *
327 > * The seed state is {@link McpServerStatus.Stopped}: a declared-but-not-yet
328 > * connected server has not been started by any SDK, so it must not claim to
329 > * be {@link McpServerStatus.Starting}. The live state is enriched from the
330 > * SDK's reported status once a session materializes.
331 > */
332 > export function makeMcpServerCustomization(definitionUri: URI, name: string): McpServerCustomization {
333 return {
334 type: CustomizationType.McpServer,
341 };
342 }
344 > // ---------------------------------------------------------------------------
345 > // Component path config
346 > // ---------------------------------------------------------------------------
347 >
348 > export interface IComponentPathConfig {
349 > readonly paths: readonly string[];
350 > readonly exclusive: boolean;
351 > }
352 >
353 > const emptyComponentPathConfig: IComponentPathConfig = { paths: [], exclusive: false };
354 >
355 > /**
356 > * Parses a manifest component path field into a normalized config.
357 > * Supports `undefined`, `string`, `string[]`, and `{ paths: string[], exclusive?: boolean }`.
358 > */
359 > export function parseComponentPathConfig(raw: unknown): IComponentPathConfig {
360 if (raw === undefined || raw === null) {
361 return emptyComponentPathConfig;
389 return emptyComponentPathConfig;
390 }
392 > /**
393 > * Resolves the directories to scan for a given component type, combining
394 > * the default directory with any custom paths from the manifest config.
395 > * Paths that resolve outside the boundary are silently ignored.
396 > * @param boundaryUri The outermost directory that resolved paths must stay within. Defaults to {@link pluginUri}.
397 > */
398 > export function resolveComponentDirs(pluginUri: URI, defaultDir: string, config: IComponentPathConfig, boundaryUri?: URI): readonly URI[] {
399 const boundary = (boundaryUri && isEqualOrParent(pluginUri, boundaryUri)) ? boundaryUri : pluginUri;
400 const dirs: URI[] = [];
410 return dirs;
411 }
413 > // ---------------------------------------------------------------------------
414 > // MCP server helpers
415 > // ---------------------------------------------------------------------------
416 >
417 > /**
418 > * Extracts the MCP server map from a raw JSON value. Accepts both the
419 > * wrapped format `{ mcpServers: { … } }` and the flat format.
420 > */
421 > export function resolveMcpServersMap(raw: unknown): Record<string, unknown> | undefined {
422 if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
423 return undefined;
428 : obj;
429 }
431 > /**
432 > * Normalizes a raw JSON value into a typed MCP server configuration.
433 > */
434 > export function normalizeMcpServerConfiguration(rawConfig: unknown): IMcpServerConfiguration | undefined {
435 if (!rawConfig || typeof rawConfig !== 'object') {
436 return undefined;
477 return undefined;
478 }
480 > /**
481 > * Characters in a file path that require shell quoting to prevent
482 > * word splitting or interpretation by common shells.
483 > */
484 > const shellUnsafeChars = /[\s&|<>()^;!`"']/;
485 >
486 > /**
487 > * Replaces a plugin-root token in a shell command string with the
488 > * given fsPath, shell-quoting if the path contains special characters.
489 > */
490 > export function shellQuotePluginRootInCommand(command: string, fsPath: string, token: string) {
491 if (!command.includes(token)) {
492 return command;
511 });
512 }
514 > /**
515 > * Replaces plugin-root token references in MCP server definition string fields
516 > * with the plugin root filesystem path.
517 > */
518 > export function interpolateMcpPluginRoot(
519 def: IMcpServerDefinition,
520 fsPath: string,
562 return { name: def.name, configuration: interpolated, uri: def.uri, customization: def.customization };
563 }
565 > /**
566 > * Regex matching bare `${VAR_NAME}` references (uppercase only) that are NOT
567 > * using VS Code's `${env:VAR}` colon-delimited syntax.
568 > */
569 > const BARE_ENV_VAR_RE = /\$\{(?![A-Za-z]+:)([A-Z_][A-Z0-9_]*)\}/g;
570 >
571 > /**
572 > * Converts bare `${VAR}` environment-variable references to VS Code `${env:VAR}` syntax.
573 > */
574 > export function convertBareEnvVarsToVsCodeSyntax(
575 def: IMcpServerDefinition,
576 ): IMcpServerDefinition {
586 });
587 }
589 > // ---------------------------------------------------------------------------
590 > // Hook parsing helpers
591 > // ---------------------------------------------------------------------------
592 >
593 > /**
594 > * Maps known hook type identifiers from all formats (VS Code PascalCase,
595 > * Copilot CLI camelCase, Claude PascalCase) to canonical identifiers.
596 > */
597 > const HOOK_TYPE_MAP: Record<string, string> = {
598 > // PascalCase (VS Code / Claude)
599 > 'SessionStart': 'SessionStart',
600 > 'SessionEnd': 'SessionEnd',
601 > 'UserPromptSubmit': 'UserPromptSubmit',
602 > 'PreToolUse': 'PreToolUse',
603 > 'PostToolUse': 'PostToolUse',
604 > 'PreCompact': 'PreCompact',
605 > 'SubagentStart': 'SubagentStart',
606 > 'SubagentStop': 'SubagentStop',
607 > 'Stop': 'Stop',
608 > 'ErrorOccurred': 'ErrorOccurred',
609 > // camelCase (GitHub Copilot CLI)
610 > 'sessionStart': 'SessionStart',
611 > 'sessionEnd': 'SessionEnd',
612 > 'userPromptSubmitted': 'UserPromptSubmit',
613 > 'preToolUse': 'PreToolUse',
614 > 'postToolUse': 'PostToolUse',
615 > 'agentStop': 'Stop',
616 > 'subagentStop': 'SubagentStop',
617 > 'errorOccurred': 'ErrorOccurred',
618 > };
619 >
620 > /**
621 > * Normalizes a raw hook command object, validating structure and mapping
622 > * legacy `bash`/`powershell` fields to platform-specific overrides.
623 > */
624 function normalizeHookCommand(raw: Record<string, unknown>): IParsedHookCommand | undefined {
625 // Allow omitted type (Claude compatibility) — treat as 'command'
656 };
657 }
659 > /**
660 > * Resolves a raw hook command JSON object into a {@link IParsedHookCommand},
661 > * normalizing fields and resolving the working directory.
662 > */
663 function resolveHookCommand(raw: Record<string, unknown>, workspaceRoot: URI | undefined, userHome: URI): IParsedHookCommand | undefined {
664 const normalized = normalizeHookCommand(raw);
683 return { ...normalized, cwd: cwdUri };
684 }
686 > /**
687 > * Extracts hook commands from an item that may be a direct command object
688 > * or a nested structure with a `matcher` (Claude format).
689 > */
690 function extractHookCommands(item: unknown, workspaceRoot: URI | undefined, userHome: URI): IParsedHookCommand[] {
691 if (!item || typeof item !== 'object') {
717 return commands;
718 }
720 > /**
721 > * Parses hooks from a JSON object (any supported format).
722 > *
723 > * Handles Claude's `disableAllHooks` short-circuit, the `HOOK_TYPE_MAP`
724 > * canonicalization, and the nested `{ matcher, hooks: [...] }` command
725 > * form. Returns one {@link IParsedHookGroup} per recognized lifecycle
726 > * event; all groups parsed from the same file share a single
727 > * {@link IParsedHookGroup.customization} (keyed on `hookUri`), so callers
728 > * that only need the file-level customization can read it off any group.
729 > */
730 > export function parseHooksJson(
731 hookUri: URI,
732 json: unknown,
777 return result;
778 }
780 > /**
781 > * Applies plugin-root token interpolation to hook commands for
782 > * Claude and OpenPlugin formats.
783 > */
784 > export function interpolateHookPluginRoot(
785 hookUri: URI,
786 json: unknown,
834 return parseHooksJson(hookUri, cloneAndChange(json, replacer), workspaceRoot, userHome);
835 }
837 > // ---------------------------------------------------------------------------
838 > // Filesystem helpers
839 > // ---------------------------------------------------------------------------
840 >
841 export async function readJsonFile(uri: URI, fileService: IFileService): Promise<unknown | undefined> {
842 try {
847 }
848 }
850 export async function pathExists(resource: URI, fileService: IFileService): Promise<boolean> {
851 try {
856 }
857 }
859 > // ---------------------------------------------------------------------------
860 > // Component readers
861 > // ---------------------------------------------------------------------------
862 >
863 > const COMMAND_FILE_SUFFIX = '.md';
864 > const RULE_FILE_SUFFIX = '.mdc';
865 > const INSTRUCTION_FILE_SUFFIX = '.instructions.md';
866 >
867 export async function readSkills(
868 pluginRoot: URI,
931 return skills;
932 }
934 export async function readPluginSkills(pluginRoot: URI, dirs: readonly URI[], format: IPluginFormatConfig, fileService: IFileService): Promise<readonly INamedPluginResource[]> {
935 return readSkills(pluginRoot, dirs, fileService, format.format === PluginFormat.AgentPlugin
937 : undefined);
938 }
940 async function isResolvedWithin(root: URI, resource: URI, fileService: IFileService): Promise<boolean> {
941 try {
949 }
950 }
952 export async function readMarkdownComponents(dirs: readonly URI[], fileService: IFileService): Promise<readonly INamedPluginResource[]> {
953 const seen = new Set<string>();
989 return items;
990 }
992 function getInstructionFileName(resource: URI): string | undefined {
993 const fileName = basename(resource);
1001 return undefined;
1002 }
1004 > /**
1005 > * Reads rule/instruction files from plugin `rules` component directories.
1006 > *
1007 > * Open Plugins rules are conventionally `.mdc` files. We also accept
1008 > * `.instructions.md` for compatibility with VS Code-discovered instructions
1009 > * bundled as synthetic plugins.
1010 > */
1011 export async function readInstructionComponents(dirs: readonly URI[], fileService: IFileService): Promise<readonly INamedPluginResource[]> {
1012 const seen = new Set<string>();
1054 return items;
1055 }
1057 > /**
1058 > * Reads `.md` files in agent directories and enriches each entry with
1059 > * the optional `name` / `description` from YAML frontmatter. Falls back
1060 > * to the file-derived name when frontmatter is missing or unreadable.
1061 > */
1062 export async function readAgentComponents(dirs: readonly URI[], fileService: IFileService): Promise<readonly INamedPluginResource[]> {
1063 const files = await readMarkdownComponents(dirs, fileService);
1090 return result;
1091 }
1093 export async function parseAgentFile(uri: URI, fileService: IFileService): Promise<{ name: string; description?: string; userInvocable?: boolean }> {
1094 // Use regex to strip the trailing `.agent.md` or .md before parsing, so we can fall back to a cleaner name if frontmatter is missing or broken.
1105 }
1106 }
1108 export async function parseSkillFile(uri: URI, fileService: IFileService): Promise<{ name: string; description?: string; userInvokable?: boolean }> {
1109 try {
1118 }
1119 }
1121 export async function parseRuleFile(uri: URI, fileService: IFileService): Promise<{ name: string; description?: string; globs?: string[]; alwaysApply?: boolean }> {
1122 const nameFromFile = basename(uri).replace(/(\.instructions)?\.md$/i, '');
1133 }
1134 }
1136 async function readHooks(
1137 pluginUri: URI,
1152 return [];
1153 }
1155 async function readMcpServers(
1156 pluginUri: URI,
1173 return [...merged.values()].sort((a, b) => a.name.localeCompare(b.name));
1174 }
1176 export async function readPluginMcpServers(
1177 pluginUri: URI,
1182 return readMcpServers(pluginUri, paths, format, fileService);
1183 }
1185 > export function parseMcpServerDefinitionMap(
1186 definitionURI: URI,
1187 raw: unknown,
1219 return definitions;
1220 }
1222 > // ---------------------------------------------------------------------------
1223 > // Top-level parse function
1224 > // ---------------------------------------------------------------------------
1225 >
1226 > /**
1227 > * Parses a plugin directory to extract hooks, MCP servers, skills, agents,
1228 > * and instructions.
1229 > * This is the main entry point for the agent host to discover plugin contents.
1230 > */
1231 export async function parsePlugin(
1232 pluginUri: URI,
1292 };
1293 }
1295 > /** Pairs an agent {@link INamedPluginResource} with its protocol-level {@link AgentCustomization}. */
1296 > export function toParsedAgent(resource: INamedPluginResource): IParsedAgent {
1297 return { ...resource, customization: makeAgentCustomization(resource) };
1298 }
1300 > /** Pairs a skill {@link INamedPluginResource} with its protocol-level {@link SkillCustomization}. */
1301 > export function toParsedSkill(resource: INamedPluginResource): IParsedSkill {
1302 return { ...resource, customization: makeSkillCustomization(resource) };
1303 }
1305 function toParsedRule(resource: INamedPluginResource): IParsedRule {
1306 return { ...resource, customization: makeRuleCustomization(resource) };
src/vs/base/common/arrays.ts 404 covered LOC · 72 ranges

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- json.ts
2 > * Copyright (c) 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 ScanError {
7 > None = 0,
8 > UnexpectedEndOfComment = 1,
9 > UnexpectedEndOfString = 2,
10 > UnexpectedEndOfNumber = 3,
11 > InvalidUnicode = 4,
12 > InvalidEscapeCharacter = 5,
13 > InvalidCharacter = 6
14 > }
15 >
16 > export const enum SyntaxKind {
17 > OpenBraceToken = 1,
18 > CloseBraceToken = 2,
19 > OpenBracketToken = 3,
20 > CloseBracketToken = 4,
21 > CommaToken = 5,
22 > ColonToken = 6,
23 > NullKeyword = 7,
24 > TrueKeyword = 8,
25 > FalseKeyword = 9,
26 > StringLiteral = 10,
27 > NumericLiteral = 11,
28 > LineCommentTrivia = 12,
29 > BlockCommentTrivia = 13,
30 > LineBreakTrivia = 14,
31 > Trivia = 15,
32 > Unknown = 16,
33 > EOF = 17
34 > }
35 >
36 > /**
37 > * The scanner object, representing a JSON scanner at a position in the input string.
38 > */
39 > export interface JSONScanner {
40 > /**
41 > * Sets the scan position to a new offset. A call to 'scan' is needed to get the first token.
42 > */
43 > setPosition(pos: number): void;
44 > /**
45 > * Read the next token. Returns the token code.
46 > */
47 > scan(): SyntaxKind;
48 > /**
49 > * Returns the current scan position, which is after the last read token.
50 > */
51 > getPosition(): number;
52 > /**
53 > * Returns the last read token.
54 > */
55 > getToken(): SyntaxKind;
56 > /**
57 > * Returns the last read token value. The value for strings is the decoded string content. For numbers its of type number, for boolean it's true or false.
58 > */
59 > getTokenValue(): string;
60 > /**
61 > * The start offset of the last read token.
62 > */
63 > getTokenOffset(): number;
64 > /**
65 > * The length of the last read token.
66 > */
67 > getTokenLength(): number;
68 > /**
69 > * An error code of the last scan.
70 > */
71 > getTokenError(): ScanError;
72 > }
73 >
74 >
75 >
76 > export interface ParseError {
77 > error: ParseErrorCode;
78 > offset: number;
79 > length: number;
80 > }
81 >
82 > export const enum ParseErrorCode {
83 > InvalidSymbol = 1,
84 > InvalidNumberFormat = 2,
85 > PropertyNameExpected = 3,
86 > ValueExpected = 4,
87 > ColonExpected = 5,
88 > CommaExpected = 6,
89 > CloseBraceExpected = 7,
90 > CloseBracketExpected = 8,
91 > EndOfFileExpected = 9,
92 > InvalidCommentToken = 10,
93 > UnexpectedEndOfComment = 11,
94 > UnexpectedEndOfString = 12,
95 > UnexpectedEndOfNumber = 13,
96 > InvalidUnicode = 14,
97 > InvalidEscapeCharacter = 15,
98 > InvalidCharacter = 16
99 > }
100 >
101 > export type NodeType = 'object' | 'array' | 'property' | 'string' | 'number' | 'boolean' | 'null';
102 >
103 > export interface Node {
104 > readonly type: NodeType;
105 > readonly value?: any;
106 > readonly offset: number;
107 > readonly length: number;
108 > readonly colonOffset?: number;
109 > readonly parent?: Node;
110 > readonly children?: Node[];
111 > }
112 >
113 > export type Segment = string | number;
114 > export type JSONPath = Segment[];
115 >
116 > export interface Location {
117 > /**
118 > * The previous property key or literal value (string, number, boolean or null) or undefined.
119 > */
120 > previousNode?: Node;
121 > /**
122 > * The path describing the location in the JSON document. The path consists of a sequence strings
123 > * representing an object property or numbers for array indices.
124 > */
125 > path: JSONPath;
126 > /**
127 > * Matches the locations path against a pattern consisting of strings (for properties) and numbers (for array indices).
128 > * '*' will match a single segment, of any property name or index.
129 > * '**' will match a sequence of segments or no segment, of any property name or index.
130 > */
131 > matches: (patterns: JSONPath) => boolean;
132 > /**
133 > * If set, the location's offset is at a property key.
134 > */
135 > isAtPropertyKey: boolean;
136 > }
137 >
138 > export interface ParseOptions {
139 > disallowComments?: boolean;
140 > allowTrailingComma?: boolean;
141 > allowEmptyContent?: boolean;
142 > }
143 >
144 > export namespace ParseOptions {
145 > export const DEFAULT = {
146 > allowTrailingComma: true
147 > };
148 > }
149 >
150 > export interface JSONVisitor {
151 > /**
152 > * Invoked when an open brace is encountered and an object is started. The offset and length represent the location of the open brace.
153 > */
154 > onObjectBegin?: (offset: number, length: number) => void;
155 >
156 > /**
157 > * Invoked when a property is encountered. The offset and length represent the location of the property name.
158 > */
159 > onObjectProperty?: (property: string, offset: number, length: number) => void;
160 >
161 > /**
162 > * Invoked when a closing brace is encountered and an object is completed. The offset and length represent the location of the closing brace.
163 > */
164 > onObjectEnd?: (offset: number, length: number) => void;
165 >
166 > /**
167 > * Invoked when an open bracket is encountered. The offset and length represent the location of the open bracket.
168 > */
169 > onArrayBegin?: (offset: number, length: number) => void;
170 >
171 > /**
172 > * Invoked when a closing bracket is encountered. The offset and length represent the location of the closing bracket.
173 > */
174 > onArrayEnd?: (offset: number, length: number) => void;
175 >
176 > /**
177 > * Invoked when a literal value is encountered. The offset and length represent the location of the literal value.
178 > */
179 > onLiteralValue?: (value: any, offset: number, length: number) => void;
180 >
181 > /**
182 > * Invoked when a comma or colon separator is encountered. The offset and length represent the location of the separator.
183 > */
184 > onSeparator?: (character: string, offset: number, length: number) => void;
185 >
186 > /**
187 > * When comments are allowed, invoked when a line or block comment is encountered. The offset and length represent the location of the comment.
188 > */
189 > onComment?: (offset: number, length: number) => void;
190 >
191 > /**
192 > * Invoked on an error.
193 > */
194 > onError?: (error: ParseErrorCode, offset: number, length: number) => void;
195 > }
196 >
197 > /**
198 > * Creates a JSON scanner on the given text.
199 > * If ignoreTrivia is set, whitespaces or comments are ignored.
200 > */
201 > export function createScanner(text: string, ignoreTrivia: boolean = false): JSONScanner {
202
203 let pos = 0;
558 };
559 }
560 > json.ts
561 function isWhitespace(ch: number): boolean {
562 return ch === CharacterCodes.space || ch === CharacterCodes.tab || ch === CharacterCodes.verticalTab || ch === CharacterCodes.formFeed ||
564 ch === CharacterCodes.narrowNoBreakSpace || ch === CharacterCodes.mathematicalSpace || ch === CharacterCodes.ideographicSpace || ch === CharacterCodes.byteOrderMark;
565 }
566 > json.ts
567 function isLineBreak(ch: number): boolean {
568 return ch === CharacterCodes.lineFeed || ch === CharacterCodes.carriageReturn || ch === CharacterCodes.lineSeparator || ch === CharacterCodes.paragraphSeparator;
569 }
570 > json.ts
571 function isDigit(ch: number): boolean {
572 return ch >= CharacterCodes._0 && ch <= CharacterCodes._9;
573 }
574 > json.ts
575 > const enum CharacterCodes {
576 > nullCharacter = 0,
577 > maxAsciiCharacter = 0x7F,
578 >
579 > lineFeed = 0x0A, // \n
580 > carriageReturn = 0x0D, // \r
581 > lineSeparator = 0x2028,
582 > paragraphSeparator = 0x2029,
583 >
584 > // REVIEW: do we need to support this? The scanner doesn't, but our IText does. This seems
585 > // like an odd disparity? (Or maybe it's completely fine for them to be different).
586 > nextLine = 0x0085,
587 >
588 > // Unicode 3.0 space characters
589 > space = 0x0020, // " "
590 > nonBreakingSpace = 0x00A0, //
591 > enQuad = 0x2000,
592 > emQuad = 0x2001,
593 > enSpace = 0x2002,
594 > emSpace = 0x2003,
595 > threePerEmSpace = 0x2004,
596 > fourPerEmSpace = 0x2005,
597 > sixPerEmSpace = 0x2006,
598 > figureSpace = 0x2007,
599 > punctuationSpace = 0x2008,
600 > thinSpace = 0x2009,
601 > hairSpace = 0x200A,
602 > zeroWidthSpace = 0x200B,
603 > narrowNoBreakSpace = 0x202F,
604 > ideographicSpace = 0x3000,
605 > mathematicalSpace = 0x205F,
606 > ogham = 0x1680,
607 >
608 > _ = 0x5F,
609 > $ = 0x24,
610 >
611 > _0 = 0x30,
612 > _1 = 0x31,
613 > _2 = 0x32,
614 > _3 = 0x33,
615 > _4 = 0x34,
616 > _5 = 0x35,
617 > _6 = 0x36,
618 > _7 = 0x37,
619 > _8 = 0x38,
620 > _9 = 0x39,
621 >
622 > a = 0x61,
623 > b = 0x62,
624 > c = 0x63,
625 > d = 0x64,
626 > e = 0x65,
627 > f = 0x66,
628 > g = 0x67,
629 > h = 0x68,
630 > i = 0x69,
631 > j = 0x6A,
632 > k = 0x6B,
633 > l = 0x6C,
634 > m = 0x6D,
635 > n = 0x6E,
636 > o = 0x6F,
637 > p = 0x70,
638 > q = 0x71,
639 > r = 0x72,
640 > s = 0x73,
641 > t = 0x74,
642 > u = 0x75,
643 > v = 0x76,
644 > w = 0x77,
645 > x = 0x78,
646 > y = 0x79,
647 > z = 0x7A,
648 >
649 > A = 0x41,
650 > B = 0x42,
651 > C = 0x43,
652 > D = 0x44,
653 > E = 0x45,
654 > F = 0x46,
655 > G = 0x47,
656 > H = 0x48,
657 > I = 0x49,
658 > J = 0x4A,
659 > K = 0x4B,
660 > L = 0x4C,
661 > M = 0x4D,
662 > N = 0x4E,
663 > O = 0x4F,
664 > P = 0x50,
665 > Q = 0x51,
666 > R = 0x52,
667 > S = 0x53,
668 > T = 0x54,
669 > U = 0x55,
670 > V = 0x56,
671 > W = 0x57,
672 > X = 0x58,
673 > Y = 0x59,
674 > Z = 0x5A,
675 >
676 > ampersand = 0x26, // &
677 > asterisk = 0x2A, // *
678 > at = 0x40, // @
679 > backslash = 0x5C, // \
680 > bar = 0x7C, // |
681 > caret = 0x5E, // ^
682 > closeBrace = 0x7D, // }
683 > closeBracket = 0x5D, // ]
684 > closeParen = 0x29, // )
685 > colon = 0x3A, // :
686 > comma = 0x2C, // ,
687 > dot = 0x2E, // .
688 > doubleQuote = 0x22, // "
689 > equals = 0x3D, // =
690 > exclamation = 0x21, // !
691 > greaterThan = 0x3E, // >
692 > lessThan = 0x3C, // <
693 > minus = 0x2D, // -
694 > openBrace = 0x7B, // {
695 > openBracket = 0x5B, // [
696 > openParen = 0x28, // (
697 > percent = 0x25, // %
698 > plus = 0x2B, // +
699 > question = 0x3F, // ?
700 > semicolon = 0x3B, // ;
701 > singleQuote = 0x27, // '
702 > slash = 0x2F, // /
703 > tilde = 0x7E, // ~
704 >
705 > backspace = 0x08, // \b
706 > formFeed = 0x0C, // \f
707 > byteOrderMark = 0xFEFF,
708 > tab = 0x09, // \t
709 > verticalTab = 0x0B, // \v
710 > }
711 >
712 > interface NodeImpl extends Node {
713 > type: NodeType;
714 > value?: any;
715 > offset: number;
716 > length: number;
717 > colonOffset?: number;
718 > parent?: NodeImpl;
719 > children?: NodeImpl[];
720 > }
721 >
722 > /**
723 > * For a given offset, evaluate the location in the JSON document. Each segment in the location path is either a property name or an array index.
724 > */
725 > export function getLocation(text: string, position: number): Location {
726 const segments: Segment[] = []; // strings or numbers
727 const earlyReturnException = new Object();
838 };
839 }
840 > json.ts
841 >
842 > /**
843 > * Parses the given text and returns the object the JSON content represents. On invalid input, the parser tries to be as fault tolerant as possible, but still return a result.
844 > * Therefore always check the errors list to find out if the input was valid.
845 > */
846 > export function parse(text: string, errors: ParseError[] = [], options: ParseOptions = ParseOptions.DEFAULT): any {
847 let currentProperty: string | null = null;
848 let currentParent: any = [];
889 return currentParent[0];
890 }
891 > json.ts
892 >
893 > /**
894 > * Parses the given text and returns a tree representation the JSON content. On invalid input, the parser tries to be as fault tolerant as possible, but still return a result.
895 > */
896 > export function parseTree(text: string, errors: ParseError[] = [], options: ParseOptions = ParseOptions.DEFAULT): Node {
897 let currentParent: NodeImpl = { type: 'array', offset: -1, length: -1, children: [], parent: undefined }; // artificial root
898
955 return result;
956 }
957 > json.ts
958 > /**
959 > * Finds the node at the given path in a JSON DOM.
960 > */
961 > export function findNodeAtLocation(root: Node, path: JSONPath): Node | undefined {
962 if (!root) {
963 return undefined;
990 return node;
991 }
992 > json.ts
993 > /**
994 > * Gets the JSON path of the given JSON DOM node
995 > */
996 > export function getNodePath(node: Node): JSONPath {
997 if (!node.parent || !node.parent.children) {
998 return [];
1010 return path;
1011 }
1012 > json.ts
1013 > /**
1014 > * Evaluates the JavaScript object of the given JSON DOM node
1015 > */
1016 > export function getNodeValue(node: Node): any {
1017 switch (node.type) {
1018 case 'array':
1038
1039 }
1040 > json.ts
1041 > export function contains(node: Node, offset: number, includeRightBound = false): boolean {
1042 return (offset >= node.offset && offset < (node.offset + node.length)) || includeRightBound && (offset === (node.offset + node.length));
1043 }
1044 > json.ts
1045 > /**
1046 > * Finds the most inner node at the given offset. If includeRightBound is set, also finds nodes that end at the given offset.
1047 > */
1048 > export function findNodeAtOffset(node: Node, offset: number, includeRightBound = false): Node | undefined {
1049 if (contains(node, offset, includeRightBound)) {
1050 const children = node.children;
1062 return undefined;
1063 }
1064 > json.ts
1065 >
1066 > /**
1067 > * Parses the given text and invokes the visitor functions for each object, array and literal reached.
1068 > */
1069 > export function visit(text: string, visitor: JSONVisitor, options: ParseOptions = ParseOptions.DEFAULT): any {
1070
1071 const _scanner = createScanner(text, false);
1308 return true;
1309 }
1310 > json.ts
1311 > export function getNodeType(value: unknown): NodeType {
1312 switch (typeof value) {
1313 case 'boolean': return 'boolean';
src/vs/workbench/services/editor/common/editorService.ts 396 covered LOC · 2 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- editorService.ts
2 > * Copyright (c) Microsoft 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 { IResourceEditorInput, IEditorOptions, IResourceEditorInputIdentifier, ITextResourceEditorInput } from '../../../../platform/editor/common/editor.js';
8 > import { IEditorPane, GroupIdentifier, IUntitledTextResourceEditorInput, IResourceDiffEditorInput, ITextDiffEditorPane, IEditorIdentifier, ISaveOptions, IRevertOptions, EditorsOrder, IVisibleEditorPane, IEditorCloseEvent, IUntypedEditorInput, IFindEditorOptions, IEditorWillOpenEvent, ITextResourceDiffEditorInput } from '../../../common/editor.js';
9 > import { EditorInput } from '../../../common/editor/editorInput.js';
10 > import { Event } from '../../../../base/common/event.js';
11 > import { IEditor, IDiffEditor } from '../../../../editor/common/editorCommon.js';
12 > import { ICloseEditorOptions, IEditorGroup, IEditorGroupsContainer, isEditorGroup } from './editorGroupsService.js';
13 > import { URI } from '../../../../base/common/uri.js';
14 > import { IGroupModelChangeEvent } from '../../../common/editor/editorGroupModel.js';
15 > import { DisposableStore } from '../../../../base/common/lifecycle.js';
16 >
17 > export const IEditorService = createDecorator<IEditorService>('editorService');
18 >
19 > /**
20 > * Open an editor in the currently active group.
21 > */
22 > export const ACTIVE_GROUP = -1;
23 > export type ACTIVE_GROUP_TYPE = typeof ACTIVE_GROUP;
24 >
25 > /**
26 > * Open an editor to the side of the active group.
27 > */
28 > export const SIDE_GROUP = -2;
29 > export type SIDE_GROUP_TYPE = typeof SIDE_GROUP;
30 >
31 > /**
32 > * Open an editor in a new auxiliary window.
33 > */
34 > export const AUX_WINDOW_GROUP = -3;
35 > export type AUX_WINDOW_GROUP_TYPE = typeof AUX_WINDOW_GROUP;
36 >
37 > /**
38 > * Open an editor in a modal overlay on top of the workbench.
39 > */
40 > export const MODAL_GROUP = -4;
41 > export type MODAL_GROUP_TYPE = typeof MODAL_GROUP;
42 >
43 > /**
44 > * Setting that controls whether editors open in a modal editor part.
45 > */
46 > export const USE_MODAL_EDITOR_SETTING = 'workbench.editor.useModal';
47 >
48 > /**
49 > * Possible values for the `workbench.editor.useModal` setting:
50 > * - `'off'`: never open editors modal (user opt-out, honored over `RequiresModal`)
51 > * - `'some'`: open modal only for editors that request it (e.g. `RequiresModal`)
52 > * - `'all'`: open all editors modal
53 > */
54 > export type UseModalEditorMode = 'off' | 'some' | 'all';
55 >
56 > export type PreferredGroup = IEditorGroup | GroupIdentifier | SIDE_GROUP_TYPE | ACTIVE_GROUP_TYPE | AUX_WINDOW_GROUP_TYPE | MODAL_GROUP_TYPE;
57 >
58 > export function isPreferredGroup(obj: unknown): obj is PreferredGroup {
59 const candidate = obj as PreferredGroup | undefined;
60
61 return typeof obj === 'number' || isEditorGroup(candidate);
62 }
64 > export interface ISaveEditorsOptions extends ISaveOptions {
65 >
66 > /**
67 > * If true, will ask for a location of the editor to save to.
68 > */
69 > readonly saveAs?: boolean;
70 > }
71 >
72 > export interface ISaveEditorsResult {
73 >
74 > /**
75 > * Whether the save operation was successful.
76 > */
77 > readonly success: boolean;
78 >
79 > /**
80 > * Resulting editors after the save operation.
81 > */
82 > readonly editors: Array<EditorInput | IUntypedEditorInput>;
83 > }
84 >
85 > export interface IUntypedEditorReplacement {
86 >
87 > /**
88 > * The editor to replace.
89 > */
90 > readonly editor: EditorInput;
91 >
92 > /**
93 > * The replacement for the editor.
94 > */
95 > readonly replacement: IUntypedEditorInput;
96 >
97 > /**
98 > * Skips asking the user for confirmation and doesn't
99 > * save the document. Only use this if you really need to!
100 > */
101 > forceReplaceDirty?: boolean;
102 > }
103 >
104 > export interface IBaseSaveRevertAllEditorOptions {
105 >
106 > /**
107 > * Whether to include untitled editors as well.
108 > */
109 > readonly includeUntitled?: {
110 >
111 > /**
112 > * Whether to include scratchpad editors.
113 > * Scratchpads are not included if not specified.
114 > */
115 > readonly includeScratchpad: boolean;
116 >
117 > } | boolean;
118 >
119 > /**
120 > * Whether to exclude sticky editors.
121 > */
122 > readonly excludeSticky?: boolean;
123 > }
124 >
125 > export interface ISaveAllEditorsOptions extends ISaveEditorsOptions, IBaseSaveRevertAllEditorOptions { }
126 >
127 > export interface IRevertAllEditorsOptions extends IRevertOptions, IBaseSaveRevertAllEditorOptions { }
128 >
129 > export interface IOpenEditorsOptions {
130 >
131 > /**
132 > * Whether to validate trust when opening editors
133 > * that are potentially not inside the workspace.
134 > */
135 > readonly validateTrust?: boolean;
136 > }
137 >
138 > export interface IEditorsChangeEvent {
139 > /**
140 > * The group which had the editor change
141 > */
142 > groupId: GroupIdentifier;
143 > /*
144 > * The event fired from the model
145 > */
146 > event: IGroupModelChangeEvent;
147 > }
148 >
149 > export interface IVisibleEditorsChangeEvent {
150 >
151 > /**
152 > * Indicates whether the visibility change is the result of an explicit
153 > * user action (`true`) or happened automatically as a side effect
154 > * (e.g. the chat agent opening files it has edited).
155 > */
156 > readonly isExplicit: boolean;
157 > }
158 >
159 > export interface IEditorService {
160 >
161 > readonly _serviceBrand: undefined;
162 >
163 > /**
164 > * Emitted when the currently active editor changes.
165 > *
166 > * @see {@link IEditorService.activeEditorPane}
167 > */
168 > readonly onDidActiveEditorChange: Event<void>;
169 >
170 > /**
171 > * Emitted when any of the current visible editors changes.
172 > *
173 > * @see {@link IEditorService.visibleEditorPanes}
174 > */
175 > readonly onDidVisibleEditorsChange: Event<IVisibleEditorsChangeEvent>;
176 >
177 > /**
178 > * An aggregated event for any change to any editor across
179 > * all groups.
180 > */
181 > readonly onDidEditorsChange: Event<IEditorsChangeEvent>;
182 >
183 > /**
184 > * Emitted when an editor is about to open.
185 > */
186 > readonly onWillOpenEditor: Event<IEditorWillOpenEvent>;
187 >
188 > /**
189 > * Emitted when an editor is closed.
190 > */
191 > readonly onDidCloseEditor: Event<IEditorCloseEvent>;
192 >
193 > /**
194 > * The currently active editor pane or `undefined` if none. The editor pane is
195 > * the workbench container for editors of any kind.
196 > *
197 > * @see {@link IEditorService.activeEditor} for access to the active editor input
198 > */
199 > readonly activeEditorPane: IVisibleEditorPane | undefined;
200 >
201 > /**
202 > * The currently active editor or `undefined` if none. An editor is active when it is
203 > * located in the currently active editor group. It will be `undefined` if the active
204 > * editor group has no editors open.
205 > */
206 > readonly activeEditor: EditorInput | undefined;
207 >
208 > /**
209 > * The currently active text editor control or `undefined` if there is currently no active
210 > * editor or the active editor widget is neither a text nor a diff editor.
211 > *
212 > * @see {@link IEditorService.activeEditor}
213 > */
214 > readonly activeTextEditorControl: IEditor | IDiffEditor | undefined;
215 >
216 > /**
217 > * The currently active text editor language id or `undefined` if there is currently no active
218 > * editor or the active editor control is neither a text nor a diff editor. If the active
219 > * editor is a diff editor, the modified side's language id will be taken.
220 > */
221 > readonly activeTextEditorLanguageId: string | undefined;
222 >
223 > /**
224 > * All editor panes that are currently visible across all editor groups.
225 > *
226 > * @see {@link IEditorService.visibleEditors} for access to the visible editor inputs
227 > */
228 > readonly visibleEditorPanes: readonly IVisibleEditorPane[];
229 >
230 > /**
231 > * All editors that are currently visible. An editor is visible when it is opened in an
232 > * editor group and active in that group. Multiple editor groups can be opened at the same time.
233 > */
234 > readonly visibleEditors: readonly EditorInput[];
235 >
236 > /**
237 > * All text editor widgets that are currently visible across all editor groups. A text editor
238 > * widget is either a text or a diff editor.
239 > *
240 > * This property supports side-by-side editors as well, by returning both sides if they are
241 > * text editor widgets.
242 > */
243 > readonly visibleTextEditorControls: readonly (IEditor | IDiffEditor)[];
244 >
245 > /**
246 > * All text editor widgets that are currently visible across all editor groups. A text editor
247 > * widget is either a text or a diff editor.
248 > *
249 > * This property supports side-by-side editors as well, by returning both sides if they are
250 > * text editor widgets.
251 > *
252 > * @param order the order of the editors to use
253 > */
254 > getVisibleTextEditorControls(order: EditorsOrder): readonly (IEditor | IDiffEditor)[];
255 >
256 > /**
257 > * All editors that are opened across all editor groups in sequential order
258 > * of appearance.
259 > *
260 > * This includes active as well as inactive editors in each editor group.
261 > */
262 > readonly editors: readonly EditorInput[];
263 >
264 > /**
265 > * The total number of editors that are opened either inactive or active.
266 > */
267 > readonly count: number;
268 >
269 > /**
270 > * All editors that are opened across all editor groups with their group
271 > * identifier.
272 > *
273 > * @param order the order of the editors to use
274 > * @param options whether to exclude sticky editors or not
275 > */
276 > getEditors(order: EditorsOrder, options?: { excludeSticky?: boolean }): readonly IEditorIdentifier[];
277 >
278 > /**
279 > * Open an editor in an editor group.
280 > *
281 > * @param editor the editor to open
282 > * @param options the options to use for the editor
283 > * @param group the target group. If unspecified, the editor will open in the currently
284 > * active group. Use `SIDE_GROUP` to open the editor in a new editor group to the side
285 > * of the currently active group.
286 > *
287 > * @returns the editor that opened or `undefined` if the operation failed or the editor was not
288 > * opened to be active.
289 > */
290 > openEditor(editor: IResourceEditorInput, group?: PreferredGroup): Promise<IEditorPane | undefined>;
291 > openEditor(editor: ITextResourceEditorInput | IUntitledTextResourceEditorInput, group?: PreferredGroup): Promise<IEditorPane | undefined>;
292 > openEditor(editor: ITextResourceDiffEditorInput | IResourceDiffEditorInput, group?: PreferredGroup): Promise<ITextDiffEditorPane | undefined>;
293 > openEditor(editor: IUntypedEditorInput, group?: PreferredGroup): Promise<IEditorPane | undefined>;
294 >
295 > /**
296 > * Using this method is a sign that your editor has not adopted the editor
297 > * resolver yet. Please use `IEditorResolverService.registerEditor` to make your editor
298 > * known to the workbench and then use untyped editor inputs for opening:
299 > *
300 > * ```ts
301 > * editorService.openEditor({ resource });
302 > * ```
303 > *
304 > * If you already have an `EditorInput` in hand and must use it for opening, use `group.openEditor`
305 > * instead, via `IEditorGroupsService`.
306 > */
307 > openEditor(editor: EditorInput, options?: IEditorOptions, group?: PreferredGroup): Promise<IEditorPane | undefined>;
308 >
309 > /**
310 > * Open editors in an editor group.
311 > *
312 > * @param editors the editors to open with associated options
313 > * @param group the target group. If unspecified, the editor will open in the currently
314 > * active group. Use `SIDE_GROUP` to open the editor in a new editor group to the side
315 > * of the currently active group.
316 > *
317 > * @returns the editors that opened. The array can be empty or have less elements for editors
318 > * that failed to open or were instructed to open as inactive.
319 > */
320 > openEditors(editors: IUntypedEditorInput[], group?: PreferredGroup, options?: IOpenEditorsOptions): Promise<readonly IEditorPane[]>;
321 >
322 > /**
323 > * Replaces editors in an editor group with the provided replacement.
324 > *
325 > * @param replacements the editors to replace
326 > * @param group the editor group
327 > *
328 > * @returns a promise that is resolved when the replaced active
329 > * editor (if any) has finished loading.
330 > */
331 > replaceEditors(replacements: IUntypedEditorReplacement[], group: IEditorGroup | GroupIdentifier): Promise<void>;
332 >
333 > /**
334 > * Find out if the provided editor is opened in any editor group.
335 > *
336 > * Note: An editor can be opened but not actively visible.
337 > *
338 > * Note: This method will return `true` if a side by side editor
339 > * is opened where the `primary` editor matches too.
340 > */
341 > isOpened(editor: IResourceEditorInputIdentifier): boolean;
342 >
343 > /**
344 > * Find out if the provided editor is visible in any editor group.
345 > */
346 > isVisible(editor: EditorInput): boolean;
347 >
348 > /**
349 > * Close an editor in a specific editor group.
350 > */
351 > closeEditor(editor: IEditorIdentifier, options?: ICloseEditorOptions): Promise<void>;
352 >
353 > /**
354 > * Close multiple editors in specific editor groups.
355 > */
356 > closeEditors(editors: readonly IEditorIdentifier[], options?: ICloseEditorOptions): Promise<void>;
357 >
358 > /**
359 > * This method will return an entry for each editor that reports
360 > * a `resource` that matches the provided one in the group or
361 > * across all groups.
362 > *
363 > * It is possible that multiple editors are returned in case the
364 > * same resource is opened in different editors. To find the specific
365 > * editor, use the `IResourceEditorInputIdentifier` as input.
366 > */
367 > findEditors(resource: URI, options?: IFindEditorOptions): readonly IEditorIdentifier[];
368 > findEditors(editor: IResourceEditorInputIdentifier, options?: IFindEditorOptions): readonly IEditorIdentifier[];
369 >
370 > /**
371 > * Save the provided list of editors.
372 > */
373 > save(editors: IEditorIdentifier | readonly IEditorIdentifier[], options?: ISaveEditorsOptions): Promise<ISaveEditorsResult>;
374 >
375 > /**
376 > * Save all editors.
377 > */
378 > saveAll(options?: ISaveAllEditorsOptions): Promise<ISaveEditorsResult>;
379 >
380 > /**
381 > * Reverts the provided list of editors.
382 > *
383 > * @returns `true` if all editors reverted and `false` otherwise.
384 > */
385 > revert(editors: IEditorIdentifier | readonly IEditorIdentifier[], options?: IRevertOptions): Promise<boolean>;
386 >
387 > /**
388 > * Reverts all editors.
389 > *
390 > * @returns `true` if all editors reverted and `false` otherwise.
391 > */
392 > revertAll(options?: IRevertAllEditorsOptions): Promise<boolean>;
393 >
394 > /**
395 > * Create a scoped editor service that only operates on the provided
396 > * editor group container. Use `main` to create a scoped editor service
397 > * to the main editor group container of the main window.
398 > */
399 > createScoped(editorGroupsContainer: IEditorGroupsContainer, disposables: DisposableStore): IEditorService;
400 > }
src/vs/workbench/contrib/chat/common/promptSyntax/hookSchema.ts 385 covered LOC · 15 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- hookSchema.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IJSONSchema } from '../../../../../base/common/jsonSchema.js';
7 > import * as nls from '../../../../../nls.js';
8 > import { URI } from '../../../../../base/common/uri.js';
9 > import { joinPath } from '../../../../../base/common/resources.js';
10 > import { isAbsolute } from '../../../../../base/common/path.js';
11 > import { untildify } from '../../../../../base/common/labels.js';
12 > import { OperatingSystem } from '../../../../../base/common/platform.js';
13 > import { IParsedHookCommand } from '../../../../../platform/agentPlugins/common/pluginParsers.js';
14 > import { HookType, HOOKS_BY_TARGET, HOOK_METADATA } from './hookTypes.js';
15 > import { Target } from './promptTypes.js';
16 > import { IValue, IMapValue } from './promptFileParser.js';
17 >
18 > /**
19 > * A single hook command configuration.
20 > * Extends the platform-layer {@link IParsedHookCommand} with editor-specific
21 > * metadata used for UI display and field highlighting.
22 > */
23 > export interface IHookCommand extends IParsedHookCommand {
24 > readonly type: 'command';
25 > /** Original JSON field name that provided the windows command. */
26 > readonly windowsSource?: 'windows' | 'powershell';
27 > /** Original JSON field name that provided the linux command. */
28 > readonly linuxSource?: 'linux' | 'bash';
29 > /** Original JSON field name that provided the osx command. */
30 > readonly osxSource?: 'osx' | 'bash';
31 > }
32 >
33 > /**
34 > * Collected hooks for a chat request, organized by hook type.
35 > * This is passed to the extension host so it knows what hooks are available.
36 > */
37 > export type ChatRequestHooks = {
38 > readonly [K in HookType]?: readonly IParsedHookCommand[];
39 > };
40 >
41 > export namespace ChatRequestHooks {
42 > export function isEquals(a: ChatRequestHooks | undefined, b: ChatRequestHooks | undefined): boolean {
43 if (a === b) {
44 return true;
63 return true;
64 }
65 > } hookSchema.ts
66 >
67 > /**
68 > * Merges two sets of hooks by concatenating the command arrays for each hook type.
69 > * Additional hooks are appended after the base hooks.
70 > */
71 > export function mergeHooks(base: ChatRequestHooks | undefined, additional: ChatRequestHooks): ChatRequestHooks {
72 if (!base) {
73 return additional;
84 return result as ChatRequestHooks;
85 }
87 > /**
88 > * Descriptions for hook command fields, used by both the JSON schema and the hover provider.
89 > */
90 > export const HOOK_COMMAND_FIELD_DESCRIPTIONS: Record<string, string> = {
91 > type: nls.localize('hook.type', 'Must be "command".'),
92 > command: nls.localize('hook.command', 'The command to execute. This is the default cross-platform command.'),
93 > windows: nls.localize('hook.windows', 'Windows-specific command. If specified and running on Windows, this overrides the "command" field.'),
94 > linux: nls.localize('hook.linux', 'Linux-specific command. If specified and running on Linux, this overrides the "command" field.'),
95 > osx: nls.localize('hook.osx', 'macOS-specific command. If specified and running on macOS, this overrides the "command" field.'),
96 > bash: nls.localize('hook.bash', 'Bash command for Linux and macOS.'),
97 > powershell: nls.localize('hook.powershell', 'PowerShell command for Windows.'),
98 > cwd: nls.localize('hook.cwd', 'Working directory for the script (relative to repository root).'),
99 > env: nls.localize('hook.env', 'Additional environment variables that are merged with the existing environment.'),
100 > timeout: nls.localize('hook.timeout', 'Maximum execution time in seconds (default: 30).'),
101 > timeoutSec: nls.localize('hook.timeoutSec', 'Maximum execution time in seconds (default: 10).'),
102 > };
103 >
104 > /**
105 > * JSON Schema for GitHub Copilot hook configuration files.
106 > * Hooks enable executing custom shell commands at strategic points in an agent's workflow.
107 > */
108 > const vscodeHookCommandSchema: IJSONSchema = {
109 > type: 'object',
110 > additionalProperties: true,
111 > required: ['type'],
112 > anyOf: [
113 > { required: ['command'] },
114 > { required: ['windows'] },
115 > { required: ['linux'] },
116 > { required: ['osx'] },
117 > { required: ['bash'] },
118 > { required: ['powershell'] }
119 > ],
120 > errorMessage: nls.localize('hook.commandRequired', 'At least one of "command", "windows", "linux", or "osx" must be specified.'),
121 > properties: {
122 > type: {
123 > type: 'string',
124 > enum: ['command'],
125 > description: HOOK_COMMAND_FIELD_DESCRIPTIONS.type
126 > },
127 > command: {
128 > type: 'string',
129 > description: HOOK_COMMAND_FIELD_DESCRIPTIONS.command
130 > },
131 > windows: {
132 > type: 'string',
133 > description: HOOK_COMMAND_FIELD_DESCRIPTIONS.windows
134 > },
135 > linux: {
136 > type: 'string',
137 > description: HOOK_COMMAND_FIELD_DESCRIPTIONS.linux
138 > },
139 > osx: {
140 > type: 'string',
141 > description: HOOK_COMMAND_FIELD_DESCRIPTIONS.osx
142 > },
143 > cwd: {
144 > type: 'string',
145 > description: HOOK_COMMAND_FIELD_DESCRIPTIONS.cwd
146 > },
147 > env: {
148 > type: 'object',
149 > additionalProperties: { type: 'string' },
150 > description: HOOK_COMMAND_FIELD_DESCRIPTIONS.env
151 > },
152 > timeout: {
153 > type: 'number',
154 > default: 30,
155 > description: HOOK_COMMAND_FIELD_DESCRIPTIONS.timeout
156 > }
157 > }
158 > };
159 >
160 > const hookArraySchema: IJSONSchema = {
161 > type: 'array',
162 > items: vscodeHookCommandSchema
163 > };
164 >
165 > /**
166 > * Builds JSON Schema hook properties for a given target by looking up
167 > * the hook keys from HOOKS_BY_TARGET and descriptions from HOOK_METADATA.
168 > */
169 > function buildHookProperties(target: Target, arraySchema: IJSONSchema): Record<string, IJSONSchema> {
170 > return Object.fromEntries(
171 > Object.entries(HOOKS_BY_TARGET[target]).map(([key, hookType]) => [
172 > key,
173 > { ...arraySchema, description: HOOK_METADATA[hookType]?.description }
174 > ])
175 > );
176 > }
177 >
178 > /**
179 > * Hook properties for the VS Code format.
180 > */
181 > const vscodeHookProperties: Record<string, IJSONSchema> = buildHookProperties(Target.VSCode, hookArraySchema);
182 >
183 > /**
184 > * Hook command schema for the Copilot CLI format.
185 > * Adds `bash`, `powershell`, and `timeoutSec` fields alongside the standard ones.
186 > */
187 > const copilotCliHookCommandSchema: IJSONSchema = {
188 > type: 'object',
189 > additionalProperties: true,
190 > required: ['type'],
191 > anyOf: [
192 > { required: ['bash'] },
193 > { required: ['powershell'] }
194 > ],
195 > errorMessage: nls.localize('hook.cliCommandRequired', 'At least one of "bash" or "powershell" must be specified.'),
196 > properties: {
197 > type: {
198 > type: 'string',
199 > enum: ['command'],
200 > description: HOOK_COMMAND_FIELD_DESCRIPTIONS.type
201 > },
202 > bash: {
203 > type: 'string',
204 > description: HOOK_COMMAND_FIELD_DESCRIPTIONS.bash
205 > },
206 > powershell: {
207 > type: 'string',
208 > description: HOOK_COMMAND_FIELD_DESCRIPTIONS.powershell
209 > },
210 > cwd: {
211 > type: 'string',
212 > description: HOOK_COMMAND_FIELD_DESCRIPTIONS.cwd
213 > },
214 > env: {
215 > type: 'object',
216 > additionalProperties: { type: 'string' },
217 > description: HOOK_COMMAND_FIELD_DESCRIPTIONS.env
218 > },
219 > timeoutSec: {
220 > type: 'number',
221 > default: 10,
222 > description: HOOK_COMMAND_FIELD_DESCRIPTIONS.timeoutSec
223 > }
224 > }
225 > };
226 >
227 > const copilotCliHookArraySchema: IJSONSchema = {
228 > type: 'array',
229 > items: copilotCliHookCommandSchema
230 > };
231 >
232 > /**
233 > * Hook properties for the Copilot CLI format.
234 > */
235 > const copilotCliHookProperties: Record<string, IJSONSchema> = buildHookProperties(Target.GitHubCopilot, copilotCliHookArraySchema);
236 >
237 > export const hookFileSchema: IJSONSchema = {
238 > $schema: 'http://json-schema.org/draft-07/schema#',
239 > type: 'object',
240 > description: nls.localize('hookFile.description', 'GitHub Copilot hook configuration file. Hooks enable executing custom shell commands at strategic points in an agent\'s workflow.'),
241 > additionalProperties: true,
242 > required: ['hooks'],
243 > properties: {
244 > hooks: {
245 > type: 'object',
246 > description: nls.localize('hookFile.hooks', 'Hook definitions organized by type.'),
247 > additionalProperties: true,
248 > }
249 > },
250 > // Conditionally apply PascalCase or camelCase hook properties based on
251 > // whether the file uses the Copilot CLI format (detected by the "version" field).
252 > if: {
253 > required: ['version'],
254 > properties: {
255 > version: { type: 'number' }
256 > }
257 > },
258 > then: {
259 > // Copilot CLI format: camelCase hook names, bash/powershell/timeoutSec fields
260 > properties: {
261 > version: {
262 > type: 'number',
263 > description: nls.localize('hookFile.version', 'Hook configuration format version.'),
264 > },
265 > hooks: {
266 > properties: copilotCliHookProperties
267 > }
268 > }
269 > },
270 > else: {
271 > // VS Code / PascalCase format
272 > properties: {
273 > hooks: {
274 > properties: vscodeHookProperties
275 > }
276 > }
277 > },
278 > defaultSnippets: [
279 > {
280 > label: nls.localize('hookFile.snippet.basic', 'Basic hook configuration'),
281 > description: nls.localize('hookFile.snippet.basic.description', 'A basic hook configuration with common hooks'),
282 > body: {
283 > hooks: {
284 > SessionStart: [
285 > {
286 > type: 'command',
287 > command: '${1:echo "Session started" >> session.log}',
288 > }
289 > ],
290 > PreToolUse: [
291 > {
292 > type: 'command',
293 > command: '${2:./scripts/validate.sh}',
294 > timeout: 15
295 > }
296 > ]
297 > }
298 > }
299 > }
300 > ]
301 > };
302 >
303 > /**
304 > * URI for the hook schema registration.
305 > */
306 > export const HOOK_SCHEMA_URI = 'vscode://schemas/hooks';
307 >
308 > /**
309 > * Normalizes a raw hook type identifier to the canonical HookType enum value.
310 > * Only matches exact enum values. For tool-specific naming conventions (e.g., Claude, Copilot CLI),
311 > * use the corresponding compat module's resolver function.
312 > */
313 > export function toHookType(rawHookTypeId: string): HookType | undefined {
314 if (Object.values(HookType).includes(rawHookTypeId as HookType)) {
315 return rawHookTypeId as HookType;
317 return undefined;
318 }
320 > /**
321 > * Normalizes a raw hook command object, validating structure.
322 > * Maps legacy bash/powershell fields to platform-specific overrides:
323 > * - bash -> linux + osx
324 > * - powershell -> windows
325 > * This is an internal helper - use resolveHookCommand for the full resolution.
326 > */
327 function normalizeHookCommand(raw: Record<string, unknown>): { command?: string; windows?: string; linux?: string; osx?: string; windowsSource?: 'windows' | 'powershell'; linuxSource?: 'linux' | 'bash'; osxSource?: 'osx' | 'bash'; cwd?: string; env?: Record<string, string>; timeout?: number } | undefined {
328 if (raw.type !== 'command') {
364 };
365 }
367 > /**
368 > * Gets a label for the given platform.
369 > */
370 > export function getPlatformLabel(os: OperatingSystem): string {
371 if (os === OperatingSystem.Windows) {
372 return 'Windows';
378 return '';
379 }
381 > /**
382 > * Resolves the effective command for the given platform.
383 > * This applies OS-specific overrides (windows, linux, osx) to get the actual command that will be executed.
384 > * Similar to how launch.json handles platform-specific configurations in debugAdapter.ts.
385 > */
386 > export function resolveEffectiveCommand(hook: IParsedHookCommand, os: OperatingSystem): string | undefined {
387 // Select the platform-specific override based on the OS
388 if (os === OperatingSystem.Windows && hook.windows) {
397 return hook.command;
398 }
400 > /**
401 > * Checks if the hook is using a platform-specific command override.
402 > */
403 > export function isUsingPlatformOverride(hook: IParsedHookCommand, os: OperatingSystem): boolean {
404 if (os === OperatingSystem.Windows && hook.windows) {
405 return true;
411 return false;
412 }
414 > /**
415 > * Gets the source shell type for the effective command on the given platform.
416 > * Returns 'powershell' if the Windows command came from a powershell field,
417 > * 'bash' if the Linux/macOS command came from a bash field,
418 > * or undefined for default shell handling.
419 > */
420 > export function getEffectiveCommandSource(hook: IHookCommand, os: OperatingSystem): 'powershell' | 'bash' | undefined {
421 if (os === OperatingSystem.Windows && hook.windows && hook.windowsSource === 'powershell') {
422 return 'powershell';
428 return undefined;
429 }
431 > /**
432 > * Gets the original JSON field key name for the given platform's command.
433 > * Returns the actual field name from the JSON (e.g., 'bash' instead of 'osx' if bash was used).
434 > * This is used for editor focus to highlight the correct field.
435 > */
436 > export function getEffectiveCommandFieldKey(hook: IHookCommand | IParsedHookCommand, os: OperatingSystem): string {
437 const h = hook as Partial<IHookCommand>;
438 if (os === OperatingSystem.Windows && hook.windows) {
445 return 'command';
446 }
448 > /**
449 > * Formats a hook command for display.
450 > * Resolves OS-specific overrides to show the effective command for the given platform.
451 > * If using a platform-specific override, includes the platform as a prefix badge.
452 > */
453 > export function formatHookCommandLabel(hook: IParsedHookCommand, os: OperatingSystem): string {
454 const command = resolveEffectiveCommand(hook, os);
455 if (!command) {
458 return command;
459 }
461 > /**
462 > * Resolves a raw hook command object to the canonical IHookCommand format.
463 > * Normalizes the command and resolves the cwd path relative to the workspace root.
464 > * @param raw The raw hook command object from JSON
465 > * @param workspaceRootUri The workspace root URI to resolve relative cwd paths against
466 > * @param userHome The user's home directory path for tilde expansion
467 > */
468 > export function resolveHookCommand(raw: Record<string, unknown>, workspaceRootUri: URI | undefined, userHome: string): IHookCommand | undefined {
469 const normalized = normalizeHookCommand(raw);
470 if (!normalized) {
501 };
502 }
504 > /**
505 > * Helper to extract hook commands from an item that could be:
506 > * 1. A direct command object: { type: 'command', command: '...' }
507 > * 2. A nested structure with matcher (Claude style): { matcher: '...', hooks: [{ type: 'command', command: '...' }] }
508 > *
509 > * This allows Copilot format to handle Claude-style entries if pasted.
510 > * Also handles Claude's leniency where 'type' field can be omitted.
511 > */
512 > export function extractHookCommandsFromItem(
513 item: unknown,
514 workspaceRootUri: URI | undefined,
546 return commands;
547 }
549 > /**
550 > * Normalizes a hook command object for resolving.
551 > * Claude format allows omitting the 'type' field, treating it as 'command'.
552 > * This ensures compatibility when Claude-style hooks are pasted into Copilot format.
553 > */
554 function normalizeForResolve(raw: Record<string, unknown>): Record<string, unknown> {
555 // If type is missing or already 'command', ensure it's set to 'command'
559 return raw;
560 }
562 > /**
563 > * Converts an {@link IValue} YAML AST node into a plain JavaScript value
564 > * (string, array, or object) suitable for passing to hook parsing helpers.
565 > */
566 function yamlValueToPlain(value: IValue): unknown {
567 switch (value.type) {
579 }
580 }
582 > /**
583 > * Parses hooks from a subagent's YAML frontmatter `hooks` attribute.
584 > *
585 > * Supports two formats for hook entries:
586 > *
587 > * 1. **Direct command** (our format, without matcher):
588 > * ```yaml
589 > * hooks:
590 > * PreToolUse:
591 > * - type: command
592 > * command: "./scripts/validate.sh"
593 > * ```
594 > *
595 > * 2. **Nested with matcher** (Claude Code format):
596 > * ```yaml
597 > * hooks:
598 > * PreToolUse:
599 > * - matcher: "Bash"
600 > * hooks:
601 > * - type: command
602 > * command: "./scripts/validate.sh"
603 > * ```
604 > *
605 > * @param hooksMap The raw YAML map value from the `hooks` frontmatter attribute.
606 > * @param workspaceRootUri Workspace root for resolving relative `cwd` paths.
607 > * @param userHome User home directory path for tilde expansion.
608 > * @param target The agent's target, used to resolve hook type names correctly.
609 > * @returns Resolved hooks organized by hook type, ready for use in {@link ChatRequestHooks}.
610 > */
611 > export function parseSubagentHooksFromYaml(
612 hooksMap: IMapValue,
613 workspaceRootUri: URI | undefined,
src/vs/platform/policy/common/copilotManagedSettings.ts 373 covered LOC · 20 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- copilotManagedSettings.ts
2 > * Copyright (c) Microsoft 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 { IPolicyData } from '../../../base/common/defaultAccount.js';
8 > import { IExtraKnownMarketplaceEntry, extraKnownMarketplacesToConfigDict } from '../../../base/common/managedSettings.js';
9 > import { IManagedSettingPolicyDefinition, IManagedSettingsPolicyDefinitions, ManagedSettingValue, ManagedSettingsData } from '../../../base/common/policy.js';
10 > import { IStringDictionary } from '../../../base/common/collections.js';
11 > import { isEmptyObject, isObject, isString } from '../../../base/common/types.js';
12 > import { createDecorator } from '../../instantiation/common/instantiation.js';
13 > import { PolicyDefinition } from './policy.js';
14 >
15 > export type { ManagedSettingsData } from '../../../base/common/policy.js';
16 >
17 > export type RawManagedSettingsData = Readonly<Record<string, unknown>>;
18 >
19 > /** Windows registry root for GitHub Copilot policies. */
20 > export const GITHUB_COPILOT_WIN32_REGISTRY_PATH = 'SOFTWARE\\Policies\\GitHubCopilot';
21 >
22 > /** Windows product name passed to the native policy watcher. */
23 > export const GITHUB_COPILOT_WIN32_POLICY_NAME = 'GitHubCopilot';
24 >
25 > /** macOS CFPreferences application ID for GitHub Copilot managed preferences. */
26 > export const GITHUB_COPILOT_MACOS_BUNDLE_ID = 'com.github.copilot';
27 >
28 > /** MDM key for the V0 managed setting. */
29 > export const COPILOT_DISABLE_BYPASS_PERMISSIONS_MODE_KEY = 'permissions.disableBypassPermissionsMode';
30 >
31 > /** Managed-settings key for enterprise plugin enablement (carried as a JSON-encoded `{ [pluginId]: boolean }`). */
32 > export const COPILOT_ENABLED_PLUGINS_KEY = 'enabledPlugins';
33 >
34 > /** Managed-settings key for enterprise marketplaces (carried as a JSON-encoded `{ [name]: url-or-shorthand }`). */
35 > export const COPILOT_EXTRA_MARKETPLACES_KEY = 'extraKnownMarketplaces';
36 >
37 > /** Managed-settings key for the strict-marketplace allowlist (carried as a JSON-encoded array of source entries; absent = no restrictions, `[]` = lockdown). */
38 > export const COPILOT_STRICT_MARKETPLACES_KEY = 'strictKnownMarketplaces';
39 >
40 > /** Managed-settings key for the per-server MCP allowlist (carried as a JSON-encoded array of matcher entries; absent = no allow restriction, `[]` = only servers matching an entry, i.e. block all). */
41 > export const COPILOT_ALLOWED_MCP_SERVERS_KEY = 'allowedMcpServers';
42 >
43 > /** Managed-settings key for the per-server MCP denylist (carried as a JSON-encoded array of matcher entries; deny always takes precedence over allow). */
44 > export const COPILOT_DENIED_MCP_SERVERS_KEY = 'deniedMcpServers';
45 >
46 > /**
47 > * Managed-settings key for the default chat model (carried as a plain string: `auto`, a model
48 > * family name, or a full model id). Nested under `permissions` in the managed-settings schema
49 > * (alongside {@link COPILOT_DISABLE_BYPASS_PERMISSIONS_MODE_KEY}), so it flattens to the dot-path
50 > * `permissions.model` in the normalized bag — the key policy `value()` callbacks must read.
51 > */
52 > export const COPILOT_MODEL_KEY = 'permissions.model';
53 >
54 > /**
55 > * Enterprise OTel managed-settings keys. These are the scalar leaves of the canonical
56 > * `telemetry` block from the cross-client managed-settings schema (see the CLI
57 > * `ManagedTelemetrySettings`); they flatten to dot-path bag keys via
58 > * {@link normalizeManagedSettings}, so no {@link STRUCTURED_MANAGED_SETTINGS} entry is needed.
59 > * The `telemetry.resourceAttributes` and `telemetry.headers` map fields are structured
60 > * ({@link STRUCTURED_MANAGED_SETTINGS} rows carry them as JSON-encoded objects under their nested
61 > * keys); `telemetry.serviceName` is a scalar.
62 > */
63 >
64 > /** Managed-settings key for enterprise OTel enablement. */
65 > export const COPILOT_OTEL_ENABLED_KEY = 'telemetry.enabled';
66 >
67 > /** Managed-settings key for the enterprise OTLP collector endpoint. */
68 > export const COPILOT_OTEL_ENDPOINT_KEY = 'telemetry.endpoint';
69 >
70 > /** Managed-settings key for the enterprise OTLP protocol (`http/json`, `http/protobuf`, or `grpc`). */
71 > export const COPILOT_OTEL_PROTOCOL_KEY = 'telemetry.protocol';
72 >
73 > /** Managed-settings key for enterprise OTel content capture. */
74 > export const COPILOT_OTEL_CAPTURE_CONTENT_KEY = 'telemetry.captureContent';
75 >
76 > /** Managed-settings key that prevents users from enabling OTel content capture themselves. */
77 > export const COPILOT_OTEL_LOCK_CAPTURE_CONTENT_KEY = 'telemetry.lockCaptureContent';
78 >
79 > /** Managed-settings key for the OTel `service.name` resource attribute. */
80 > export const COPILOT_OTEL_SERVICE_NAME_KEY = 'telemetry.serviceName';
81 >
82 > /** Managed-settings key for additional OTel resource attributes (a `{ [k]: string }` map). */
83 > export const COPILOT_OTEL_RESOURCE_ATTRIBUTES_KEY = 'telemetry.resourceAttributes';
84 >
85 > /** Managed-settings key for extra OTLP exporter headers (a `{ [k]: string }` map). */
86 > export const COPILOT_OTEL_HEADERS_KEY = 'telemetry.headers';
87 >
88 > const managedSettingValueCallbacks = new Map<string, (policyData: IPolicyData) => ManagedSettingValue | undefined>();
89 >
90 > /**
91 > * Standard pass-through `value` callback for a managed-settings-driven policy: locks the setting
92 > * to the managed value when the enterprise has set it, and returns `undefined` otherwise so the
93 > * user's own setting falls through. Use for the common case; policies that combine the managed
94 > * value with other conditions (e.g. `chat_preview_features_enabled`) keep a custom callback.
95 > *
96 > * The callback is memoized per key, so repeated calls for the same key return the SAME function
97 > * reference. That reference identity is what lets `isSamePolicyDefinition` skip needless
98 > * re-registration, and memoizing makes the guarantee hold regardless of where the helper is called.
99 > */
100 > export function managedSettingValue(key: string): (policyData: IPolicyData) => ManagedSettingValue | undefined {
101 let callback = managedSettingValueCallbacks.get(key);
102 if (!callback) {
106 return callback;
107 }
109 > let managedModelValueCallback: ((policyData: IPolicyData) => ManagedSettingValue | undefined) | undefined;
110 >
111 > /**
112 > * `value` callback for the default-chat-model managed setting ({@link COPILOT_MODEL_KEY}). Like
113 > * {@link managedSettingValue} it locks the setting to the managed value and otherwise falls through
114 > * to the user's own value, but it additionally trims the string and treats a blank/whitespace-only
115 > * value as "unset" (returns `undefined`) — an admin clearing the field must not lock the setting to
116 > * an empty string. The model-specific normalization lives here, alongside the other managed-settings
117 > * handling, rather than inline at the policy declaration, so every managed-settings control is wired
118 > * the same way.
119 > *
120 > * Memoized (single key) so repeated calls return the SAME function reference, matching the
121 > * reference-identity contract {@link managedSettingValue} relies on for `isSamePolicyDefinition`.
122 > */
123 > export function managedModelValue(): (policyData: IPolicyData) => ManagedSettingValue | undefined {
124 if (!managedModelValueCallback) {
125 managedModelValueCallback = policyData => {
131 return managedModelValueCallback;
132 }
134 > export const INativeManagedSettingsService = createDecorator<INativeManagedSettingsService>('nativeManagedSettingsService');
135 >
136 > export interface INativeManagedSettingsService {
137 > readonly _serviceBrand: undefined;
138 > readonly managedSettings: ManagedSettingsData;
139 > readonly onDidChangeManagedSettings: Event<ManagedSettingsData>;
140 > updatePolicyDefinitions(policyDefinitions: IStringDictionary<PolicyDefinition>): Promise<ManagedSettingsData>;
141 > }
142 >
143 > export class NullNativeManagedSettingsService implements INativeManagedSettingsService {
144 readonly _serviceBrand: undefined;
145 readonly managedSettings: ManagedSettingsData = {};
146 readonly onDidChangeManagedSettings = Event.None;
148 > async updatePolicyDefinitions(): Promise<ManagedSettingsData> { return this.managedSettings; }
149 > }
150 >
151 function flattenManagedSettings(object: unknown): Record<string, string | number | boolean> {
152 const result: Record<string, string | number | boolean> = {};
154 return result;
155 }
157 function flattenManagedSettingsValue(value: unknown, prefix: string | undefined, result: Record<string, string | number | boolean>): void {
158 if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
171 }
172 }
174 function isManagedSettingsObject(value: unknown): value is Record<string, unknown> {
175 return typeof value === 'object' && value !== null && !Array.isArray(value);
176 }
178 > /**
179 > * Aggregate the `managedSettings` declarations of every policy definition into a single
180 > * key -> definition map. This is the single source of truth for which Copilot managed-settings
181 > * keys (and their value types) are honored, and it drives both delivery channels: the native
182 > * MDM watcher and the server `managed_settings` endpoint projection.
183 > */
184 > export function collectManagedSettingsDefinitions(policyDefinitions: IStringDictionary<PolicyDefinition>): IManagedSettingsPolicyDefinitions {
185 const definitions: Record<string, IManagedSettingPolicyDefinition> = {};
186 for (const policyName in policyDefinitions) {
194 return definitions;
195 }
197 > /**
198 > * Whether any policy in `policyDefinitions` declares at least one managed-settings key. Cheap
199 > * existence check (short-circuits) used to decide whether the native MDM watcher is needed at all,
200 > * without aggregating the full {@link collectManagedSettingsDefinitions} map.
201 > */
202 > export function hasManagedSettingsDefinitions(policyDefinitions: IStringDictionary<PolicyDefinition>): boolean {
203 for (const policyName in policyDefinitions) {
204 const policyManagedSettings = policyDefinitions[policyName].managedSettings;
209 return false;
210 }
212 > /**
213 > * Project a raw managed-settings bag onto the declared schema: keep only keys declared by a
214 > * policy definition whose runtime value matches the declared type. Undeclared keys and
215 > * type-mismatched values are dropped (with an optional warning). Values are validated, never
216 > * coerced, so a key declared as `string` keeps its string value untouched.
217 > *
218 > * This keeps the server endpoint and native MDM delivery aligned on the same
219 > * declaration-driven key set and value types.
220 > */
221 > export function projectManagedSettings(values: ManagedSettingsData, definitions: IManagedSettingsPolicyDefinitions, onWarn?: (msg: string) => void): ManagedSettingsData {
222 const projected: Record<string, ManagedSettingValue> = {};
223 for (const key in definitions) {
234 return projected;
235 }
237 > /**
238 > * A delivery channel that can provide managed settings. Managed settings can be delivered by more
239 > * than one channel, so this names the known sources to give policy evaluation and the Policy
240 > * Diagnostics report one shared vocabulary. Extend this union (and {@link MANAGED_SETTINGS_CHANNELS}
241 > * / {@link pickManagedSettings}) when adding a new channel.
242 > */
243 > export type ManagedSettingsChannel =
244 > /** GitHub `/copilot_internal/managed_settings` endpoint (server-delivered). */
245 > | 'server'
246 > /** Native MDM: OS registry (Windows) / managed preferences (macOS) via `@vscode/policy-watcher`. */
247 > | 'nativeMdm'
248 > /** File on a well-known disk path (`managed-settings.json`). */
249 > | 'file';
250 >
251 > /**
252 > * The source attributed to an effective managed setting (or to the overall report). A
253 > * {@link ManagedSettingsChannel} once a channel has won, or `'none'` when no channel contributes.
254 > */
255 > export type ManagedSettingsSource = ManagedSettingsChannel | 'none';
256 >
257 > /**
258 > * The delivery channels in fixed precedence order (highest first): native MDM → server-delivered →
259 > * file on disk. This single ordered list drives the per-key resolution in {@link pickManagedSettings}
260 > * and is the one place to extend when a new channel is introduced. Rationale for the order: the
261 > * server is harder to bypass than local MDM, and a local file is the most easily tampered with.
262 > */
263 > export const MANAGED_SETTINGS_CHANNELS: readonly ManagedSettingsChannel[] = ['nativeMdm', 'server', 'file'];
264 >
265 > /** A single channel's contribution to a managed-settings key, for provenance in the resolution. */
266 > export interface IManagedSettingsContribution {
267 > /** The channel that supplied this value. */
268 > readonly channel: ManagedSettingsChannel;
269 > /** The value the channel supplied for the key. */
270 > readonly value: ManagedSettingValue;
271 > }
272 >
273 > /** How a single managed-settings key was resolved across the delivery channels. */
274 > export interface IManagedSettingResolution {
275 > /** The effective (winning) value applied for the key. */
276 > readonly value: ManagedSettingValue;
277 > /** The channel whose value won (always the first {@link contributions} entry's channel). */
278 > readonly source: ManagedSettingsChannel;
279 > /** Every channel that supplied this key, in precedence order (winner first, overridden after). */
280 > readonly contributions: readonly IManagedSettingsContribution[];
281 > }
282 >
283 > /** The result of merging managed settings from every delivery channel on a per-key basis. */
284 > export interface IManagedSettingsPick {
285 > /** The effective merged bag: the winning value for each key contributed by any channel. */
286 > readonly values: ManagedSettingsData;
287 > /** Per-key provenance: how each key resolved and which channels were overridden. */
288 > readonly resolutions: ReadonlyMap<string, IManagedSettingResolution>;
289 > /** The channels that supplied at least one *winning* key, in precedence order. */
290 > readonly activeSources: readonly ManagedSettingsChannel[];
291 > }
292 >
293 > /**
294 > * Merge the managed-settings bags from every delivery channel on a **per-key** basis.
295 > *
296 > * Precedence (highest first): native MDM → server-delivered → file on disk. Unlike a single
297 > * authoritative source, the channels *are* merged key-by-key: for each key the highest-precedence
298 > * channel that supplies it wins, but a key that the higher channels never set is still filled in by
299 > * a lower channel. A value an admin locks via native MDM therefore cannot be overwritten by the
300 > * server or a file, while keys those higher channels leave unset remain available to lower ones.
301 > *
302 > * The parameter order matches the precedence so call sites read top-to-bottom. Centralizing the
303 > * resolution here (rather than inlining it at each call site) keeps policy evaluation
304 > * ({@link AccountPolicyService.getPolicyData}) and the Policy Diagnostics report from drifting apart,
305 > * and gives one obvious place to extend when a new channel is introduced. Empty or absent channels
306 > * contribute nothing.
307 > */
308 > export function pickManagedSettings(nativeMdm: ManagedSettingsData | undefined, server: ManagedSettingsData | undefined, file: ManagedSettingsData | undefined): IManagedSettingsPick {
309 const bags: Record<ManagedSettingsChannel, ManagedSettingsData | undefined> = { nativeMdm, server, file };
310
349 };
350 }
352 > // --- File-based managed settings ---
353 >
354 > /** macOS well-known path for file-based managed settings. */
355 > export const MANAGED_SETTINGS_MACOS_FILE_PATH = '/Library/Application Support/GitHubCopilot/managed-settings.json';
356 >
357 > /** Linux well-known path for file-based managed settings. */
358 > export const MANAGED_SETTINGS_LINUX_FILE_PATH = '/etc/github-copilot/managed-settings.json';
359 >
360 > /** Windows directory name under %ProgramFiles% for file-based managed settings. */
361 > export const MANAGED_SETTINGS_WINDOWS_DIR = 'GitHubCopilot';
362 >
363 > /** Managed settings file name. */
364 > export const MANAGED_SETTINGS_FILE_NAME = 'managed-settings.json';
365 >
366 > /**
367 > * Descriptor for a structured (object/array) managed setting: one carried across every delivery
368 > * channel as a canonical JSON string under a single key. This table is the single place that
369 > * knows how to turn a managed-settings schema field into that canonical value, so adding a
370 > * structured key is one row here (plus the policy declaration that reads the bag key).
371 > *
372 > * `key` is both the source field name read from the parsed input and the canonical bag key the
373 > * JSON string is stored under — for structured settings these are identical by contract (a
374 > * structured key's bag name matches the schema field exactly; only scalar settings flatten to a
375 > * differently-shaped dot-path, and those don't go through this table).
376 > */
377 > interface IStructuredManagedSetting {
378 > /** Source field name read from the parsed input, and the canonical bag key the JSON string is stored under. */
379 > readonly key: string;
380 > /**
381 > * Normalize the raw value into the canonical pre-stringify shape an admin authors via native
382 > * MDM. Return `undefined` to omit the key (absent or malformed value). Note an empty array (the
383 > * `strictKnownMarketplaces` lockdown case) is returned as-is, not omitted.
384 > */
385 > readonly encode: (value: unknown, onWarn?: (msg: string) => void) => unknown;
386 > }
387 >
388 > /**
389 > * Encode a managed-settings value into a canonical `{ [k]: string }` map: keeps string values
390 > * as-is and coerces number/boolean values to strings; drops keys with non-primitive values.
391 > * Returns `undefined` for a non-object input so the structured key is omitted.
392 > */
393 function encodeStringMap(value: unknown): Record<string, string> | undefined {
394 if (!isObject(value)) {
408 return out;
409 }
411 > /** Pass an object value through unchanged; omit the key for any non-object value. */
412 function encodeObject(value: unknown): object | undefined {
413 return isObject(value) ? value : undefined;
414 }
416 > /** Pass an array value through unchanged (including an empty array); omit the key otherwise. */
417 function encodeArray(value: unknown): unknown[] | undefined {
418 return Array.isArray(value) ? value : undefined;
419 }
421 > /**
422 > * Encode the schema's `{ [id]: { source } }` marketplace map into the canonical
423 > * `{ [name]: url-or-shorthand }` dict; drops malformed entries (with an optional warning) and omits
424 > * the key when there are none.
425 > */
426 function encodeExtraMarketplaces(value: unknown, onWarn?: (msg: string) => void): Record<string, string> | undefined {
427 return extraKnownMarketplacesToConfigDict(normalizeExtraKnownMarketplaces(value, onWarn));
428 }
430 > const STRUCTURED_MANAGED_SETTINGS: readonly IStructuredManagedSetting[] = [
431 > {
432 > key: COPILOT_ENABLED_PLUGINS_KEY,
433 > encode: encodeObject,
434 > },
435 > {
436 > key: COPILOT_STRICT_MARKETPLACES_KEY,
437 > encode: encodeArray,
438 > },
439 > {
440 > key: COPILOT_ALLOWED_MCP_SERVERS_KEY,
441 > encode: encodeArray,
442 > },
443 > {
444 > key: COPILOT_DENIED_MCP_SERVERS_KEY,
445 > encode: encodeArray,
446 > },
447 > {
448 > key: COPILOT_EXTRA_MARKETPLACES_KEY,
449 > encode: encodeExtraMarketplaces,
450 > },
451 > {
452 > // Nested under `telemetry`; carried as a JSON-encoded `{ [k]: string }` map. Non-string
453 > // primitive values are coerced to strings; non-primitive values are dropped.
454 > key: COPILOT_OTEL_RESOURCE_ATTRIBUTES_KEY,
455 > encode: encodeStringMap,
456 > },
457 > {
458 > // Nested under `telemetry`; carried as a JSON-encoded `{ [k]: string }` map of OTLP headers.
459 > key: COPILOT_OTEL_HEADERS_KEY,
460 > encode: encodeStringMap,
461 > },
462 > ];
463 >
464 > /**
465 > * Read a (possibly nested) dot-separated key from a parsed managed-settings object, e.g.
466 > * `telemetry.resourceAttributes`. Returns `undefined` if any path segment is missing or not an
467 > * object. Single-segment keys behave like a plain property read.
468 > */
469 function readNestedManagedKey(obj: Record<string, unknown>, dottedKey: string): unknown {
470 let current: unknown = obj;
477 return current;
478 }
480 > /**
481 > * Return a copy of `obj` with the (possibly nested) dot-separated key removed, cloning only the
482 > * objects along the touched path so the original (and any shared sub-objects) stay untouched. The
483 > * spread-then-`delete` shape matches a destructuring rest: it copies own enumerable keys (including
484 > * an own `__proto__`) without triggering the inherited `__proto__` setter.
485 > */
486 function withNestedManagedKeyDeleted(obj: Record<string, unknown>, dottedKey: string): Record<string, unknown> {
487 const dot = dottedKey.indexOf('.');
498 return { ...obj, [head]: withNestedManagedKeyDeleted(child as Record<string, unknown>, dottedKey.slice(dot + 1)) };
499 }
501 > /**
502 > * Normalize a parsed managed-settings object (from the server `managed_settings` API, a file on
503 > * disk, or any other source using the managed-settings schema) into the canonical
504 > * `ManagedSettingsData` bag that the policy framework consumes. This is the **single**
505 > * normalization path for all delivery channels, so downstream projection and policy `value()`
506 > * callbacks behave identically regardless of source. It does not enforce the declared
507 > * `managedSettings` schema — dropping undeclared or type-mismatched keys happens later, at
508 > * {@link projectManagedSettings}.
509 > *
510 > * - Scalar leaves (`permissions.*` and any forward-compatible scalar keys) are flattened into
511 > * dot-separated keys.
512 > * - Structured settings (declared in {@link STRUCTURED_MANAGED_SETTINGS}) are carried as canonical
513 > * JSON strings under a single key each — the same shape an admin authors via native MDM.
514 > * `PolicyConfiguration` parses the JSON back into the object-typed setting on read.
515 > * `extraKnownMarketplaces` is normalized from the schema's `{ [id]: { source } }` map to the
516 > * `{ [name]: url-or-shorthand }` dict.
517 > *
518 > * Malformed marketplace entries are dropped (with an optional warning via {@link onWarn}) rather
519 > * than throwing, so a bad enterprise settings file degrades gracefully instead of blocking startup.
520 > */
521 > export function normalizeManagedSettings(parsed: Record<string, unknown>, onWarn?: (msg: string) => void): ManagedSettingsData {
522 // Spread + delete (not for..in + assignment) so the scalar remainder keeps exact `{ ...rest }`
523 // semantics: it never triggers the inherited `__proto__` setter for a source-sent own
540 return result;
541 }
543 > /**
544 > * Normalize the schema's `{ [id]: { source } }` marketplace map into an
545 > * {@link IExtraKnownMarketplaceEntry} array, preserving the marketplace `name`,
546 > * source discriminator, and any `ref`. Malformed or off-spec entries are dropped
547 > * (with an optional warning via {@link onWarn}).
548 > */
549 function normalizeExtraKnownMarketplaces(value: unknown, onWarn?: (msg: string) => void): IExtraKnownMarketplaceEntry[] | undefined {
550 if (!isObject(value)) {
576 return entries;
577 }
579 > export const IFileManagedSettingsService = createDecorator<IFileManagedSettingsService>('fileManagedSettingsService');
580 >
581 > export interface IFileManagedSettingsService {
582 > readonly _serviceBrand: undefined;
583 > readonly rawManagedSettings: RawManagedSettingsData;
584 > readonly managedSettings: ManagedSettingsData;
585 > readonly onDidChangeRawManagedSettings: Event<RawManagedSettingsData>;
586 > readonly onDidChangeManagedSettings: Event<ManagedSettingsData>;
587 > }
588 >
589 > export class NullFileManagedSettingsService implements IFileManagedSettingsService {
590 readonly _serviceBrand: undefined;
591 readonly rawManagedSettings: RawManagedSettingsData = {};
593 readonly onDidChangeRawManagedSettings = Event.None;
594 readonly onDidChangeManagedSettings = Event.None;
src/vs/base/common/uri.ts 357 covered LOC · 52 ranges

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- korean.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > // allow-any-unicode-comment-file
7 >
8 > /**
9 > * Gets alternative Korean characters for the character code. This will return the ascii
10 > * character code(s) that a Hangul character may have been input with using a qwerty layout.
11 > *
12 > * This only aims to cover modern (not archaic) Hangul syllables.
13 > *
14 > * @param code The character code to get alternate characters for
15 > */
16 > export function getKoreanAltChars(code: number): ArrayLike<number> | undefined {
17 const result = disassembleKorean(code);
18 if (result && result.length > 0) {
21 return undefined;
22 }
23 > korean.ts
24 > let codeBufferLength = 0;
25 > const codeBuffer = new Uint32Array(10);
26 function disassembleKorean(code: number): Uint32Array | undefined {
27 codeBufferLength = 0;
91 return undefined;
92 }
93 > korean.ts
94 function getCodesFromArray(code: number, array: ArrayLike<number>, arrayStartIndex: number): void {
95 // Verify the code is within the array's range
98 }
99 }
100 > korean.ts
101 function addCodesToBuffer(codes: number): void {
102 // NUL is ignored, this is used for archaic characters to avoid using a Map
114 }
115 }
116 > korean.ts
117 > const enum HangulRangeStartCode {
118 > InitialConsonant = 0x1100,
119 > Vowel = 0x1161,
120 > FinalConsonant = 0x11A8,
121 > CompatibilityJamo = 0x3131,
122 > }
123 >
124 > const enum AsciiCode {
125 > NUL = 0,
126 > A = 65,
127 > B = 66,
128 > C = 67,
129 > D = 68,
130 > E = 69,
131 > F = 70,
132 > G = 71,
133 > H = 72,
134 > I = 73,
135 > J = 74,
136 > K = 75,
137 > L = 76,
138 > M = 77,
139 > N = 78,
140 > O = 79,
141 > P = 80,
142 > Q = 81,
143 > R = 82,
144 > S = 83,
145 > T = 84,
146 > U = 85,
147 > V = 86,
148 > W = 87,
149 > X = 88,
150 > Y = 89,
151 > Z = 90,
152 > a = 97,
153 > b = 98,
154 > c = 99,
155 > d = 100,
156 > e = 101,
157 > f = 102,
158 > g = 103,
159 > h = 104,
160 > i = 105,
161 > j = 106,
162 > k = 107,
163 > l = 108,
164 > m = 109,
165 > n = 110,
166 > o = 111,
167 > p = 112,
168 > q = 113,
169 > r = 114,
170 > s = 115,
171 > t = 116,
172 > u = 117,
173 > v = 118,
174 > w = 119,
175 > x = 120,
176 > y = 121,
177 > z = 122,
178 > }
179 >
180 > /**
181 > * Numbers that represent multiple ascii codes. These are precomputed at compile time to reduce
182 > * bundle and runtime overhead.
183 > */
184 > const enum AsciiCodeCombo {
185 > fa = AsciiCode.a << 8 | AsciiCode.f,
186 > fg = AsciiCode.g << 8 | AsciiCode.f,
187 > fq = AsciiCode.q << 8 | AsciiCode.f,
188 > fr = AsciiCode.r << 8 | AsciiCode.f,
189 > ft = AsciiCode.t << 8 | AsciiCode.f,
190 > fv = AsciiCode.v << 8 | AsciiCode.f,
191 > fx = AsciiCode.x << 8 | AsciiCode.f,
192 > hk = AsciiCode.k << 8 | AsciiCode.h,
193 > hl = AsciiCode.l << 8 | AsciiCode.h,
194 > ho = AsciiCode.o << 8 | AsciiCode.h,
195 > ml = AsciiCode.l << 8 | AsciiCode.m,
196 > nj = AsciiCode.j << 8 | AsciiCode.n,
197 > nl = AsciiCode.l << 8 | AsciiCode.n,
198 > np = AsciiCode.p << 8 | AsciiCode.n,
199 > qt = AsciiCode.t << 8 | AsciiCode.q,
200 > rt = AsciiCode.t << 8 | AsciiCode.r,
201 > sg = AsciiCode.g << 8 | AsciiCode.s,
202 > sw = AsciiCode.w << 8 | AsciiCode.s,
203 > }
204 >
205 > /**
206 > * Hangul Jamo - Modern consonants #1
207 > *
208 > * Range U+1100..U+1112
209 > *
210 > * | | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
211 > * |--------|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
212 > * | U+110x | ᄀ | ᄁ | ᄂ | ᄃ | ᄄ | ᄅ | ᄆ | ᄇ | ᄈ | ᄉ | ᄊ | ᄋ | ᄌ | ᄍ | ᄎ | ᄏ |
213 > * | U+111x | ᄐ | ᄑ | ᄒ |
214 > */
215 > const modernConsonants = new Uint8Array([
216 > AsciiCode.r, // ㄱ
217 > AsciiCode.R, // ㄲ
218 > AsciiCode.s, // ㄴ
219 > AsciiCode.e, // ㄷ
220 > AsciiCode.E, // ㄸ
221 > AsciiCode.f, // ㄹ
222 > AsciiCode.a, // ㅁ
223 > AsciiCode.q, // ㅂ
224 > AsciiCode.Q, // ㅃ
225 > AsciiCode.t, // ㅅ
226 > AsciiCode.T, // ㅆ
227 > AsciiCode.d, // ㅇ
228 > AsciiCode.w, // ㅈ
229 > AsciiCode.W, // ㅉ
230 > AsciiCode.c, // ㅊ
231 > AsciiCode.z, // ㅋ
232 > AsciiCode.x, // ㅌ
233 > AsciiCode.v, // ㅍ
234 > AsciiCode.g, // ㅎ
235 > ]);
236 >
237 > /**
238 > * Hangul Jamo - Modern Vowels
239 > *
240 > * Range U+1161..U+1175
241 > *
242 > * | | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
243 > * |--------|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
244 > * | U+116x | | ᅡ | ᅢ | ᅣ | ᅤ | ᅥ | ᅦ | ᅧ | ᅨ | ᅩ | ᅪ | ᅫ | ᅬ | ᅭ | ᅮ | ᅯ |
245 > * | U+117x | ᅰ | ᅱ | ᅲ | ᅳ | ᅴ | ᅵ |
246 > */
247 > const modernVowels = new Uint16Array([
248 > AsciiCode.k, // -> ㅏ
249 > AsciiCode.o, // -> ㅐ
250 > AsciiCode.i, // -> ㅑ
251 > AsciiCode.O, // -> ㅒ
252 > AsciiCode.j, // -> ㅓ
253 > AsciiCode.p, // -> ㅔ
254 > AsciiCode.u, // -> ㅕ
255 > AsciiCode.P, // -> ㅖ
256 > AsciiCode.h, // -> ㅗ
257 > AsciiCodeCombo.hk, // -> ㅘ
258 > AsciiCodeCombo.ho, // -> ㅙ
259 > AsciiCodeCombo.hl, // -> ㅚ
260 > AsciiCode.y, // -> ㅛ
261 > AsciiCode.n, // -> ㅜ
262 > AsciiCodeCombo.nj, // -> ㅝ
263 > AsciiCodeCombo.np, // -> ㅞ
264 > AsciiCodeCombo.nl, // -> ㅟ
265 > AsciiCode.b, // -> ㅠ
266 > AsciiCode.m, // -> ㅡ
267 > AsciiCodeCombo.ml, // -> ㅢ
268 > AsciiCode.l, // -> ㅣ
269 > ]);
270 >
271 > /**
272 > * Hangul Jamo - Modern Consonants #2
273 > *
274 > * Range U+11A8..U+11C2
275 > *
276 > * | | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
277 > * |--------|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
278 > * | U+11Ax | | | | | | | | | ᆨ | ᆩ | ᆪ | ᆫ | ᆬ | ᆭ | ᆮ | ᆯ |
279 > * | U+11Bx | ᆰ | ᆱ | ᆲ | ᆳ | ᆴ | ᆵ | ᆶ | ᆷ | ᆸ | ᆹ | ᆺ | ᆻ | ᆼ | ᆽ | ᆾ | ᆿ |
280 > * | U+11Cx | ᇀ | ᇁ | ᇂ |
281 > */
282 > const modernFinalConsonants = new Uint16Array([
283 > AsciiCode.r, // ㄱ
284 > AsciiCode.R, // ㄲ
285 > AsciiCodeCombo.rt, // ㄳ
286 > AsciiCode.s, // ㄴ
287 > AsciiCodeCombo.sw, // ㄵ
288 > AsciiCodeCombo.sg, // ㄶ
289 > AsciiCode.e, // ㄷ
290 > AsciiCode.f, // ㄹ
291 > AsciiCodeCombo.fr, // ㄺ
292 > AsciiCodeCombo.fa, // ㄻ
293 > AsciiCodeCombo.fq, // ㄼ
294 > AsciiCodeCombo.ft, // ㄽ
295 > AsciiCodeCombo.fx, // ㄾ
296 > AsciiCodeCombo.fv, // ㄿ
297 > AsciiCodeCombo.fg, // ㅀ
298 > AsciiCode.a, // ㅁ
299 > AsciiCode.q, // ㅂ
300 > AsciiCodeCombo.qt, // ㅄ
301 > AsciiCode.t, // ㅅ
302 > AsciiCode.T, // ㅆ
303 > AsciiCode.d, // ㅇ
304 > AsciiCode.w, // ㅈ
305 > AsciiCode.c, // ㅊ
306 > AsciiCode.z, // ㅋ
307 > AsciiCode.x, // ㅌ
308 > AsciiCode.v, // ㅍ
309 > AsciiCode.g, // ㅎ
310 > ]);
311 >
312 > /**
313 > * Hangul Compatibility Jamo
314 > *
315 > * Range U+3131..U+318F
316 > *
317 > * This includes range includes archaic jamo which we don't consider, these are
318 > * given the NUL character code in order to be ignored.
319 > *
320 > * | | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
321 > * |--------|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
322 > * | U+313x | | ㄱ | ㄲ | ㄳ | ㄴ | ㄵ | ㄶ | ㄷ | ㄸ | ㄹ | ㄺ | ㄻ | ㄼ | ㄽ | ㄾ | ㄿ |
323 > * | U+314x | ㅀ | ㅁ | ㅂ | ㅃ | ㅄ | ㅅ | ㅆ | ㅇ | ㅈ | ㅉ | ㅊ | ㅋ | ㅌ | ㅍ | ㅎ | ㅏ |
324 > * | U+315x | ㅐ | ㅑ | ㅒ | ㅓ | ㅔ | ㅕ | ㅖ | ㅗ | ㅘ | ㅙ | ㅚ | ㅛ | ㅜ | ㅝ | ㅞ | ㅟ |
325 > * | U+316x | ㅠ | ㅡ | ㅢ | ㅣ | HF | ㅥ | ㅦ | ㅧ | ㅨ | ㅩ | ㅪ | ㅫ | ㅬ | ㅭ | ㅮ | ㅯ |
326 > * | U+317x | ㅰ | ㅱ | ㅲ | ㅳ | ㅴ | ㅵ | ㅶ | ㅷ | ㅸ | ㅹ | ㅺ | ㅻ | ㅼ | ㅽ | ㅾ | ㅿ |
327 > * | U+318x | ㆀ | ㆁ | ㆂ | ㆃ | ㆄ | ㆅ | ㆆ | ㆇ | ㆈ | ㆉ | ㆊ | ㆋ | ㆌ | ㆍ | ㆎ |
328 > */
329 > const compatibilityJamo = new Uint16Array([
330 > AsciiCode.r, // ㄱ
331 > AsciiCode.R, // ㄲ
332 > AsciiCodeCombo.rt, // ㄳ
333 > AsciiCode.s, // ㄴ
334 > AsciiCodeCombo.sw, // ㄵ
335 > AsciiCodeCombo.sg, // ㄶ
336 > AsciiCode.e, // ㄷ
337 > AsciiCode.E, // ㄸ
338 > AsciiCode.f, // ㄹ
339 > AsciiCodeCombo.fr, // ㄺ
340 > AsciiCodeCombo.fa, // ㄻ
341 > AsciiCodeCombo.fq, // ㄼ
342 > AsciiCodeCombo.ft, // ㄽ
343 > AsciiCodeCombo.fx, // ㄾ
344 > AsciiCodeCombo.fv, // ㄿ
345 > AsciiCodeCombo.fg, // ㅀ
346 > AsciiCode.a, // ㅁ
347 > AsciiCode.q, // ㅂ
348 > AsciiCode.Q, // ㅃ
349 > AsciiCodeCombo.qt, // ㅄ
350 > AsciiCode.t, // ㅅ
351 > AsciiCode.T, // ㅆ
352 > AsciiCode.d, // ㅇ
353 > AsciiCode.w, // ㅈ
354 > AsciiCode.W, // ㅉ
355 > AsciiCode.c, // ㅊ
356 > AsciiCode.z, // ㅋ
357 > AsciiCode.x, // ㅌ
358 > AsciiCode.v, // ㅍ
359 > AsciiCode.g, // ㅎ
360 > AsciiCode.k, // ㅏ
361 > AsciiCode.o, // ㅐ
362 > AsciiCode.i, // ㅑ
363 > AsciiCode.O, // ㅒ
364 > AsciiCode.j, // ㅓ
365 > AsciiCode.p, // ㅔ
366 > AsciiCode.u, // ㅕ
367 > AsciiCode.P, // ㅖ
368 > AsciiCode.h, // ㅗ
369 > AsciiCodeCombo.hk, // ㅘ
370 > AsciiCodeCombo.ho, // ㅙ
371 > AsciiCodeCombo.hl, // ㅚ
372 > AsciiCode.y, // ㅛ
373 > AsciiCode.n, // ㅜ
374 > AsciiCodeCombo.nj, // ㅝ
375 > AsciiCodeCombo.np, // ㅞ
376 > AsciiCodeCombo.nl, // ㅟ
377 > AsciiCode.b, // ㅠ
378 > AsciiCode.m, // ㅡ
379 > AsciiCodeCombo.ml, // ㅢ
380 > AsciiCode.l, // ㅣ
381 > // HF: Hangul Filler (everything after this is archaic)
382 > // ㅥ
383 > // ㅦ
384 > // ㅧ
385 > // ㅨ
386 > // ㅩ
387 > // ㅪ
388 > // ㅫ
389 > // ㅬ
390 > // ㅮ
391 > // ㅯ
392 > // ㅰ
393 > // ㅱ
394 > // ㅲ
395 > // ㅳ
396 > // ㅴ
397 > // ㅵ
398 > // ㅶ
399 > // ㅷ
400 > // ㅸ
401 > // ㅹ
402 > // ㅺ
403 > // ㅻ
404 > // ㅼ
405 > // ㅽ
406 > // ㅾ
407 > // ㅿ
408 > // ㆀ
409 > // ㆁ
410 > // ㆂ
411 > // ㆃ
412 > // ㆄ
413 > // ㆅ
414 > // ㆆ
415 > // ㆇ
416 > // ㆈ
417 > // ㆉ
418 > // ㆊ
419 > // ㆋ
420 > // ㆌ
421 > // ㆍ
422 > // ㆎ
423 > ]);
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/workbench/api/common/extHostExtensionService.ts 324 covered LOC · 64 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostExtensionService.ts
2 > * Copyright (c) Microsoft 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 * as path from '../../../base/common/path.js';
8 > import * as performance from '../../../base/common/performance.js';
9 > import { originalFSPath, joinPath, extUriBiasedIgnorePathCase } from '../../../base/common/resources.js';
10 > import { asPromise, Barrier, IntervalTimer, timeout } from '../../../base/common/async.js';
11 > import { dispose, toDisposable, Disposable, DisposableStore, IDisposable } from '../../../base/common/lifecycle.js';
12 > import { TernarySearchTree } from '../../../base/common/ternarySearchTree.js';
13 > import { URI, UriComponents } from '../../../base/common/uri.js';
14 > import { ILogService } from '../../../platform/log/common/log.js';
15 > import { ExtHostExtensionServiceShape, MainContext, MainThreadExtensionServiceShape, MainThreadTelemetryShape, MainThreadWorkspaceShape } from './extHost.protocol.js';
16 > import { IExtensionDescriptionDelta, IExtensionHostInitData } from '../../services/extensions/common/extensionHostProtocol.js';
17 > import { ExtHostConfiguration, IExtHostConfiguration } from './extHostConfiguration.js';
18 > import { ActivatedExtension, EmptyExtension, ExtensionActivationTimes, ExtensionActivationTimesBuilder, ExtensionsActivator, IExtensionAPI, IExtensionModule, HostExtension, ExtensionActivationTimesFragment } from './extHostExtensionActivator.js';
19 > import { ExtHostStorage, IExtHostStorage } from './extHostStorage.js';
20 > import { ExtHostWorkspace, IExtHostWorkspace } from './extHostWorkspace.js';
21 > import { MissingExtensionDependency, ActivationKind, checkProposedApiEnabled, isProposedApiEnabled, ExtensionActivationReason, IProposedApiUsage, setProposedApiUsageReporter, setEnabledApiProposalsFallbackExperiment } from '../../services/extensions/common/extensions.js';
22 > import { ExtensionDescriptionRegistry, IActivationEventsReader } from '../../services/extensions/common/extensionDescriptionRegistry.js';
23 > import * as errors from '../../../base/common/errors.js';
24 > import type * as vscode from 'vscode';
25 > import { ExtensionIdentifier, ExtensionIdentifierMap, ExtensionIdentifierSet, IExtensionDescription } from '../../../platform/extensions/common/extensions.js';
26 > import { VSBuffer } from '../../../base/common/buffer.js';
27 > import { ExtensionGlobalMemento, ExtensionMemento } from './extHostMemento.js';
28 > import { RemoteAuthorityResolverError, ExtensionKind, ExtensionMode, ExtensionRuntime, ManagedResolvedAuthority as ExtHostManagedResolvedAuthority } from './extHostTypes.js';
29 > import { ResolvedAuthority, ResolvedOptions, RemoteAuthorityResolverErrorCode, IRemoteConnectionData, getRemoteAuthorityPrefix, TunnelInformation, ManagedRemoteConnection, WebSocketRemoteConnection } from '../../../platform/remote/common/remoteAuthorityResolver.js';
30 > import { IInstantiationService, createDecorator } from '../../../platform/instantiation/common/instantiation.js';
31 > import { IExtHostInitDataService } from './extHostInitDataService.js';
32 > import { IExtensionStoragePaths } from './extHostStoragePaths.js';
33 > import { IExtHostRpcService } from './extHostRpcService.js';
34 > import { ServiceCollection } from '../../../platform/instantiation/common/serviceCollection.js';
35 > import { IExtHostTunnelService } from './extHostTunnelService.js';
36 > import { IExtHostTerminalService } from './extHostTerminalService.js';
37 > import { IExtHostLanguageModels } from './extHostLanguageModels.js';
38 > import { Emitter, Event } from '../../../base/common/event.js';
39 > import { IExtensionActivationHost, checkActivateWorkspaceContainsExtension } from '../../services/extensions/common/workspaceContains.js';
40 > import { ExtHostSecretState, IExtHostSecretState } from './extHostSecretState.js';
41 > import { ExtensionSecrets } from './extHostSecrets.js';
42 > import { Schemas } from '../../../base/common/network.js';
43 > import { IResolveAuthorityResult } from '../../services/extensions/common/extensionHostProxy.js';
44 > import { IExtHostLocalizationService } from './extHostLocalizationService.js';
45 > import { StopWatch } from '../../../base/common/stopwatch.js';
46 > import { isCI, setTimeout0 } from '../../../base/common/platform.js';
47 > import { IExtHostManagedSockets } from './extHostManagedSockets.js';
48 > import { Dto } from '../../services/extensions/common/proxyIdentifier.js';
49 >
50 > interface ITestRunner {
51 > /** Old test runner API, as exported from `vscode/lib/testrunner` */
52 > run(testsRoot: string, clb: (error: Error, failures?: number) => void): void;
53 > }
54 >
55 > interface INewTestRunner {
56 > /** New test runner API, as explained in the extension test doc */
57 > run(): Promise<void>;
58 > }
59 >
60 > export const IHostUtils = createDecorator<IHostUtils>('IHostUtils');
61 >
62 > export interface IHostUtils {
63 > readonly _serviceBrand: undefined;
64 > readonly pid: number | undefined;
65 > exit(code: number): void;
66 > fsExists?(path: string): Promise<boolean>;
67 > fsRealpath?(path: string): Promise<string>;
68 > }
69 >
70 > type TelemetryActivationEventFragment = {
71 > id: { classification: 'PublicNonPersonalData'; purpose: 'FeatureInsight'; comment: 'The identifier of an extension' };
72 > name: { classification: 'PublicNonPersonalData'; purpose: 'FeatureInsight'; comment: 'The name of the extension' };
73 > extensionVersion: { classification: 'PublicNonPersonalData'; purpose: 'FeatureInsight'; comment: 'The version of the extension' };
74 > publisherDisplayName: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The publisher of the extension' };
75 > activationEvents: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'All activation events of the extension' };
76 > isBuiltin: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'If the extension is builtin or git installed' };
77 > reason: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The activation event' };
78 > reasonId: { classification: 'PublicNonPersonalData'; purpose: 'FeatureInsight'; comment: 'The identifier of the activation event' };
79 > };
80 >
81 > export abstract class AbstractExtHostExtensionService extends Disposable implements ExtHostExtensionServiceShape {
82 >
83 > readonly _serviceBrand: undefined;
84 >
85 > abstract readonly extensionRuntime: ExtensionRuntime;
86 >
87 > private readonly _onDidChangeRemoteConnectionData = this._register(new Emitter<void>());
88 > public readonly onDidChangeRemoteConnectionData = this._onDidChangeRemoteConnectionData.event;
89 >
90 > protected readonly _hostUtils: IHostUtils;
91 > protected readonly _initData: IExtensionHostInitData;
92 > protected readonly _extHostContext: IExtHostRpcService;
93 > protected readonly _instaService: IInstantiationService;
94 > protected readonly _extHostWorkspace: ExtHostWorkspace;
95 > protected readonly _extHostConfiguration: ExtHostConfiguration;
96 > protected readonly _logService: ILogService;
97 > protected readonly _extHostTunnelService: IExtHostTunnelService;
98 > protected readonly _extHostTerminalService: IExtHostTerminalService;
99 > protected readonly _extHostLocalizationService: IExtHostLocalizationService;
100 >
101 > protected readonly _mainThreadWorkspaceProxy: MainThreadWorkspaceShape;
102 > protected readonly _mainThreadTelemetryProxy: MainThreadTelemetryShape;
103 > protected readonly _mainThreadExtensionsProxy: MainThreadExtensionServiceShape;
104 >
105 > private readonly _almostReadyToRunExtensions: Barrier;
106 > private readonly _readyToStartExtensionHost: Barrier;
107 > private readonly _readyToRunExtensions: Barrier;
108 > private readonly _eagerExtensionsActivated: Barrier;
109 >
110 > private readonly _activationEventsReader: SyncedActivationEventsReader;
111 > protected readonly _myRegistry: ExtensionDescriptionRegistry;
112 > protected readonly _globalRegistry: ExtensionDescriptionRegistry;
113 > private readonly _storage: ExtHostStorage;
114 > private readonly _secretState: ExtHostSecretState;
115 > private readonly _storagePath: IExtensionStoragePaths;
116 > private readonly _activator: ExtensionsActivator;
117 > private _extensionPathIndex: Promise<ExtensionPaths> | null;
118 > private _realPathCache = new Map<string, Promise<string>>();
119 >
120 > private readonly _resolvers: { [authorityPrefix: string]: vscode.RemoteAuthorityResolver };
121 >
122 > private _started: boolean;
123 > private _isTerminating: boolean = false;
124 > private _remoteConnectionData: IRemoteConnectionData | null;
125 >
126 > constructor(
127 @IInstantiationService instaService: IInstantiationService,
128 @IHostUtils hostUtils: IHostUtils,
212 this._register(setEnabledApiProposalsFallbackExperiment(this._initData.enabledApiProposalsFallback, this._initData.quality));
213 }
215 > private _reportProposedApiUsage(usage: IProposedApiUsage): void {
216 type ProposedApiUsageClassification = {
217 owner: 'alexr00';
229 });
230 }
232 > public getRemoteConnectionData(): IRemoteConnectionData | null {
233 return this._remoteConnectionData;
234 }
236 > public async initialize(): Promise<void> {
237 try {
238
251 }
252 }
254 > private async _deactivateAll(): Promise<void> {
255 this._storagePath.onWillDeactivateAll();
256
269 await Promise.all(allPromises);
270 }
272 > public terminate(reason: string, code: number = 0): void {
273 if (this._isTerminating) {
274 // we are already shutting down...
303 });
304 }
306 > public isActivated(extensionId: ExtensionIdentifier): boolean {
307 if (this._readyToRunExtensions.isOpen()) {
308 return this._activator.isActivated(extensionId);
310 return false;
311 }
313 > public async getExtension(extensionId: string): Promise<IExtensionDescription | undefined> {
314 const ext = await this._mainThreadExtensionsProxy.$getExtension(extensionId);
315 return ext && {
319 };
320 }
322 > private _activateByEvent(activationEvent: string, startup: boolean): Promise<void> {
323 return this._activator.activateByEvent(activationEvent, startup);
324 }
326 > private _activateById(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<void> {
327 return this._activator.activateById(extensionId, reason);
328 }
330 > public activateByIdWithErrors(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<void> {
331 return this._activateById(extensionId, reason).then(() => {
332 const extension = this._activator.getActivatedExtension(extensionId);
338 });
339 }
341 > public getExtensionRegistry(): Promise<ExtensionDescriptionRegistry> {
342 return this._readyToRunExtensions.wait().then(_ => this._myRegistry);
343 }
345 > public getExtensionExports(extensionId: ExtensionIdentifier): IExtensionAPI | null | undefined {
346 if (this._readyToRunExtensions.isOpen()) {
347 return this._activator.getActivatedExtension(extensionId).exports;
354 }
355 }
357 > /**
358 > * Applies realpath to file-uris and returns all others uris unmodified.
359 > * The real path is cached for the lifetime of the extension host.
360 > */
361 > private async _realPathExtensionUri(uri: URI): Promise<URI> {
362 if (uri.scheme === Schemas.file && this._hostUtils.fsRealpath) {
363 const fsPath = uri.fsPath;
370 return uri;
371 }
373 > // create trie to enable fast 'filename -> extension id' look up
374 > public async getExtensionPathIndex(): Promise<ExtensionPaths> {
375 if (!this._extensionPathIndex) {
376 this._extensionPathIndex = this._createExtensionPathIndex(this._myRegistry.getAllExtensionDescriptions()).then((searchTree) => {
380 return this._extensionPathIndex;
381 }
383 > /**
384 > * create trie to enable fast 'filename -> extension id' look up
385 > */
386 > private async _createExtensionPathIndex(extensions: IExtensionDescription[]): Promise<TernarySearchTree<URI, IExtensionDescription>> {
387 const tst = TernarySearchTree.forUris<IExtensionDescription>(key => {
388 // using the default/biased extUri-util because the IExtHostFileSystemInfo-service
400 return tst;
401 }
403 > private _deactivate(extensionId: ExtensionIdentifier): Promise<void> {
404 let result = Promise.resolve(undefined);
405
440 return result;
441 }
443 > // --- impl
444 >
445 > private async _activateExtension(extensionDescription: IExtensionDescription, reason: ExtensionActivationReason): Promise<ActivatedExtension> {
446 if (!this._initData.remote.isRemote) {
447 // local extension host process
462 });
463 }
465 > private _logExtensionActivationTimes(extensionDescription: IExtensionDescription, reason: ExtensionActivationReason, outcome: string, activationTimes?: ExtensionActivationTimes) {
466 const event = getTelemetryActivationEvent(extensionDescription, reason);
467 type ExtensionActivationTimesClassification = {
488 });
489 }
491 > private _doActivateExtension(extensionDescription: IExtensionDescription, reason: ExtensionActivationReason): Promise<ActivatedExtension> {
492 const event = getTelemetryActivationEvent(extensionDescription, reason);
493 type ActivatePluginClassification = {
522 });
523 }
525 > private _loadExtensionContext(extensionDescription: IExtensionDescription, extensionInternalStore: DisposableStore): Promise<vscode.ExtensionContext> {
526
527 const languageModelAccessInformation = this._extHostLanguageModels.createLanguageModelAccessInformation(extensionDescription);
596 });
597 }
599 > private static _callActivate(logService: ILogService, extensionId: ExtensionIdentifier, extensionModule: IExtensionModule, context: vscode.ExtensionContext, extensionInternalStore: IDisposable, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<ActivatedExtension> {
600 // Make sure the extension's surface is not undefined
601 extensionModule = extensionModule || {
611 });
612 }
614 > private static _callActivateOptional(logService: ILogService, extensionId: ExtensionIdentifier, extensionModule: IExtensionModule, context: vscode.ExtensionContext, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<IExtensionAPI> {
615 if (typeof extensionModule.activate === 'function') {
616 try {
633 }
634 }
636 > // -- eager activation
637 >
638 > private _activateOneStartupFinished(desc: IExtensionDescription, activationEvent: string): void {
639 this._activateById(desc.identifier, {
640 startup: false,
645 });
646 }
648 > private _activateAllStartupFinishedDeferred(extensions: IExtensionDescription[], start: number = 0): void {
649 const timeBudget = 50; // 50 milliseconds
650 const startTime = Date.now();
668 });
669 }
671 > private _activateAllStartupFinished(): void {
672 // startup is considered finished
673 this._mainThreadExtensionsProxy.$setPerformanceMarks(performance.getMarks());
691 });
692 }
694 > // Handle "eager" activation extensions
695 > private _handleEagerExtensions(): Promise<void> {
696 const starActivation = this._activateByEvent('*', true).then(undefined, (err) => {
697 this._logService.error(err);
710 return eagerExtensionsActivation;
711 }
713 > private _handleWorkspaceContainsEagerExtensions(folders: ReadonlyArray<vscode.WorkspaceFolder>): Promise<void> {
714 if (folders.length === 0) {
715 return Promise.resolve(undefined);
722 ).then(() => { });
723 }
725 > private async _handleWorkspaceContainsEagerExtension(folders: ReadonlyArray<vscode.WorkspaceFolder>, desc: IExtensionDescription): Promise<void> {
726 if (this.isActivated(desc.identifier)) {
727 return;
747 );
748 }
750 > private async _handleRemoteResolverEagerExtensions(): Promise<void> {
751 if (this._initData.remote.authority) {
752 return this._activateByEvent(`onResolveRemoteAuthority:${this._initData.remote.authority}`, false);
753 }
754 }
756 > public async $extensionTestsExecute(): Promise<number> {
757 await this._eagerExtensionsActivated.wait();
758 try {
763 }
764 }
766 > private async _doHandleExtensionTests(): Promise<number> {
767 const { extensionDevelopmentLocationURI, extensionTestsLocationURI } = this._initData.environment;
768 if (!extensionDevelopmentLocationURI || !extensionTestsLocationURI) {
824 });
825 }
827 > private _startExtensionHost(): Promise<void> {
828 if (this._started) {
829 throw new Error(`Extension host is already started!`);
843 });
844 }
846 > // -- called by extensions
847 >
848 > public registerRemoteAuthorityResolver(authorityPrefix: string, resolver: vscode.RemoteAuthorityResolver): vscode.Disposable {
849 this._resolvers[authorityPrefix] = resolver;
850 return toDisposable(() => {
852 });
853 }
855 > public async getRemoteExecServer(remoteAuthority: string): Promise<vscode.ExecServer | undefined> {
856 const { resolver } = await this._activateAndGetResolver(remoteAuthority);
857 return resolver?.resolveExecServer?.(remoteAuthority, { resolveAttempt: 0 });
858 }
860 > // -- called by main thread
861 >
862 > private async _activateAndGetResolver(remoteAuthority: string): Promise<{ authorityPrefix: string; resolver: vscode.RemoteAuthorityResolver | undefined }> {
863 const authorityPlusIndex = remoteAuthority.indexOf('+');
864 if (authorityPlusIndex === -1) {
872 return { authorityPrefix, resolver: this._resolvers[authorityPrefix] };
873 }
875 > public async $resolveAuthority(remoteAuthorityChain: string, resolveAttempt: number): Promise<Dto<IResolveAuthorityResult>> {
876 const sw = StopWatch.create(false);
877 const prefix = () => `[resolveAuthority(${getRemoteAuthorityPrefix(remoteAuthorityChain)},${resolveAttempt})][${sw.elapsed()}ms] `;
1003 };
1004 }
1006 > public async $getCanonicalURI(remoteAuthority: string, uriComponents: UriComponents): Promise<UriComponents | null> {
1007 this._logService.info(`$getCanonicalURI invoked for authority (${getRemoteAuthorityPrefix(remoteAuthority)})`);
1008
1027 return result;
1028 }
1030 > public async $startExtensionHost(extensionsDelta: IExtensionDescriptionDelta): Promise<void> {
1031 // eslint-disable-next-line local/code-no-any-casts
1032 extensionsDelta.toAdd.forEach((extension) => (<any>extension).extensionLocation = URI.revive(extension.extensionLocation));
1046 return this._startExtensionHost();
1047 }
1049 > public $activateByEvent(activationEvent: string, activationKind: ActivationKind): Promise<void> {
1050 if (activationKind === ActivationKind.Immediate) {
1051 return this._almostReadyToRunExtensions.wait()
1058 );
1059 }
1061 > public async $activate(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<boolean> {
1062 await this._readyToRunExtensions.wait();
1063 if (!this._myRegistry.getExtensionDescription(extensionId)) {
1068 return true;
1069 }
1071 > public async $deltaExtensions(extensionsDelta: IExtensionDescriptionDelta): Promise<void> {
1072 // eslint-disable-next-line local/code-no-any-casts
1073 extensionsDelta.toAdd.forEach((extension) => (<any>extension).extensionLocation = URI.revive(extension.extensionLocation));
1088 return Promise.resolve(undefined);
1089 }
1091 > public async $test_latency(n: number): Promise<number> {
1092 return n;
1093 }
1095 > public async $test_up(b: VSBuffer): Promise<number> {
1096 return b.byteLength;
1097 }
1099 > public async $test_down(size: number): Promise<VSBuffer> {
1100 const buff = VSBuffer.alloc(size);
1101 const value = Math.random() % 256;
1105 return buff;
1106 }
1108 > public async $updateRemoteConnectionData(connectionData: IRemoteConnectionData): Promise<void> {
1109 this._remoteConnectionData = connectionData;
1110 this._onDidChangeRemoteConnectionData.fire();
1111 }
1113 > protected _isESM(extensionDescription: IExtensionDescription | undefined, modulePath?: string): boolean {
1114 modulePath ??= extensionDescription ? this._getEntryPoint(extensionDescription) : modulePath;
1115 return modulePath?.endsWith('.mjs') || (extensionDescription?.type === 'module' && !modulePath?.endsWith('.cjs'));
1116 }
1118 > protected abstract _beforeAlmostReadyToRunExtensions(): Promise<void>;
1119 > protected abstract _getEntryPoint(extensionDescription: IExtensionDescription): string | undefined;
1120 > protected abstract _loadCommonJSModule<T extends object | undefined>(extensionId: IExtensionDescription | null, module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<T>;
1121 > protected abstract _loadESMModule<T>(extension: IExtensionDescription | null, module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<T>;
1122 > public abstract $setRemoteEnvironment(env: { [key: string]: string | null }): Promise<void>;
1123 > }
1124 >
1125 function applyExtensionsDelta(activationEventsReader: SyncedActivationEventsReader, oldGlobalRegistry: ExtensionDescriptionRegistry, oldMyRegistry: ExtensionDescriptionRegistry, extensionsDelta: IExtensionDescriptionDelta) {
1126 activationEventsReader.addActivationEvents(extensionsDelta.addActivationEvents);
1139 return { globalRegistry, myExtensions };
1140 }
1142 > type TelemetryActivationEvent = {
1143 > id: string;
1144 > name: string;
1145 > extensionVersion: string;
1146 > publisherDisplayName: string;
1147 > activationEvents: string | null;
1148 > isBuiltin: boolean;
1149 > reason: string;
1150 > reasonId: string;
1151 > };
1152 >
1153 function getTelemetryActivationEvent(extensionDescription: IExtensionDescription, reason: ExtensionActivationReason): TelemetryActivationEvent {
1154 const event = {
1165 return event;
1166 }
1168 function printExtIds(registry: ExtensionDescriptionRegistry) {
1169 return registry.getAllExtensionDescriptions().map(ext => ext.identifier.value).join(',');
1170 }
1172 > export const IExtHostExtensionService = createDecorator<IExtHostExtensionService>('IExtHostExtensionService');
1173 >
1174 > export interface IExtHostExtensionService extends AbstractExtHostExtensionService {
1175 > readonly _serviceBrand: undefined;
1176 > initialize(): Promise<void>;
1177 > terminate(reason: string): void;
1178 > getExtension(extensionId: string): Promise<IExtensionDescription | undefined>;
1179 > isActivated(extensionId: ExtensionIdentifier): boolean;
1180 > activateByIdWithErrors(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<void>;
1181 > getExtensionExports(extensionId: ExtensionIdentifier): IExtensionAPI | null | undefined;
1182 > getExtensionRegistry(): Promise<ExtensionDescriptionRegistry>;
1183 > getExtensionPathIndex(): Promise<ExtensionPaths>;
1184 > registerRemoteAuthorityResolver(authorityPrefix: string, resolver: vscode.RemoteAuthorityResolver): vscode.Disposable;
1185 > getRemoteExecServer(authority: string): Promise<vscode.ExecServer | undefined>;
1186 >
1187 > readonly onDidChangeRemoteConnectionData: Event<void>;
1188 > getRemoteConnectionData(): IRemoteConnectionData | null;
1189 > }
1190 >
1191 > export class Extension<T extends object | null | undefined> implements vscode.Extension<T> {
1192 >
1193 > #extensionService: IExtHostExtensionService;
1194 #originExtensionId: ExtensionIdentifier;
1195 #identifier: ExtensionIdentifier;
1197 > readonly id: string;
1198 > readonly extensionUri: URI;
1199 > readonly extensionPath: string;
1200 > readonly packageJSON: IExtensionDescription;
1201 > readonly extensionKind: vscode.ExtensionKind;
1202 > readonly isFromDifferentExtensionHost: boolean;
1203 >
1204 > constructor(extensionService: IExtHostExtensionService, originExtensionId: ExtensionIdentifier, description: IExtensionDescription, kind: ExtensionKind, isFromDifferentExtensionHost: boolean) {
1205 this.#extensionService = extensionService;
1206 this.#originExtensionId = originExtensionId;
1213 this.isFromDifferentExtensionHost = isFromDifferentExtensionHost;
1214 }
1216 > get isActive(): boolean {
1217 // TODO@alexdima support this
1218 return this.#extensionService.isActivated(this.#identifier);
1219 }
1221 > get exports(): T {
1222 if (this.packageJSON.api === 'none' || this.isFromDifferentExtensionHost) {
1223 return undefined!; // Strict nulloverride - Public api
1225 return <T>this.#extensionService.getExtensionExports(this.#identifier);
1226 }
1228 > async activate(): Promise<T> {
1229 if (this.isFromDifferentExtensionHost) {
1230 throw new Error('Cannot activate foreign extension'); // TODO@alexdima support this
1233 return this.exports;
1234 }
1236 >
1237 function filterExtensions(globalRegistry: ExtensionDescriptionRegistry, desiredExtensions: ExtensionIdentifierSet): IExtensionDescription[] {
1238 return globalRegistry.getAllExtensionDescriptions().filter(
1240 );
1241 }
1243 > export class ExtensionPaths {
1244 >
1245 > constructor(
1246 private _searchTree: TernarySearchTree<URI, IExtensionDescription>
1247 ) { }
1249 > setSearchTree(searchTree: TernarySearchTree<URI, IExtensionDescription>): void {
1250 this._searchTree = searchTree;
1251 }
1253 > findSubstr(key: URI): IExtensionDescription | undefined {
1254 return this._searchTree.findSubstr(key);
1255 }
1257 > forEach(callback: (value: IExtensionDescription, index: URI) => any): void {
1258 return this._searchTree.forEach(callback);
1259 }
1261 >
1262 > /**
1263 > * This mirrors the activation events as seen by the renderer. The renderer
1264 > * is the only one which can have a reliable view of activation events because
1265 > * implicit activation events are generated via extension points, and they
1266 > * are registered only on the renderer side.
1267 > */
1268 > class SyncedActivationEventsReader implements IActivationEventsReader {
1269 >
1270 > private readonly _map = new ExtensionIdentifierMap<string[]>();
1271 >
1272 > constructor(activationEvents: { [extensionId: string]: string[] }) {
1273 this.addActivationEvents(activationEvents);
1274 }
1276 > public readActivationEvents(extensionDescription: IExtensionDescription): string[] {
1277 return this._map.get(extensionDescription.identifier) ?? [];
1278 }
1280 > public addActivationEvents(activationEvents: { [extensionId: string]: string[] }): void {
1281 for (const extensionId of Object.keys(activationEvents)) {
1282 this._map.set(extensionId, activationEvents[extensionId]);
1283 }
1284 }
src/vs/platform/agentHost/common/state/protocol/channels-session/commands.ts 323 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- commands.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > // allow-any-unicode-comment-file
7 > // DO NOT EDIT -- auto-generated by scripts/sync-agent-host-protocol.ts
8 >
9 > import type { URI } from '../common/state.js';
10 > import type { BaseParams } from '../common/commands.js';
11 > import type { SessionActiveClient } from './state.js';
12 > import type { MessageAttachment } from '../channels-chat/state.js';
13 >
14 > // ─── createSession ───────────────────────────────────────────────────────────
15 >
16 > /**
17 > * Creates a new session with the specified agent provider.
18 > *
19 > * If the session URI already exists, the server MUST return an error with code
20 > * `-32003` (`SessionAlreadyExists`).
21 > *
22 > * After creation, the client should subscribe to the session URI to receive state
23 > * updates. The server also broadcasts a `root/sessionAdded` notification to all
24 > * clients.
25 > *
26 > * @category Commands
27 > * @method createSession
28 > * @direction Client → Server
29 > * @messageType Request
30 > * @version 1
31 > * @example
32 > * ```jsonc
33 > * // Client → Server
34 > * { "jsonrpc": "2.0", "id": 2, "method": "createSession",
35 > * "params": { "channel": "ahp-session:/<uuid>", "provider": "copilot" } }
36 > *
37 > * // Server → Client (success)
38 > * { "jsonrpc": "2.0", "id": 2, "result": null }
39 > *
40 > * // Server → Client (failure — provider not found)
41 > * { "jsonrpc": "2.0", "id": 2, "error": { "code": -32002, "message": "No agent for provider" } }
42 > *
43 > * // Server → Client (failure — session already exists)
44 > * { "jsonrpc": "2.0", "id": 2, "error": { "code": -32003, "message": "Session already exists" } }
45 > * ```
46 > */
47 > /**
48 > * Identifies a source session and turn to fork from.
49 > *
50 > * When provided in `createSession`, the server populates the new session with
51 > * content from the source session up to and including the response of the
52 > * specified turn.
53 > */
54 > export interface SessionForkSource {
55 > /** URI of the existing session to fork from */
56 > session: URI;
57 > /** Turn ID in the source session; content up to and including this turn's response is copied */
58 > turnId: string;
59 > }
60 >
61 > export interface CreateSessionParams extends BaseParams {
62 > /** Session URI (client-chosen, e.g. `ahp-session:/<uuid>`) */
63 > channel: URI;
64 > /** Agent provider ID */
65 > provider?: string;
66 > /**
67 > * The working directories the session's agent is granted tool access to.
68 > * A session may span multiple directories; they are equal peers except when
69 > * the agent advertises
70 > * {@link MultipleWorkingDirectoriesCapability.requiresPrimary}, in which case
71 > * one of them should be designated the primary via
72 > * {@link primaryWorkingDirectory}.
73 > *
74 > * A client MUST NOT supply more than one entry unless the agent advertises
75 > * {@link AgentCapabilities.multipleWorkingDirectories}; a server without that
76 > * capability treats only the first entry as the session's working directory
77 > * and ignores the rest. Dispatch `session/workingDirectorySet` /
78 > * `session/workingDirectoryRemoved` to change the set after the session has
79 > * started.
80 > *
81 > * Ignored for forked sessions — a fork inherits its working directories
82 > * from the source session identified by `fork`.
83 > */
84 > workingDirectories?: URI[];
85 > /**
86 > * The primary working directory for the session's **default chat**.
87 > *
88 > * A session has no primary of its own — primary is a per-chat notion (see
89 > * {@link ChatState.primaryWorkingDirectory}). But `createSession` implicitly
90 > * creates the session's default chat, and there is no separate `createChat`
91 > * call to carry that chat's create-time fields. This field is therefore the
92 > * only place a client can designate the **default chat's** primary at birth;
93 > * it is copied into that chat's read-only `primaryWorkingDirectory`. For any
94 > * non-default chat, pass {@link CreateChatParams.primaryWorkingDirectory}
95 > * instead.
96 > *
97 > * When set, it MUST be one of {@link workingDirectories}. A client SHOULD
98 > * supply this when the agent advertises
99 > * {@link MultipleWorkingDirectoriesCapability.requiresPrimary}; a host MAY
100 > * reject creation that omits it, or fall back to the first entry of
101 > * `workingDirectories`. Ignored for forked sessions (a fork inherits the
102 > * source session's chats and their primaries).
103 > */
104 > primaryWorkingDirectory?: URI;
105 > /**
106 > * Fork from an existing session. The new session is populated with content
107 > * from the source session up to and including the specified turn's response.
108 > */
109 > fork?: SessionForkSource;
110 > /**
111 > * Agent-specific configuration values collected via `resolveSessionConfig`.
112 > * Keys and values correspond to the schema returned by the server.
113 > */
114 > config?: Record<string, unknown>;
115 > /**
116 > * Eagerly claim an active client role for the new session.
117 > *
118 > * When provided, the server initializes the session with this client as an
119 > * active client, equivalent to dispatching a `session/activeClientSet`
120 > * action immediately after creation. The `clientId` MUST match the
121 > * `clientId` the creating client supplied in `initialize`.
122 > */
123 > activeClient?: SessionActiveClient;
124 > /**
125 > * Opt-in progress token. When set, the client is offering to receive
126 > * `progress` notifications (see `ProgressParams`) for any long-running work
127 > * the server does to bring this session up — most notably the lazy,
128 > * first-use download of the provider's native SDK. The server echoes this
129 > * exact token on every `progress` frame so the client can correlate it to
130 > * this `createSession` call (and the UI awaiting it).
131 > *
132 > * The token MUST be unique across the client's active requests. The server
133 > * MAY ignore it (e.g. when nothing long-running is needed), in which case no
134 > * `progress` notifications are emitted.
135 > */
136 > progressToken?: string;
137 > }
138 >
139 > // ─── disposeSession ──────────────────────────────────────────────────────────
140 >
141 > /**
142 > * Disposes a session and cleans up server-side resources.
143 > *
144 > * The server broadcasts a `root/sessionRemoved` notification to all clients.
145 > *
146 > * @category Commands
147 > * @method disposeSession
148 > * @direction Client → Server
149 > * @messageType Request
150 > * @version 1
151 > */
152 > export interface DisposeSessionParams extends BaseParams { }
153 >
154 > // ─── fetchTurns ──────────────────────────────────────────────────────────────
155 >
156 > /**
157 > * Requests that the host load older historical turns into a chat state.
158 > *
159 > * The command result does not carry turns. Instead, before responding, the host
160 > * MUST dispatch `chat/turnsLoaded` to insert any loaded turns into the chat
161 > * channel's `turns` state, ahead of the already-loaded window, and update or
162 > * clear `turnsNextCursor`.
163 > *
164 > * Before applying any operation that references a turn outside the currently
165 > * loaded window, the host MUST eagerly load enough older turns into state for
166 > * that operation to reduce against valid state.
167 > *
168 > * @category Commands
169 > * @method fetchTurns
170 > * @direction Client → Server
171 > * @messageType Request
172 > * @version 1
173 > * @example
174 > * ```jsonc
175 > * // Client → Server (load the next page indicated by ChatState.turnsNextCursor)
176 > * { "jsonrpc": "2.0", "id": 8, "method": "fetchTurns",
177 > * "params": { "channel": "ahp-chat:/<uuid>", "cursor": "opaque-cursor" } }
178 > *
179 > * // Server updates chat state, then responds
180 > * { "jsonrpc": "2.0", "id": 8, "result": {} }
181 > * ```
182 > */
183 > export interface FetchTurnsParams extends BaseParams {
184 > /** Chat URI */
185 > channel: URI;
186 > /**
187 > * Opaque cursor from `ChatState.turnsNextCursor`.
188 > *
189 > * The host MUST reject unrecognised cursors with `InvalidParams`. Omit only
190 > * when asking the host to opportunistically load its next older page for the
191 > * chat, if any.
192 > */
193 > cursor?: string;
194 > }
195 >
196 > /**
197 > * Result of the `fetchTurns` command.
198 > */
199 > export interface FetchTurnsResult { }
200 >
201 > // ─── completions ─────────────────────────────────────────────────────────────
202 >
203 > /**
204 > * The kind of completion items being requested.
205 > *
206 > * @category Commands
207 > */
208 > export const enum CompletionItemKind {
209 > /**
210 > * Completions for the text of a {@link Message} the user is composing.
211 > * Each returned item carries an attachment that gets associated with the
212 > * message when accepted.
213 > */
214 > UserMessage = 'userMessage',
215 > }
216 >
217 > /**
218 > * Requests completion items for a partially-typed input (e.g. a user message
219 > * the user is currently composing). Used to power `@`-mention pickers,
220 > * file/symbol references, and similar inline-completion experiences.
221 > *
222 > * Servers SHOULD treat this command as best-effort and return promptly. The
223 > * client SHOULD debounce calls to avoid flooding the server with requests on
224 > * every keystroke.
225 > *
226 > * @category Commands
227 > * @method completions
228 > * @direction Client → Server
229 > * @messageType Request
230 > * @version 1
231 > * @example
232 > * ```jsonc
233 > * // User has typed "look at @foo" and the cursor is just after "@foo".
234 > * // Client → Server
235 > * { "jsonrpc": "2.0", "id": 12, "method": "completions",
236 > * "params": { "kind": "userMessage", "channel": "ahp-chat:/<uuid>",
237 > * "text": "look at @foo", "offset": 12 } }
238 > *
239 > * // Server → Client
240 > * { "jsonrpc": "2.0", "id": 12, "result": {
241 > * "items": [
242 > * {
243 > * "insertText": "@foo.ts",
244 > * "rangeStart": 8,
245 > * "rangeEnd": 12,
246 > * "attachment": {
247 > * "type": "resource",
248 > * "label": "foo.ts",
249 > * "displayKind": "document",
250 > * "uri": "file:///workspace/foo.ts"
251 > * }
252 > * }
253 > * ]
254 > * }}
255 > * ```
256 > */
257 > export interface CompletionsParams extends BaseParams {
258 > /** What kind of completion is being requested. */
259 > kind: CompletionItemKind;
260 > /** The chat URI the completion is being requested for. */
261 > channel: URI;
262 > /**
263 > * The complete text of the input being completed (e.g. the full user
264 > * message text typed so far).
265 > */
266 > text: string;
267 > /**
268 > * The character offset within `text` at which the completion is requested,
269 > * measured in UTF-16 code units. MUST satisfy `0 <= offset <= text.length`.
270 > */
271 > offset: number;
272 > }
273 >
274 > /**
275 > * A single completion item returned by the `completions` command.
276 > *
277 > * When the user accepts an item, the client SHOULD:
278 > * 1. Replace the range `[rangeStart, rangeEnd)` in the input with `insertText`
279 > * (or insert `insertText` at the cursor when the range is omitted).
280 > * 2. Associate the item's `attachment` with the resulting {@link Message}.
281 > *
282 > * @category Commands
283 > */
284 > export interface CompletionItem {
285 > /**
286 > * The text inserted into the input when this item is accepted.
287 > */
288 > insertText: string;
289 >
290 > /**
291 > * If defined, the start of the range in the input's `text` that is replaced
292 > * by `insertText`. The range is the half-open interval
293 > * `[rangeStart, rangeEnd)` of character offsets, measured in UTF-16 code
294 > * units.
295 > *
296 > * When omitted, the client SHOULD insert `insertText` at the cursor.
297 > *
298 > * Note: this range refers to positions in the *current* input. The
299 > * attachment's own `rangeStart`/`rangeEnd` (when present) refer to
300 > * positions in the final {@link Message.text} after the item is
301 > * accepted.
302 > */
303 > rangeStart?: number;
304 >
305 > /**
306 > * The end of the range in the input's `text` that is replaced by
307 > * `insertText`. See {@link rangeStart}.
308 > */
309 > rangeEnd?: number;
310 >
311 > /**
312 > * The attachment associated with this completion item.
313 > */
314 > attachment: MessageAttachment;
315 > }
316 >
317 > /**
318 > * Result of the `completions` command.
319 > */
320 > export interface CompletionsResult {
321 > /** The completion items, in the order the server suggests displaying them. */
322 > items: CompletionItem[];
323 > }
src/vs/platform/workspace/common/workspace.ts 322 covered LOC · 27 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- workspace.ts
2 > * Copyright (c) Microsoft 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 { Event } from '../../../base/common/event.js';
8 > import { basename, extname } from '../../../base/common/path.js';
9 > import { TernarySearchTree } from '../../../base/common/ternarySearchTree.js';
10 > import { extname as resourceExtname, basenameOrAuthority, joinPath, extUriBiasedIgnorePathCase } from '../../../base/common/resources.js';
11 > import { URI, UriComponents } from '../../../base/common/uri.js';
12 > import { createDecorator } from '../../instantiation/common/instantiation.js';
13 > import { IEnvironmentService } from '../../environment/common/environment.js';
14 > import { Schemas } from '../../../base/common/network.js';
15 >
16 > export const IWorkspaceContextService = createDecorator<IWorkspaceContextService>('contextService');
17 >
18 > export interface IWorkspaceContextService {
19 >
20 > readonly _serviceBrand: undefined;
21 >
22 > /**
23 > * An event which fires on workbench state changes.
24 > */
25 > readonly onDidChangeWorkbenchState: Event<WorkbenchState>;
26 >
27 > /**
28 > * An event which fires on workspace name changes.
29 > */
30 > readonly onDidChangeWorkspaceName: Event<void>;
31 >
32 > /**
33 > * An event which fires before workspace folders change.
34 > */
35 > readonly onWillChangeWorkspaceFolders: Event<IWorkspaceFoldersWillChangeEvent>;
36 >
37 > /**
38 > * An event which fires on workspace folders change.
39 > */
40 > readonly onDidChangeWorkspaceFolders: Event<IWorkspaceFoldersChangeEvent>;
41 >
42 > /**
43 > * Provides access to the complete workspace object.
44 > */
45 > getCompleteWorkspace(): Promise<IWorkspace>;
46 >
47 > /**
48 > * Provides access to the workspace object the window is running with.
49 > * Use `getCompleteWorkspace` to get complete workspace object.
50 > */
51 > getWorkspace(): IWorkspace;
52 >
53 > /**
54 > * Return the state of the workbench.
55 > *
56 > * WorkbenchState.EMPTY - if the workbench was opened with empty window or file
57 > * WorkbenchState.FOLDER - if the workbench was opened with a folder
58 > * WorkbenchState.WORKSPACE - if the workbench was opened with a workspace
59 > */
60 > getWorkbenchState(): WorkbenchState;
61 >
62 > /**
63 > * Returns the folder for the given resource from the workspace.
64 > * Can be null if there is no workspace or the resource is not inside the workspace.
65 > */
66 > getWorkspaceFolder(resource: URI): IWorkspaceFolder | null;
67 >
68 > /**
69 > * Return `true` if the current workspace has the given identifier or root URI otherwise `false`.
70 > */
71 > isCurrentWorkspace(workspaceIdOrFolder: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | URI): boolean;
72 >
73 > /**
74 > * Returns if the provided resource is inside the workspace or not.
75 > */
76 > isInsideWorkspace(resource: URI): boolean;
77 >
78 > /**
79 > * Return `true` if the current workspace has data (e.g. folders or a workspace configuration) that can be sent to the extension host, otherwise `false`.
80 > */
81 > hasWorkspaceData(): boolean;
82 > }
83 >
84 > export interface IResolvedWorkspace extends IWorkspaceIdentifier, IBaseWorkspace {
85 > readonly folders: IWorkspaceFolder[];
86 > }
87 >
88 > export interface IBaseWorkspace {
89 >
90 > /**
91 > * If present, marks the window that opens the workspace
92 > * as a remote window with the given authority.
93 > */
94 > readonly remoteAuthority?: string;
95 >
96 > /**
97 > * Transient workspaces are meant to go away after being used
98 > * once, e.g. a window reload of a transient workspace will
99 > * open an empty window.
100 > *
101 > * See: https://github.com/microsoft/vscode/issues/119695
102 > */
103 > readonly transient?: boolean;
104 > }
105 >
106 > export interface IBaseWorkspaceIdentifier {
107 >
108 > /**
109 > * Every workspace (multi-root, single folder or empty)
110 > * has a unique identifier. It is not possible to open
111 > * a workspace with the same `id` in multiple windows
112 > */
113 > readonly id: string;
114 > }
115 >
116 > /**
117 > * A single folder workspace identifier is a path to a folder + id.
118 > */
119 > export interface ISingleFolderWorkspaceIdentifier extends IBaseWorkspaceIdentifier {
120 >
121 > /**
122 > * Folder path as `URI`.
123 > */
124 > readonly uri: URI;
125 > }
126 >
127 > /**
128 > * A multi-root workspace identifier is a path to a workspace file + id.
129 > */
130 > export interface IWorkspaceIdentifier extends IBaseWorkspaceIdentifier {
131 >
132 > /**
133 > * Workspace config file path as `URI`.
134 > */
135 > configPath: URI;
136 > }
137 >
138 > export interface IEmptyWorkspaceIdentifier extends IBaseWorkspaceIdentifier { }
139 >
140 > export type IAnyWorkspaceIdentifier = IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier;
141 >
142 > export function isSingleFolderWorkspaceIdentifier(obj: unknown): obj is ISingleFolderWorkspaceIdentifier {
143 const singleFolderIdentifier = obj as ISingleFolderWorkspaceIdentifier | undefined;
144
145 return typeof singleFolderIdentifier?.id === 'string' && URI.isUri(singleFolderIdentifier.uri);
146 }
147 > workspace.ts
148 > export function isEmptyWorkspaceIdentifier(obj: unknown): obj is IEmptyWorkspaceIdentifier {
149 const emptyWorkspaceIdentifier = obj as IEmptyWorkspaceIdentifier | undefined;
150 return typeof emptyWorkspaceIdentifier?.id === 'string'
152 && !isWorkspaceIdentifier(obj);
153 }
154 > workspace.ts
155 > export const EXTENSION_DEVELOPMENT_EMPTY_WINDOW_WORKSPACE: IEmptyWorkspaceIdentifier = { id: 'ext-dev' };
156 > export const UNKNOWN_EMPTY_WINDOW_WORKSPACE: IEmptyWorkspaceIdentifier = { id: 'empty-window' };
157 >
158 > export function toWorkspaceIdentifier(workspace: IWorkspace): IAnyWorkspaceIdentifier;
159 > export function toWorkspaceIdentifier(backupPath: string | undefined, isExtensionDevelopment: boolean): IEmptyWorkspaceIdentifier;
160 > export function toWorkspaceIdentifier(arg0: IWorkspace | string | undefined, isExtensionDevelopment?: boolean): IAnyWorkspaceIdentifier {
161
162 // Empty workspace
202 };
203 }
204 > workspace.ts
205 > export function isWorkspaceIdentifier(obj: unknown): obj is IWorkspaceIdentifier {
206 const workspaceIdentifier = obj as IWorkspaceIdentifier | undefined;
207
208 return typeof workspaceIdentifier?.id === 'string' && URI.isUri(workspaceIdentifier.configPath);
209 }
210 > workspace.ts
211 > export interface ISerializedSingleFolderWorkspaceIdentifier extends IBaseWorkspaceIdentifier {
212 > readonly uri: UriComponents;
213 > }
214 >
215 > export interface ISerializedWorkspaceIdentifier extends IBaseWorkspaceIdentifier {
216 > readonly configPath: UriComponents;
217 > }
218 >
219 > export function reviveIdentifier(identifier: undefined): undefined;
220 > export function reviveIdentifier(identifier: ISerializedWorkspaceIdentifier): IWorkspaceIdentifier;
221 > export function reviveIdentifier(identifier: ISerializedSingleFolderWorkspaceIdentifier): ISingleFolderWorkspaceIdentifier;
222 > export function reviveIdentifier(identifier: IEmptyWorkspaceIdentifier): IEmptyWorkspaceIdentifier;
223 > export function reviveIdentifier(identifier: ISerializedWorkspaceIdentifier | ISerializedSingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier | undefined): IAnyWorkspaceIdentifier | undefined;
224 > export function reviveIdentifier(identifier: ISerializedWorkspaceIdentifier | ISerializedSingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier | undefined): IAnyWorkspaceIdentifier | undefined {
225
226 // Single Folder
243 return undefined;
244 }
245 > workspace.ts
246 > export const enum WorkbenchState {
247 > EMPTY = 1,
248 > FOLDER,
249 > WORKSPACE
250 > }
251 >
252 > export interface IWorkspaceFoldersWillChangeEvent {
253 >
254 > readonly changes: IWorkspaceFoldersChangeEvent;
255 > readonly fromCache: boolean;
256 >
257 > join(promise: Promise<void>): void;
258 > }
259 >
260 > export interface IWorkspaceFoldersChangeEvent {
261 > added: IWorkspaceFolder[];
262 > removed: IWorkspaceFolder[];
263 > changed: IWorkspaceFolder[];
264 > }
265 >
266 > export interface IWorkspace {
267 >
268 > /**
269 > * the unique identifier of the workspace.
270 > */
271 > readonly id: string;
272 >
273 > /**
274 > * Folders in the workspace.
275 > */
276 > readonly folders: IWorkspaceFolder[];
277 >
278 > /**
279 > * Transient workspaces are meant to go away after being used
280 > * once, e.g. a window reload of a transient workspace will
281 > * open an empty window.
282 > */
283 > readonly transient?: boolean;
284 >
285 > /**
286 > * the location of the workspace configuration
287 > */
288 > readonly configuration?: URI | null;
289 >
290 > /**
291 > * Optional display name for the workspace.
292 > */
293 > readonly name?: string;
294 >
295 > }
296 >
297 > export function isWorkspace(thing: unknown): thing is IWorkspace {
298 const candidate = thing as IWorkspace | undefined;
299
302 && Array.isArray(candidate.folders));
303 }
304 > workspace.ts
305 > export interface IWorkspaceFolderData {
306 >
307 > /**
308 > * The associated URI for this workspace folder.
309 > */
310 > readonly uri: URI;
311 >
312 > /**
313 > * The name of this workspace folder. Defaults to
314 > * the basename of its [uri-path](#Uri.path)
315 > */
316 > readonly name: string;
317 >
318 > /**
319 > * The ordinal number of this workspace folder.
320 > */
321 > readonly index: number;
322 > }
323 >
324 > export interface IWorkspaceFolder extends IWorkspaceFolderData {
325 >
326 > /**
327 > * Given workspace folder relative path, returns the resource with the absolute path.
328 > */
329 > toResource: (relativePath: string) => URI;
330 > }
331 >
332 > export function isWorkspaceFolder(thing: unknown): thing is IWorkspaceFolder {
333 const candidate = thing as IWorkspaceFolder;
334
338 && typeof candidate.toResource === 'function');
339 }
340 > workspace.ts
341 > export class Workspace implements IWorkspace {
342 >
343 > private foldersMap: TernarySearchTree<URI, WorkspaceFolder>;
344 >
345 > private _folders!: WorkspaceFolder[];
346 > get folders(): WorkspaceFolder[] { return this._folders; }
347 > set folders(folders: WorkspaceFolder[]) {
348 this._folders = folders;
349 this.updateFoldersMap();
350 }
351 > workspace.ts
352 > constructor(
353 private _id: string,
354 folders: WorkspaceFolder[],
361 this.folders = folders;
362 }
363 > workspace.ts
364 > update(workspace: Workspace) {
365 this._id = workspace.id;
366 this._configuration = workspace.configuration;
370 this.folders = workspace.folders;
371 }
372 > workspace.ts
373 > get id(): string {
374 return this._id;
375 }
376 > workspace.ts
377 > get transient(): boolean {
378 return this._transient;
379 }
380 > workspace.ts
381 > get configuration(): URI | null {
382 return this._configuration;
383 }
384 > workspace.ts
385 > set configuration(configuration: URI | null) {
386 this._configuration = configuration;
387 }
388 > workspace.ts
389 > get name(): string | undefined {
390 return this._workspaceName;
391 }
392 > workspace.ts
393 > getFolder(resource: URI): IWorkspaceFolder | null {
394 if (!resource) {
395 return null;
398 return this.foldersMap.findSubstr(resource) || null;
399 }
400 > workspace.ts
401 > private updateFoldersMap(): void {
402 this.foldersMap = TernarySearchTree.forUris<WorkspaceFolder>(this.ignorePathCasing, () => true);
403 for (const folder of this.folders) {
405 }
406 }
407 > workspace.ts
408 > toJSON(): IWorkspace {
409 return { id: this.id, folders: this.folders, transient: this.transient, configuration: this.configuration, name: this.name };
410 }
411 > } workspace.ts
412 >
413 > export interface IRawFileWorkspaceFolder {
414 > readonly path: string;
415 > name?: string;
416 > }
417 >
418 > export interface IRawUriWorkspaceFolder {
419 > readonly uri: string;
420 > name?: string;
421 > }
422 >
423 > export class WorkspaceFolder implements IWorkspaceFolder {
424 >
425 > readonly uri: URI;
426 > readonly name: string;
427 > readonly index: number;
428 >
429 > constructor(
430 data: IWorkspaceFolderData,
431 /**
442 this.name = data.name;
443 }
444 > workspace.ts
445 > toResource(relativePath: string): URI {
446 return joinPath(this.uri, relativePath);
447 }
448 > workspace.ts
449 > toJSON(): IWorkspaceFolderData {
450 return { uri: this.uri, name: this.name, index: this.index };
451 }
452 > } workspace.ts
453 >
454 > export function toWorkspaceFolder(resource: URI): WorkspaceFolder {
455 return new WorkspaceFolder({ uri: resource, index: 0, name: basenameOrAuthority(resource) }, { uri: resource.toString() });
456 }
457 > workspace.ts
458 > export const WORKSPACE_EXTENSION = 'code-workspace';
459 > export const WORKSPACE_SUFFIX = `.${WORKSPACE_EXTENSION}`;
460 > export const WORKSPACE_FILTER = [{ name: localize('codeWorkspace', "Code Workspace"), extensions: [WORKSPACE_EXTENSION] }];
461 > export const UNTITLED_WORKSPACE_NAME = 'workspace.json';
462 >
463 > export function isUntitledWorkspace(path: URI, environmentService: IEnvironmentService): boolean {
464 return extUriBiasedIgnorePathCase.isEqualOrParent(path, environmentService.untitledWorkspacesHome);
465 }
466 > workspace.ts
467 > export function isTemporaryWorkspace(workspace: IWorkspace): boolean;
468 > export function isTemporaryWorkspace(path: URI): boolean;
469 > export function isTemporaryWorkspace(arg1: IWorkspace | URI): boolean {
470 let path: URI | null | undefined;
471 if (URI.isUri(arg1)) {
477 return path?.scheme === Schemas.tmp;
478 }
479 > workspace.ts
480 > export const STANDALONE_EDITOR_WORKSPACE_ID = '4064f6ec-cb38-4ad0-af64-ee6467e63c82';
481 > export function isStandaloneEditorWorkspace(workspace: IWorkspace): boolean {
482 return workspace.id === STANDALONE_EDITOR_WORKSPACE_ID;
483 }
484 > workspace.ts
485 > export function isSavedWorkspace(path: URI, environmentService: IEnvironmentService): boolean {
486 return !isUntitledWorkspace(path, environmentService) && !isTemporaryWorkspace(path);
487 }
488 > workspace.ts
489 > export function hasWorkspaceFileExtension(path: string | URI) {
490 const ext = (typeof path === 'string') ? extname(path) : resourceExtname(path);
491
src/vs/workbench/api/common/extHostWorkspace.ts 322 covered LOC · 67 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostWorkspace.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { delta as arrayDelta, mapArrayOrNot } from '../../../base/common/arrays.js';
7 > import { AsyncIterableProducer, Barrier } from '../../../base/common/async.js';
8 > import { CancellationToken, CancellationTokenSource } from '../../../base/common/cancellation.js';
9 > import { AsyncEmitter, Emitter, Event } from '../../../base/common/event.js';
10 > import { DisposableStore, toDisposable } from '../../../base/common/lifecycle.js';
11 > import { StopWatch } from '../../../base/common/stopwatch.js';
12 > import { TernarySearchTree } from '../../../base/common/ternarySearchTree.js';
13 > import { Schemas } from '../../../base/common/network.js';
14 > import { Counter } from '../../../base/common/numbers.js';
15 > import { basename, basenameOrAuthority, dirname, ExtUri, relativePath } from '../../../base/common/resources.js';
16 > import { compare } from '../../../base/common/strings.js';
17 > import { isUriComponents, URI, UriComponents } from '../../../base/common/uri.js';
18 > import { localize } from '../../../nls.js';
19 > import { ExtensionIdentifier, IExtensionDescription } from '../../../platform/extensions/common/extensions.js';
20 > import { FileSystemProviderCapabilities } from '../../../platform/files/common/files.js';
21 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
22 > import { ILogService } from '../../../platform/log/common/log.js';
23 > import { Severity } from '../../../platform/notification/common/notification.js';
24 > import { EditSessionIdentityMatch } from '../../../platform/workspace/common/editSessions.js';
25 > import { Workspace, WorkspaceFolder } from '../../../platform/workspace/common/workspace.js';
26 > import { IExtHostFileSystemInfo } from './extHostFileSystemInfo.js';
27 > import { IExtHostInitDataService } from './extHostInitDataService.js';
28 > import { IExtHostRpcService } from './extHostRpcService.js';
29 > import { GlobPattern } from './extHostTypeConverters.js';
30 > import { Range } from './extHostTypes.js';
31 > import { IURITransformerService } from './extHostUriTransformerService.js';
32 > import { IFileQueryBuilderOptions, ISearchPatternBuilder, ITextQueryBuilderOptions } from '../../services/search/common/queryBuilder.js';
33 > import { IRawFileMatch2, ITextSearchResult, resultIsMatch } from '../../services/search/common/search.js';
34 > import type * as vscode from 'vscode';
35 > import { ExtHostWorkspaceShape, IRelativePatternDto, IWorkspaceData, MainContext, MainThreadMessageOptions, MainThreadMessageServiceShape, MainThreadTelemetryShape, MainThreadWorkspaceShape } from './extHost.protocol.js';
36 > import { revive } from '../../../base/common/marshalling.js';
37 > import { AuthInfo, Credentials } from '../../../platform/request/common/request.js';
38 > import { ExcludeSettingOptions, TextSearchContext2, TextSearchMatch2 } from '../../services/search/common/searchExtTypes.js';
39 > import { bufferToStream, readableToBuffer, VSBuffer } from '../../../base/common/buffer.js';
40 > import { toDecodeStream, toEncodeReadable, UTF8 } from '../../services/textfile/common/encoding.js';
41 > import { consumeStream } from '../../../base/common/stream.js';
42 > import { stringToSnapshot } from '../../services/textfile/common/textfiles.js';
43 > // Type-only import to avoid a runtime cycle with extHostConfiguration.ts.
44 > import type { ExtHostConfigProvider } from './extHostConfiguration.js';
45 >
46 > export interface IExtHostWorkspaceProvider {
47 > getWorkspaceFolder2(uri: vscode.Uri, resolveParent?: boolean): Promise<vscode.WorkspaceFolder | undefined>;
48 > resolveWorkspaceFolder(uri: vscode.Uri): Promise<vscode.WorkspaceFolder | undefined>;
49 > getWorkspaceFolders2(): Promise<vscode.WorkspaceFolder[] | undefined>;
50 > resolveProxy(url: string): Promise<string | undefined>;
51 > lookupAuthorization(authInfo: AuthInfo): Promise<Credentials | undefined>;
52 > lookupKerberosAuthorization(url: string): Promise<string | undefined>;
53 > loadCertificates(): Promise<string[]>;
54 > }
55 >
56 function isFolderEqual(folderA: URI, folderB: URI, extHostFileSystemInfo: IExtHostFileSystemInfo): boolean {
57 return new ExtUri(uri => ignorePathCasing(uri, extHostFileSystemInfo)).isEqual(folderA, folderB);
58 }
60 function compareWorkspaceFolderByUri(a: vscode.WorkspaceFolder, b: vscode.WorkspaceFolder, extHostFileSystemInfo: IExtHostFileSystemInfo): number {
61 return isFolderEqual(a.uri, b.uri, extHostFileSystemInfo) ? 0 : compare(a.uri.toString(), b.uri.toString());
62 }
64 function compareWorkspaceFolderByUriAndNameAndIndex(a: vscode.WorkspaceFolder, b: vscode.WorkspaceFolder, extHostFileSystemInfo: IExtHostFileSystemInfo): number {
65 if (a.index !== b.index) {
69 return isFolderEqual(a.uri, b.uri, extHostFileSystemInfo) ? compare(a.name, b.name) : compare(a.uri.toString(), b.uri.toString());
70 }
72 function delta(oldFolders: vscode.WorkspaceFolder[], newFolders: vscode.WorkspaceFolder[], compare: (a: vscode.WorkspaceFolder, b: vscode.WorkspaceFolder, extHostFileSystemInfo: IExtHostFileSystemInfo) => number, extHostFileSystemInfo: IExtHostFileSystemInfo): { removed: vscode.WorkspaceFolder[]; added: vscode.WorkspaceFolder[] } {
73 const oldSortedFolders = oldFolders.slice(0).sort((a, b) => compare(a, b, extHostFileSystemInfo));
76 return arrayDelta(oldSortedFolders, newSortedFolders, (a, b) => compare(a, b, extHostFileSystemInfo));
77 }
79 function ignorePathCasing(uri: URI, extHostFileSystemInfo: IExtHostFileSystemInfo): boolean {
80 const capabilities = extHostFileSystemInfo.getCapabilities(uri.scheme);
81 return !(capabilities && (capabilities & FileSystemProviderCapabilities.PathCaseSensitive));
82 }
84 > interface MutableWorkspaceFolder extends vscode.WorkspaceFolder {
85 > name: string;
86 > index: number;
87 > }
88 >
89 > interface QueryOptions<T> {
90 > options: T;
91 > folder: URI | undefined;
92 > }
93 >
94 > type FindFilesApiKind = 'findFiles' | 'findFiles2';
95 >
96 > interface FindFilesCallIntent {
97 > /** Value the extension explicitly passed for `useIgnoreFiles.local` (findFiles2); `undefined` if not specified or N/A for legacy `findFiles`. */
98 > readonly useIgnoreFilesLocal: boolean | undefined;
99 > /** Whether the extension passed `null` as the `exclude` argument to legacy `findFiles` (the documented escape hatch). Always `false` for findFiles2. */
100 > readonly excludeWasNull: boolean;
101 > }
102 >
103 > class ExtHostWorkspaceImpl extends Workspace {
104 >
105 > static toExtHostWorkspace(data: IWorkspaceData | null, previousConfirmedWorkspace: ExtHostWorkspaceImpl | undefined, previousUnconfirmedWorkspace: ExtHostWorkspaceImpl | undefined, extHostFileSystemInfo: IExtHostFileSystemInfo): { workspace: ExtHostWorkspaceImpl | null; added: vscode.WorkspaceFolder[]; removed: vscode.WorkspaceFolder[] } {
106 > if (!data) {
107 > return { workspace: null, added: [], removed: [] };
108 > }
109 >
110 > const { id, name, folders, configuration, transient, isUntitled } = data;
111 > const newWorkspaceFolders: vscode.WorkspaceFolder[] = [];
112 >
113 > // If we have an existing workspace, we try to find the folders that match our
114 > // data and update their properties. It could be that an extension stored them
115 > // for later use and we want to keep them "live" if they are still present.
116 > const oldWorkspace = previousConfirmedWorkspace;
117 > if (previousConfirmedWorkspace) {
118 > folders.forEach((folderData, index) => {
119 > const folderUri = URI.revive(folderData.uri);
120 > const existingFolder = ExtHostWorkspaceImpl._findFolder(previousUnconfirmedWorkspace || previousConfirmedWorkspace, folderUri, extHostFileSystemInfo);
121 >
122 > if (existingFolder) {
123 > existingFolder.name = folderData.name;
124 > existingFolder.index = folderData.index;
125 >
126 > newWorkspaceFolders.push(existingFolder);
127 > } else {
128 > newWorkspaceFolders.push({ uri: folderUri, name: folderData.name, index });
129 > }
130 > });
131 > } else {
132 > newWorkspaceFolders.push(...folders.map(({ uri, name, index }) => ({ uri: URI.revive(uri), name, index })));
133 > }
134 >
135 > // make sure to restore sort order based on index
136 > newWorkspaceFolders.sort((f1, f2) => f1.index < f2.index ? -1 : 1);
137 >
138 > const workspace = new ExtHostWorkspaceImpl(id, name, newWorkspaceFolders, !!transient, configuration ? URI.revive(configuration) : null, !!isUntitled, uri => ignorePathCasing(uri, extHostFileSystemInfo));
139 > const { added, removed } = delta(oldWorkspace ? oldWorkspace.workspaceFolders : [], workspace.workspaceFolders, compareWorkspaceFolderByUri, extHostFileSystemInfo);
140 >
141 > return { workspace, added, removed };
142 > }
143 >
144 > private static _findFolder(workspace: ExtHostWorkspaceImpl, folderUriToFind: URI, extHostFileSystemInfo: IExtHostFileSystemInfo): MutableWorkspaceFolder | undefined {
145 for (let i = 0; i < workspace.folders.length; i++) {
146 const folder = workspace.workspaceFolders[i];
152 return undefined;
153 }
155 > private readonly _workspaceFolders: vscode.WorkspaceFolder[] = [];
156 > private readonly _structure: TernarySearchTree<URI, vscode.WorkspaceFolder>;
157 >
158 > constructor(id: string, private _name: string, folders: vscode.WorkspaceFolder[], transient: boolean, configuration: URI | null, private _isUntitled: boolean, ignorePathCasing: (key: URI) => boolean) {
159 super(id, folders.map(f => new WorkspaceFolder(f)), transient, configuration, ignorePathCasing);
160 this._structure = TernarySearchTree.forUris<vscode.WorkspaceFolder>(ignorePathCasing, () => true);
166 });
167 }
169 > override get name(): string {
170 return this._name;
171 }
173 > get isUntitled(): boolean {
174 return this._isUntitled;
175 }
177 > get workspaceFolders(): vscode.WorkspaceFolder[] {
178 return this._workspaceFolders.slice(0);
179 }
181 > getWorkspaceFolder(uri: URI, resolveParent?: boolean): vscode.WorkspaceFolder | undefined {
182 if (resolveParent && this._structure.get(uri)) {
183 // `uri` is a workspace folder so we check for its parent
186 return this._structure.findSubstr(uri);
187 }
189 > resolveWorkspaceFolder(uri: URI): vscode.WorkspaceFolder | undefined {
190 return this._structure.get(uri);
191 }
193 >
194 > export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspaceProvider {
195 >
196 > readonly _serviceBrand: undefined;
197 >
198 > private readonly _onDidChangeWorkspace = new Emitter<vscode.WorkspaceFoldersChangeEvent>();
199 > readonly onDidChangeWorkspace: Event<vscode.WorkspaceFoldersChangeEvent> = this._onDidChangeWorkspace.event;
200 >
201 > private readonly _onDidGrantWorkspaceTrust = new Emitter<void>();
202 > readonly onDidGrantWorkspaceTrust: Event<void> = this._onDidGrantWorkspaceTrust.event;
203 >
204 > private readonly _onDidChangeWorkspaceTrustedFolders = new Emitter<void>();
205 > readonly onDidChangeWorkspaceTrustedFolders: Event<void> = this._onDidChangeWorkspaceTrustedFolders.event;
206 >
207 > private readonly _logService: ILogService;
208 > private readonly _requestIdProvider: Counter;
209 > private readonly _barrier: Barrier;
210 >
211 > private _confirmedWorkspace?: ExtHostWorkspaceImpl;
212 > private _unconfirmedWorkspace?: ExtHostWorkspaceImpl;
213 >
214 > private readonly _proxy: MainThreadWorkspaceShape;
215 > private readonly _messageService: MainThreadMessageServiceShape;
216 > private readonly _telemetryProxy: MainThreadTelemetryShape;
217 > private readonly _extHostFileSystemInfo: IExtHostFileSystemInfo;
218 > private readonly _uriTransformerService: IURITransformerService;
219 >
220 > private readonly _activeSearchCallbacks: ((match: IRawFileMatch2) => any)[] = [];
221 >
222 > private _trusted: boolean = false;
223 >
224 > private readonly _editSessionIdentityProviders = new Map<string, vscode.EditSessionIdentityProvider>();
225 >
226 > // Pushed in by ExtHostConfiguration after init (see `$setConfigProvider`).
227 > private _configProvider?: ExtHostConfigProvider;
228 >
229 > constructor(
230 @IExtHostRpcService extHostRpc: IExtHostRpcService,
231 @IExtHostInitDataService initData: IExtHostInitDataService,
246 this._confirmedWorkspace = data ? new ExtHostWorkspaceImpl(data.id, data.name, [], !!data.transient, data.configuration ? URI.revive(data.configuration) : null, !!data.isUntitled, uri => ignorePathCasing(uri, extHostFileSystemInfo)) : undefined;
247 }
249 > /**
250 > * Receives the configuration provider from ExtHostConfiguration after init. We cannot inject
251 > * IExtHostConfiguration directly because it creates a DI cycle (ExtHostConfiguration already
252 > * depends on IExtHostWorkspace). Once set, settings reads in findFiles become synchronous.
253 > */
254 > $setConfigProvider(provider: ExtHostConfigProvider): void {
255 this._configProvider = provider;
256 }
258 > private _useIgnoreFilesInFindFiles(): boolean {
259 return this._configProvider?.getConfiguration('search').get<boolean>('experimental.useIgnoreFilesInFindFiles') ?? false;
260 }
262 > private _userIgnoreFilesSetting(): boolean {
263 // Default in `search.useIgnoreFiles` is `true`; mirror that here so telemetry computed against
264 // an unset config still reflects the fallback the query builder will apply.
265 return this._configProvider?.getConfiguration('search').get<boolean>('useIgnoreFiles') ?? true;
266 }
268 > $initializeWorkspace(data: IWorkspaceData | null, trusted: boolean): void {
269 this._trusted = trusted;
270 this.$acceptWorkspaceData(data);
271 this._barrier.open();
272 }
274 > waitForInitializeCall(): Promise<boolean> {
275 return this._barrier.wait();
276 }
278 > // --- workspace ---
279 >
280 > get workspace(): Workspace | undefined {
281 return this._actualWorkspace;
282 }
284 > get name(): string | undefined {
285 return this._actualWorkspace ? this._actualWorkspace.name : undefined;
286 }
288 > get workspaceFile(): vscode.Uri | undefined {
289 if (this._actualWorkspace) {
290 if (this._actualWorkspace.configuration) {
299 return undefined;
300 }
302 > private get _actualWorkspace(): ExtHostWorkspaceImpl | undefined {
303 return this._unconfirmedWorkspace || this._confirmedWorkspace;
304 }
306 > getWorkspaceFolders(): vscode.WorkspaceFolder[] | undefined {
307 if (!this._actualWorkspace) {
308 return undefined;
310 return this._actualWorkspace.workspaceFolders.slice(0);
311 }
313 > async getWorkspaceFolders2(): Promise<vscode.WorkspaceFolder[] | undefined> {
314 await this._barrier.wait();
315 if (!this._actualWorkspace) {
318 return this._actualWorkspace.workspaceFolders.slice(0);
319 }
321 > updateWorkspaceFolders(extension: IExtensionDescription, index: number, deleteCount: number, ...workspaceFoldersToAdd: { uri: vscode.Uri; name?: string }[]): boolean {
322 const validatedDistinctWorkspaceFoldersToAdd: { uri: vscode.Uri; name?: string }[] = [];
323 if (Array.isArray(workspaceFoldersToAdd)) {
383 return true;
384 }
386 > getWorkspaceFolder(uri: vscode.Uri, resolveParent?: boolean): vscode.WorkspaceFolder | undefined {
387 if (!this._actualWorkspace) {
388 return undefined;
390 return this._actualWorkspace.getWorkspaceFolder(uri, resolveParent);
391 }
393 > async getWorkspaceFolder2(uri: vscode.Uri, resolveParent?: boolean): Promise<vscode.WorkspaceFolder | undefined> {
394 await this._barrier.wait();
395 if (!this._actualWorkspace) {
398 return this._actualWorkspace.getWorkspaceFolder(uri, resolveParent);
399 }
401 > async resolveWorkspaceFolder(uri: vscode.Uri): Promise<vscode.WorkspaceFolder | undefined> {
402 await this._barrier.wait();
403 if (!this._actualWorkspace) {
406 return this._actualWorkspace.resolveWorkspaceFolder(uri);
407 }
409 > getPath(): string | undefined {
410
411 // this is legacy from the days before having
423 return folders[0].uri.fsPath;
424 }
426 > getRelativePath(pathOrUri: string | vscode.Uri, includeWorkspace?: boolean): string {
427
428 let resource: URI | undefined;
459 return result!;
460 }
462 > private trySetWorkspaceFolders(folders: vscode.WorkspaceFolder[]): void {
463
464 // Update directly here. The workspace is unconfirmed as long as we did not get an
474 }
475 }
477 > $acceptWorkspaceData(data: IWorkspaceData | null): void {
478
479 const { workspace, added, removed } = ExtHostWorkspaceImpl.toExtHostWorkspace(data, this._confirmedWorkspace, this._unconfirmedWorkspace, this._extHostFileSystemInfo);
490 }));
491 }
493 > // --- search ---
494 >
495 > /**
496 > * Note, null/undefined have different and important meanings for "exclude"
497 > */
498 > findFiles(include: vscode.GlobPattern | undefined, exclude: vscode.GlobPattern | null | undefined, maxResults: number | undefined, extensionId: ExtensionIdentifier, token: vscode.CancellationToken = CancellationToken.None): Promise<vscode.Uri[]> {
499 this._logService.trace(`extHostWorkspace#findFiles: fileSearch, extension: ${extensionId.value}, entryPoint: findFiles`);
500
528 }, extensionId, 'findFiles', { useIgnoreFilesLocal: undefined, excludeWasNull: exclude === null }, token);
529 }
531 >
532 > findFiles2(filePatterns: readonly vscode.GlobPattern[],
533 options: vscode.FindFiles2Options = {},
534 extensionId: ExtensionIdentifier,
537 return this._findFilesImpl({ type: 'filePatterns', value: filePatterns }, options, extensionId, 'findFiles2', { useIgnoreFilesLocal: options.useIgnoreFiles?.local, excludeWasNull: false }, token);
538 }
540 > private async _findFilesImpl(
541 // the old `findFiles` used `include` to query, but the new `findFiles2` uses `filePattern` to query.
542 // `filePattern` is the proper way to handle this, since it takes less precedence than the ignore files.
635 }
636 }
638 > private async _findFilesBase(
639 queryOptions: QueryOptions<IFileQueryBuilderOptions>[] | undefined,
640 token: CancellationToken
677 return Array.from(uriMap.values());
678 }
680 > private _reportFindFilesTelemetry(event: {
681 extensionId: string;
682 apiKind: FindFilesApiKind;
718 this._telemetryProxy.$publicLog2<FindFilesEvent, FindFilesEventClassification>('extHostFindFiles', event);
719 }
721 > findTextInFiles2(query: vscode.TextSearchQuery2, options: vscode.FindTextInFilesOptions2 | undefined, extensionId: ExtensionIdentifier, token: vscode.CancellationToken = CancellationToken.None): vscode.FindTextInFilesResponse {
722 this._logService.trace(`extHostWorkspace#findTextInFiles2: textSearch, extension: ${extensionId.value}, entryPoint: findTextInFiles2`);
723
808 };
809 }
811 >
812 > async findTextInFilesBase(query: vscode.TextSearchQuery, queryOptions: QueryOptions<ITextQueryBuilderOptions>[] | undefined, callback: (result: ITextSearchResult<URI>, uri: URI) => void, token: vscode.CancellationToken = CancellationToken.None): Promise<vscode.TextSearchComplete> {
813 const requestId = this._requestIdProvider.getNext();
814
855 }
856 }
858 > async findTextInFiles(query: vscode.TextSearchQuery, options: vscode.FindTextInFilesOptions & { useSearchExclude?: boolean }, callback: (result: vscode.TextSearchResult) => void, extensionId: ExtensionIdentifier, token: vscode.CancellationToken = CancellationToken.None): Promise<vscode.TextSearchComplete> {
859 this._logService.trace(`extHostWorkspace#findTextInFiles: textSearch, extension: ${extensionId.value}, entryPoint: findTextInFiles`);
860
911 return this.findTextInFilesBase(query, [{ options: queryOptions, folder: parsedInclude?.folder }], progress, token);
912 }
914 > $handleTextSearchResult(result: IRawFileMatch2, requestId: number): void {
915 this._activeSearchCallbacks[requestId]?.(result);
916 }
918 > async save(uri: URI): Promise<URI | undefined> {
919 const result = await this._proxy.$save(uri, { saveAs: false });
920
921 return URI.revive(result);
922 }
924 > async saveAs(uri: URI): Promise<URI | undefined> {
925 const result = await this._proxy.$save(uri, { saveAs: true });
926
927 return URI.revive(result);
928 }
930 > saveAll(includeUntitled?: boolean): Promise<boolean> {
931 return this._proxy.$saveAll(includeUntitled);
932 }
934 > resolveProxy(url: string): Promise<string | undefined> {
935 return this._proxy.$resolveProxy(url);
936 }
938 > lookupAuthorization(authInfo: AuthInfo): Promise<Credentials | undefined> {
939 return this._proxy.$lookupAuthorization(authInfo);
940 }
942 > lookupKerberosAuthorization(url: string): Promise<string | undefined> {
943 return this._proxy.$lookupKerberosAuthorization(url);
944 }
946 > loadCertificates(): Promise<string[]> {
947 return this._proxy.$loadCertificates();
948 }
950 > // --- trust ---
951 >
952 > get trusted(): boolean {
953 return this._trusted;
954 }
956 > requestResourceTrust(options: vscode.ResourceTrustRequestOptions): Promise<boolean | undefined> {
957 return this._proxy.$requestResourceTrust(options);
958 }
960 > requestWorkspaceTrust(options?: vscode.WorkspaceTrustRequestOptions): Promise<boolean | undefined> {
961 return this._proxy.$requestWorkspaceTrust(options);
962 }
964 > $onDidGrantWorkspaceTrust(): void {
965 if (!this._trusted) {
966 this._trusted = true;
968 }
969 }
971 > $onDidChangeWorkspaceTrustedFolders(): void {
972 this._onDidChangeWorkspaceTrustedFolders.fire();
973 }
975 > isResourceTrusted(resource: vscode.Uri): Promise<boolean> {
976 return this._proxy.$isResourceTrusted(resource);
977 }
979 > // --- edit sessions ---
980 >
981 > private _providerHandlePool = 0;
982 >
983 > // called by ext host
984 > registerEditSessionIdentityProvider(scheme: string, provider: vscode.EditSessionIdentityProvider) {
985 if (this._editSessionIdentityProviders.has(scheme)) {
986 throw new Error(`A provider has already been registered for scheme ${scheme}`);
997 });
998 }
1000 > // called by main thread
1001 > async $getEditSessionIdentifier(workspaceFolder: UriComponents, cancellationToken: CancellationToken): Promise<string | undefined> {
1002 this._logService.info('Getting edit session identifier for workspaceFolder', workspaceFolder);
1003 const folder = await this.resolveWorkspaceFolder(URI.revive(workspaceFolder));
1023 return result;
1024 }
1026 > async $provideEditSessionIdentityMatch(workspaceFolder: UriComponents, identity1: string, identity2: string, cancellationToken: CancellationToken): Promise<EditSessionIdentityMatch | undefined> {
1027 this._logService.info('Getting edit session identifier for workspaceFolder', workspaceFolder);
1028 const folder = await this.resolveWorkspaceFolder(URI.revive(workspaceFolder));
1048 return result;
1049 }
1051 > private readonly _onWillCreateEditSessionIdentityEvent = new AsyncEmitter<vscode.EditSessionIdentityWillCreateEvent>();
1052 >
1053 > getOnWillCreateEditSessionIdentityEvent(extension: IExtensionDescription): Event<vscode.EditSessionIdentityWillCreateEvent> {
1054 return (listener, thisArg, disposables) => {
1055 const wrappedListener: IExtensionListener<vscode.EditSessionIdentityWillCreateEvent> = function wrapped(e) { listener.call(thisArg, e); };
1058 };
1059 }
1061 > // main thread calls this to trigger participants
1062 > async $onWillCreateEditSessionIdentity(workspaceFolder: UriComponents, token: CancellationToken, timeout: number): Promise<void> {
1063 const folder = await this.resolveWorkspaceFolder(URI.revive(workspaceFolder));
1064
1079 }
1080 }
1082 > // --- canonical uri identity ---
1083 >
1084 > private readonly _canonicalUriProviders = new Map<string, vscode.CanonicalUriProvider>();
1085 >
1086 > // called by ext host
1087 > registerCanonicalUriProvider(scheme: string, provider: vscode.CanonicalUriProvider) {
1088 if (this._canonicalUriProviders.has(scheme)) {
1089 throw new Error(`A provider has already been registered for scheme ${scheme}`);
1100 });
1101 }
1103 > async provideCanonicalUri(uri: URI, options: vscode.CanonicalUriRequestOptions, cancellationToken: CancellationToken): Promise<URI | undefined> {
1104 const provider = this._canonicalUriProviders.get(uri.scheme);
1105 if (!provider) {
1114 return result;
1115 }
1117 > // called by main thread
1118 > async $provideCanonicalUri(uri: UriComponents, targetScheme: string, cancellationToken: CancellationToken): Promise<UriComponents | undefined> {
1119 return this.provideCanonicalUri(URI.revive(uri), { targetScheme }, cancellationToken);
1120 }
1122 > // --- encodings ---
1123 >
1124 > async decode(content: Uint8Array, args?: { uri?: vscode.Uri; encoding?: string }): Promise<string> {
1125 const [uri, opts] = this.toEncodeDecodeParameters(args);
1126 const options = await this._proxy.$resolveDecoding(uri, opts);
1143 return consumeStream(stream, chunks => chunks.join(''));
1144 }
1146 > async encode(content: string, args?: { uri?: vscode.Uri; encoding?: string }): Promise<Uint8Array> {
1147 const [uri, options] = this.toEncodeDecodeParameters(args);
1148 const { encoding, addBOM } = await this._proxy.$resolveEncoding(uri, options);
1157 return readableToBuffer(res).buffer;
1158 }
1160 > private toEncodeDecodeParameters(opts?: { uri?: vscode.Uri; encoding?: string }): [UriComponents | undefined, { encoding: string } | undefined] {
1161 const uri = isUriComponents(opts?.uri) ? opts.uri : undefined;
1162 const encoding = typeof opts?.encoding === 'string' ? opts.encoding : undefined;
1164 return [uri, encoding ? { encoding } : undefined];
1165 }
1167 >
1168 > export const IExtHostWorkspace = createDecorator<IExtHostWorkspace>('IExtHostWorkspace');
1169 > export interface IExtHostWorkspace extends ExtHostWorkspace, ExtHostWorkspaceShape, IExtHostWorkspaceProvider { }
1170 >
1171 function parseSearchExcludeInclude(include: string | IRelativePatternDto | undefined | null): { pattern: string; folder?: URI } | undefined {
1172 let pattern: string | undefined;
1187 return undefined;
1188 }
1190 > interface IExtensionListener<E> {
1191 > extension: IExtensionDescription;
1192 > (e: E): any;
1193 > }
1194 >
1195 function globsToISearchPatternBuilder(excludes: vscode.GlobPattern[] | undefined): ISearchPatternBuilder<URI>[] {
1196 return (
src/vs/workbench/contrib/chat/common/constants.ts 306 covered LOC · 18 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- constants.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { Schemas } from '../../../../base/common/network.js';
7 > import { IChatSessionsService, isAgentHostTarget, localChatSessionType, SessionType } from './chatSessionsService.js';
8 > import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
9 > import { IStorageService } from '../../../../platform/storage/common/storage.js';
10 > import { IWorkspace } from '../../../../platform/workspace/common/workspace.js';
11 > import { isVirtualWorkspace } from '../../../../platform/workspace/common/virtualWorkspace.js';
12 > import { ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js';
13 > import { ContextKeyExpr, RawContextKey } from '../../../../platform/contextkey/common/contextkey.js';
14 > import { ChatEntitlementContextKeys } from '../../../services/chat/common/chatEntitlementService.js';
15 > import { IsAuxiliaryWindowContext, IsSessionsWindowContext } from '../../../common/contextkeys.js';
16 > import { URI } from '../../../../base/common/uri.js';
17 > import { generateUuid } from '../../../../base/common/uuid.js';
18 > import { LocalChatSessionUri } from './model/chatUri.js';
19 > import { clearUserSelectedSessionType, getRememberedSessionType, hasPreferredCopilotHarness, storeUserSelectedSessionType } from './chatSessionTypePreference.js';
20 >
21 > export const enum BYOKUtilityModelDefault {
22 > None = 'none',
23 > MainAgent = 'mainAgent',
24 > Copilot = 'copilot',
25 > }
26 >
27 > export enum ChatConfiguration {
28 > AIDisabled = 'chat.disableAIFeatures',
29 > PluginsEnabled = 'chat.plugins.enabled',
30 > PluginLocations = 'chat.pluginLocations',
31 > PluginMarketplaces = 'chat.plugins.marketplaces',
32 > ExtraMarketplaces = 'chat.plugins.extraMarketplaces',
33 > StrictMarketplaces = 'chat.plugins.strictMarketplaces',
34 > EnabledPlugins = 'chat.plugins.enabledPlugins',
35 > AgentEnabled = 'chat.agent.enabled',
36 > PlanAgentDefaultModel = 'chat.planAgent.defaultModel',
37 > ExploreAgentDefaultModel = 'chat.exploreAgent.defaultModel',
38 > UtilityModel = 'chat.utilityModel',
39 > UtilitySmallModel = 'chat.utilitySmallModel',
40 > BYOKUtilityModelDefault = 'chat.byokUtilityModelDefault',
41 > RequestQueueingDefaultAction = 'chat.requestQueuing.defaultAction',
42 > AgentStatusEnabled = 'chat.agentsControl.enabled',
43 > EditorAssociations = 'chat.editorAssociations',
44 > UnifiedAgentsBar = 'chat.unifiedAgentsBar.enabled',
45 > AgentSessionProjectionEnabled = 'chat.agentSessionProjection.enabled',
46 > ExtensionToolsEnabled = 'chat.extensionTools.enabled',
47 > RepoInfoEnabled = 'chat.repoInfo.enabled',
48 > EditRequests = 'chat.editRequests',
49 > InlineReferencesStyle = 'chat.inlineReferences.style',
50 > AutoReply = 'chat.autoReply',
51 > GlobalAutoApprove = 'chat.tools.global.autoApprove',
52 > AutoApproveEdits = 'chat.tools.edits.autoApprove',
53 > AutoApprovedUrls = 'chat.tools.urls.autoApprove',
54 > EligibleForAutoApproval = 'chat.tools.eligibleForAutoApproval',
55 > EnableMath = 'chat.math.enabled',
56 > CheckpointsEnabled = 'chat.checkpoints.enabled',
57 > ThinkingStyle = 'chat.agent.thinkingStyle',
58 > ThinkingGenerateTitles = 'chat.agent.thinking.generateTitles',
59 > TerminalToolsInThinking = 'chat.agent.thinking.terminalTools',
60 > SimpleTerminalCollapsible = 'chat.tools.terminal.simpleCollapsible',
61 > CompressOutputEnabled = 'chat.tools.compressOutput.enabled',
62 > ThinkingPhrases = 'chat.agent.thinking.phrases',
63 > AutoExpandToolFailures = 'chat.tools.autoExpandFailures',
64 > TodosShowWidget = 'chat.tools.todos.showWidget',
65 > NotifyWindowOnConfirmation = 'chat.notifyWindowOnConfirmation',
66 > NotifyWindowOnResponseReceived = 'chat.notifyWindowOnResponseReceived',
67 > ChatViewSessionsEnabled = 'chat.viewSessions.enabled',
68 > SessionSyncEnabled = 'chat.sessionSync.enabled',
69 > SessionSyncExcludeRepositories = 'chat.sessionSync.excludeRepositories',
70 > ChatViewSessionsGrouping = 'chat.viewSessions.grouping',
71 > ChatViewSessionsOrientation = 'chat.viewSessions.orientation',
72 > ChatViewProgressBadgeEnabled = 'chat.viewProgressBadge.enabled',
73 > ChatContextUsageEnabled = 'chat.contextUsage.enabled',
74 > Verbose = 'chat.verbose',
75 > ProgressBorder = 'chat.progressBorder.enabled',
76 > SubagentToolCustomAgents = 'chat.customAgentInSubagent.enabled',
77 > SubagentsAllowInvocationsFromSubagents = 'chat.subagents.allowInvocationsFromSubagents',
78 > ShowCodeBlockProgressAnimation = 'chat.agent.codeBlockProgress',
79 > RestoreLastPanelSession = 'chat.restoreLastPanelSession',
80 > ExitAfterDelegation = 'chat.exitAfterDelegation',
81 > ExplainChangesEnabled = 'chat.editing.explainChanges.enabled',
82 > RevealNextChangeOnResolve = 'chat.editing.revealNextChangeOnResolve',
83 > OpenChangedFileInDiffEditor = 'chat.editing.openChangedFileInDiffEditor',
84 > GrowthNotificationEnabled = 'chat.growthNotification.enabled',
85 > TitleBarSignInEnabled = 'chat.titleBar.signIn.enabled',
86 > TitleBarOpenInAgentsWindowEnabled = 'chat.titleBar.openInAgentsWindow.enabled',
87 >
88 > ChatCustomizationsStructuredPreviewEnabled = 'chat.customizations.structuredPreview.enabled',
89 > ChatCustomizationsPromptMigrationEnabled = 'chat.customizations.promptMigration.enabled',
90 > AutopilotAdvancedEnabled = 'chat.autopilot.advanced.enabled',
91 > PlanReviewInlineEditorEnabled = 'chat.planReview.inlineEditor.enabled',
92 > DefaultPermissionLevel = 'chat.permissions.default',
93 > AssistedPermissionsEnabled = 'chat.assistedPermissions.enabled',
94 > PermissionsSandboxToggleEnabled = 'chat.experimental.permissionsSandboxToggle.enabled',
95 > DefaultConfiguration = 'chat.defaultConfiguration',
96 > DefaultModel = 'chat.defaultModel',
97 > ImageCarouselEnabled = 'imageCarousel.chat.enabled',
98 > ArtifactsEnabled = 'chat.artifacts.enabled',
99 > ArtifactsRulesByMimeType = 'chat.artifacts.rules.byMimeType',
100 > ArtifactsRulesByFilePath = 'chat.artifacts.rules.byFilePath',
101 > ArtifactsRulesByMemoryFilePath = 'chat.artifacts.rules.byMemoryFilePath',
102 > ToolConfirmationCarousel = 'chat.tools.confirmationCarousel.enabled',
103 > ToolRiskAssessmentEnabled = 'chat.tools.riskAssessment.enabled',
104 > ToolRiskAssessmentModel = 'chat.tools.riskAssessment.model',
105 > DefaultNewSessionMode = 'chat.newSession.defaultMode',
106 > CopilotCliHideExtensionHostAgents = 'chat.agents.copilotCli.hideExtensionHost',
107 > EditorPreferCopilotHarness = 'chat.editor.preferCopilotHarness',
108 > DefaultToCopilotHarness = 'chat.defaultToCopilotHarness',
109 > EditorLocalAgentEnabled = 'chat.editor.localAgent.enabled',
110 > CopilotCliHideExtensionHostEditor = 'chat.editor.copilotCli.hideExtensionHost',
111 > AgentsHandoffTipMode = 'chat.agentsHandoffTip.mode',
112 > TurnStatusPills = 'chat.turnStatusPills',
113 >
114 > IncrementalRendering = 'chat.experimental.incrementalRendering.enabled',
115 > IncrementalRenderingStyle = 'chat.experimental.incrementalRendering.animationStyle',
116 > IncrementalRenderingBuffering = 'chat.experimental.incrementalRendering.buffering',
117 >
118 > CollectInstructionsInExtension = 'chat.experimental.collectInstructionsInExtension',
119 > ImplicitContextActiveEditor = 'chat.implicitContext.includeActiveEditor',
120 > }
121 >
122 > /**
123 > * The "kind" of agents for custom agents.
124 > */
125 > export enum ChatModeKind {
126 > Ask = 'ask',
127 > Edit = 'edit',
128 > Agent = 'agent'
129 > }
130 >
131 > /**
132 > * The permission level controlling tool auto-approval behavior.
133 > */
134 > export enum ChatPermissionLevel {
135 > /** Use existing auto-approve settings */
136 > Default = 'default',
137 > /** Delegate approval decisions to a model */
138 > Assisted = 'assisted',
139 > /** Auto-approve all tool calls, auto-retry on error */
140 > AutoApprove = 'autoApprove',
141 > /** Everything AutoApprove does plus an internal stop hook that continues until the task is done */
142 > Autopilot = 'autopilot'
143 > }
144 >
145 > const chatPermissionLevels = new Set<string>(Object.values(ChatPermissionLevel));
146 >
147 > export function isChatPermissionLevel(level: unknown | undefined): level is ChatPermissionLevel {
148 return chatPermissionLevels.has(level as string);
149 }
150 > constants.ts
151 > /**
152 > * Shape of the {@link ChatConfiguration.DefaultConfiguration}
153 > * object setting. Controls the starting `mode` and `approvals` for new agent-host
154 > * sessions (such as Copilot CLI). All properties are optional — a missing property
155 > * falls back to the per-axis default.
156 > */
157 > export type AgentSessionMode = 'interactive' | 'plan' | 'autopilot';
158 >
159 > /** Approval values exposed by the `chat.defaultConfiguration` setting. */
160 > export enum ChatDefaultPermissionLevel {
161 > Default = 'default',
162 > Assisted = 'assisted',
163 > AllowAll = 'allowAll',
164 > }
165 >
166 > export interface IChatDefaultConfiguration {
167 > /** Starting agent mode: `interactive` / `plan` / `autopilot`. */
168 > readonly mode?: AgentSessionMode;
169 > /** Starting approval level: `default` / `assisted` / `allowAll`. */
170 > readonly approvals?: ChatDefaultPermissionLevel;
171 > }
172 >
173 > /** Maps a default-configuration value to the internal Agent Host permission level. */
174 > export function getChatPermissionLevelFromDefaultConfiguration(value: unknown): ChatPermissionLevel | undefined {
175 switch (value) {
176 case ChatDefaultPermissionLevel.Default:
185 }
186 }
187 > constants.ts
188 > /**
189 > * Returns true if the permission level enables auto-approval of all tool calls.
190 > * Both {@link ChatPermissionLevel.AutoApprove} and {@link ChatPermissionLevel.Autopilot} enable auto-approval.
191 > */
192 > export function isAutoApproveLevel(level: ChatPermissionLevel | undefined): boolean {
193 return level === ChatPermissionLevel.AutoApprove || level === ChatPermissionLevel.Autopilot;
194 }
195 > constants.ts
196 > /**
197 > * True for {@link ChatPermissionLevel.Autopilot} only. Unlike {@link isAutoApproveLevel}, this
198 > * excludes {@link ChatPermissionLevel.AutoApprove}, so it can gate Autopilot-only behavior such as
199 > * risk-based skipping of tool calls.
200 > */
201 > export function isAutopilotLevel(level: ChatPermissionLevel | undefined): boolean {
202 return level === ChatPermissionLevel.Autopilot;
203 }
204 > constants.ts
205 > // Thinking display modes for pinned content
206 > export enum ThinkingDisplayMode {
207 > Collapsed = 'collapsed',
208 > CollapsedPreview = 'collapsedPreview',
209 > FixedScrolling = 'fixedScrolling',
210 > }
211 >
212 > export enum CollapsedToolsDisplayMode {
213 > Off = 'off',
214 > WithThinking = 'withThinking',
215 > Always = 'always',
216 > }
217 >
218 > export enum ChatNotificationMode {
219 > Off = 'off',
220 > WindowNotFocused = 'windowNotFocused',
221 > Always = 'always',
222 > }
223 >
224 > export type RawChatParticipantLocation = 'panel' | 'terminal' | 'notebook' | 'editing-session';
225 >
226 > export enum ChatAgentLocation {
227 > /**
228 > * This is chat, whether it's in the sidebar, a chat editor, or quick chat.
229 > * Leaving the values alone as they are in stored data so we don't have to normalize them.
230 > */
231 > Chat = 'panel',
232 > Terminal = 'terminal',
233 > Notebook = 'notebook',
234 > /**
235 > * EditorInline means inline chat in a text editor.
236 > */
237 > EditorInline = 'editor',
238 > }
239 >
240 > export namespace ChatAgentLocation {
241 > export function fromRaw(value: RawChatParticipantLocation | string): ChatAgentLocation {
242 switch (value) {
243 case 'panel': return ChatAgentLocation.Chat;
248 return ChatAgentLocation.Chat;
249 }
250 > } constants.ts
251 >
252 > /**
253 > * List of file schemes that are always unsupported for use in chat
254 > */
255 > const chatAlwaysUnsupportedFileSchemes = new Set([
256 > Schemas.vscodeChatEditor,
257 > Schemas.walkThrough,
258 > Schemas.vscodeLocalChatSession,
259 > Schemas.vscodeSettings,
260 > Schemas.webviewPanel,
261 > Schemas.vscodeUserData,
262 > Schemas.extension,
263 > 'ccreq',
264 > 'openai-codex', // Codex session custom editor scheme
265 > ]);
266 >
267 > export function isSupportedChatFileScheme(accessor: ServicesAccessor, scheme: string): boolean {
268 const chatService = accessor.get(IChatSessionsService);
269
281 return true;
282 }
283 > constants.ts
284 > /**
285 > * Returns the effective default session type for a new chat in the VS Code
286 > * editor window.
287 > *
288 > * Virtual workspaces always default to {@link localChatSessionType}. Otherwise,
289 > * when the agent host is enabled and `chat.defaultToCopilotHarness` is opted in,
290 > * Agent Host Copilot CLI is the default. It falls back to the local harness
291 > * when enabled, or to the first visible non-local provider.
292 > */
293 > export function getComputedDefaultSessionType(
294 configurationService: IConfigurationService,
295 chatSessionsService: Pick<IChatSessionsService, 'getChatSessionContribution' | 'getAllChatSessionContributions'>,
311 return getVisibleNonLocalEditorChatSessionTypes(configurationService, chatSessionsService, workspace)[0] ?? localChatSessionType;
312 }
313 > constants.ts
314 > export function getComputedDefaultSessionResource(
315 configurationService: IConfigurationService,
316 chatSessionsService: Pick<IChatSessionsService, 'getChatSessionContribution' | 'getAllChatSessionContributions'>,
323 : URI.from({ scheme: defaultType, path: `/untitled-${generateUuid()}` });
324 }
325 > constants.ts
326 > export function isRememberedSessionTypeUsable(
327 sessionType: string,
328 configurationService: IConfigurationService,
338 return !!chatSessionsService.getChatSessionContribution(sessionType);
339 }
340 > constants.ts
341 > export interface IDefaultNewChatSessionTypeOptions {
342 > readonly explicitOverride?: string;
343 > readonly currentSessionType?: string;
344 > }
345 >
346 > export interface IResolvedNewChatSessionType {
347 > /** The session type to open for the new chat. */
348 > readonly sessionType: string;
349 > /**
350 > * True when {@link sessionType} is the one-time `chat.editor.preferCopilotHarness`
351 > * swap. The caller must persist the marker (via `markPreferredCopilotHarness`)
352 > * only once it has actually applied this session type, so the migration is not
353 > * consumed by a caller that discards the result.
354 > */
355 > readonly isPreferCopilotHarnessSwap: boolean;
356 > }
357 >
358 > export function getDefaultNewChatSessionType(
359 configurationService: IConfigurationService,
360 chatSessionsService: Pick<IChatSessionsService, 'getChatSessionContribution' | 'getAllChatSessionContributions'>,
379 return getComputedDefaultSessionType(configurationService, chatSessionsService, workspace, agentHostEnabled);
380 }
381 > constants.ts
382 > export function resolveDefaultNewChatSessionType(
383 configurationService: IConfigurationService,
384 chatSessionsService: Pick<IChatSessionsService, 'getChatSessionContribution' | 'getAllChatSessionContributions'>,
413 return { sessionType: getDefaultNewChatSessionType(configurationService, chatSessionsService, storageService, workspace, agentHostEnabled, options), isPreferCopilotHarnessSwap: false };
414 }
415 > constants.ts
416 function getUsableRememberedSessionType(
417 storageService: IStorageService,
423 return remembered && isRememberedSessionTypeUsable(remembered, configurationService, chatSessionsService, workspace) ? remembered : undefined;
424 }
425 > constants.ts
426 > export function getDefaultNewChatSessionResource(
427 configurationService: IConfigurationService,
428 chatSessionsService: Pick<IChatSessionsService, 'getChatSessionContribution' | 'getAllChatSessionContributions'>,
437 : URI.from({ scheme: defaultType, path: `/untitled-${generateUuid()}` });
438 }
439 > constants.ts
440 > export function recordUserSelectedSessionType(
441 storageService: IStorageService,
442 configurationService: IConfigurationService,
452 }
453 }
454 > constants.ts
455 > export function isEditorLocalAgentEnabled(configurationService: IConfigurationService, workspace: IWorkspace): boolean {
456 return isVirtualWorkspace(workspace) || (configurationService.getValue<boolean>(ChatConfiguration.EditorLocalAgentEnabled) ?? true);
457 }
458 > constants.ts
459 > export function isVisibleEditorChatSessionType(
460 sessionType: string,
461 configurationService: IConfigurationService,
473 return !!chatSessionsService.getChatSessionContribution(sessionType);
474 }
475 > constants.ts
476 function getVisibleNonLocalEditorChatSessionTypes(
477 configurationService: IConfigurationService,
487 return Array.from(sessionTypes);
488 }
489 > constants.ts
490 > export const MANAGE_CHAT_COMMAND_ID = 'workbench.action.chat.manage';
491 > export const CHAT_OPEN_AGENT_HOST_CHAT_COMMAND_ID = 'workbench.action.chat.openAgentHostChat';
492 >
493 > export const OPEN_WORKSPACE_IN_AGENTS_WINDOW_COMMAND_ID = 'workbench.action.openWorkspaceInAgentsWindow';
494 > export const OPEN_AGENTS_WINDOW_COMMAND_ID = 'workbench.action.openAgentsWindow';
495 > export const OPEN_AGENTS_WINDOW_PRECONDITION = ContextKeyExpr.and(
496 > ChatEntitlementContextKeys.Setup.hidden.negate(),
497 > ChatEntitlementContextKeys.Setup.disabledInWorkspace.negate(),
498 > IsSessionsWindowContext.negate(),
499 > ContextKeyExpr.has(`config.${ChatConfiguration.AgentEnabled}`),
500 > IsAuxiliaryWindowContext.negate()
501 > );
502 >
503 > export const ChatEditorTitleMaxLength = 30;
504 >
505 > export const CHAT_TERMINAL_OUTPUT_MAX_PREVIEW_LINES = 1000;
506 > export const CONTEXT_MODELS_EDITOR = new RawContextKey<boolean>('inModelsEditor', false);
507 > export const CONTEXT_MODELS_SEARCH_FOCUS = new RawContextKey<boolean>('inModelsSearch', false);
src/vs/base/common/yaml.ts 301 covered LOC · 54 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- yaml.ts
2 > * Copyright (c) Microsoft 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 >
8 > /**
9 > * Parses a simplified YAML-like input from a single string.
10 > * Supports objects, arrays, primitive types (string, number, boolean, null).
11 > * Tracks positions for error reporting and node locations.
12 > *
13 > * Limitations:
14 > * - No anchors or references
15 > * - No complex types (dates, binary)
16 > * - No single pair implicit entries
17 > *
18 > * @param input A string containing the YAML-like input
19 > * @param errors Array to collect parsing errors
20 > * @returns The parsed representation (YamlMapNode, YamlSequenceNode, or YamlScalarNode)
21 > */
22 > export function parse(input: string, errors: YamlParseError[] = [], options: ParseOptions = {}): YamlNode | undefined {
23 const scanner = new YamlScanner(input);
24 const tokens = scanner.scan();
26 return parser.parse();
27 }
28 > yaml.ts
29 > /**
30 > * Helper to parse a Markdown with YAML frontmatter document
31 > * @returns
32 > */
33 > export function parseFrontMatter(input: string, errors: YamlParseError[] = [], options: ParseOptions = {}): MarkdownNode | undefined {
34 const tokens = new YamlScanner(input).scan();
35 if (tokens.length === 0 || tokens[0].type !== TokenType.DocumentStart) {
46 return new MarkdownNode(header, body);
47 }
48 > yaml.ts
49 > export class MarkdownNode {
50 > constructor(public readonly header: YamlNode | undefined, public readonly body: string) {
51 }
52 > yaml.ts
53 > getStringValue(name: string): string | undefined {
54 if (this.header && this.header.type === 'map') {
55 const property = this.header.properties.find(p => p.key.value === name);
60 return undefined;
61 }
62 > yaml.ts
63 > getStringArrayValue(name: string): string[] | undefined {
64 if (this.header && this.header.type === 'map') {
65 const property = this.header.properties.find(p => p.key.value === name);
76 return undefined;
77 }
78 > yaml.ts
79 > getBooleanValue(name: string): boolean | undefined {
80 const value = this.getStringValue(name);
81 if (value === 'true') {
86 return undefined;
87 }
88 > } yaml.ts
89 >
90 >
91 > /**
92 > * Parses a comma-separated list from a scalar node's value into an array of scalars.
93 > * Handles single-quoted and double-quoted items, trimming surrounding whitespace for
94 > * unquoted items. Offsets on each produced scalar node are relative to the original
95 > * document that the input scalar was parsed from.
96 > *
97 > * Internally wraps the scalar value in `[…]` and delegates to the full YAML parser so
98 > * that quoting, whitespace, and escape handling are consistent with the rest of the parser.
99 > *
100 > * @param scalar A scalar node whose value contains a comma-separated list.
101 > */
102 > export function parseCommaSeparatedList(value: string, offset: number = 0): YamlScalarNode[] {
103 // Wrap the value as a YAML flow sequence and parse it.
104 const parsed = parse(`[${value}]`);
118 return items;
119 }
120 > yaml.ts
121 > // -- AST Node Types ----------------------------------------------------------
122 >
123 > export interface YamlScalarNode {
124 > readonly type: 'scalar';
125 > readonly value: string;
126 > readonly rawValue: string;
127 > readonly startOffset: number;
128 > readonly endOffset: number;
129 > readonly format: 'single' | 'double' | 'none' | 'literal' | 'folded';
130 > }
131 >
132 > export interface YamlMapNode {
133 > readonly type: 'map';
134 > readonly properties: { key: YamlScalarNode; value: YamlNode }[];
135 > readonly style: 'block' | 'flow';
136 > readonly startOffset: number;
137 > readonly endOffset: number;
138 > }
139 >
140 > export interface YamlSequenceNode {
141 > readonly type: 'sequence';
142 > readonly items: YamlNode[];
143 > readonly style: 'block' | 'flow';
144 > readonly startOffset: number;
145 > readonly endOffset: number;
146 > }
147 >
148 > export type YamlNode = YamlSequenceNode | YamlMapNode | YamlScalarNode;
149 >
150 > export interface YamlParseError {
151 > readonly message: string;
152 > readonly startOffset: number;
153 > readonly endOffset: number;
154 > readonly code: string;
155 > }
156 >
157 > export interface ParseOptions {
158 > readonly allowDuplicateKeys?: boolean;
159 > }
160 >
161 > // -- Token Types -------------------------------------------------------------
162 >
163 > const enum TokenType {
164 > // Scalar values (unquoted, single-quoted, double-quoted)
165 > Scalar,
166 > // Structural tokens
167 > Colon, // ':'
168 > Dash, // '- '
169 > Comma, // ','
170 > FlowMapStart, // '{'
171 > FlowMapEnd, // '}'
172 > FlowSeqStart, // '['
173 > FlowSeqEnd, // ']'
174 > // Whitespace / structure
175 > Newline,
176 > Indent, // leading whitespace at start of line (carries the indent level)
177 > Comment,
178 > DocumentStart, // '---'
179 > DocumentEnd, // '...'
180 > EOF,
181 > }
182 >
183 > interface Token {
184 > readonly type: TokenType;
185 > readonly startOffset: number;
186 > readonly endOffset: number;
187 > /** For Scalar tokens: the raw text (including quotes). */
188 > readonly rawValue: string;
189 > /** For Scalar tokens: the interpreted string value. */
190 > readonly value: string;
191 > /** For Scalar tokens: quote style. */
192 > readonly format: 'single' | 'double' | 'none' | 'literal' | 'folded';
193 > /** For Indent tokens: the column (number of spaces). */
194 > readonly indent: number;
195 > }
196 >
197 function makeToken(
198 type: TokenType,
211 };
212 }
213 > yaml.ts
214 > // -- Scanner -----------------------------------------------------------------
215 >
216 > class YamlScanner {
217 > private pos = 0;
218 > private readonly tokens: Token[] = [];
219 > // Track flow nesting depth so commas and flow indicators are only special inside flow collections
220 > private flowDepth = 0;
221 > // Track whether we've already seen a block colon on the current line.
222 > // After the first key: value colon, subsequent ': ' on the same line is part of the scalar value.
223 > private seenBlockColon = false;
224 > private seenDocumentStart = 0;
225 >
226 > constructor(private readonly input: string) { }
227 >
228 > scan(maxDocuments = 1): Token[] {
229 while (this.pos < this.input.length) {
230 this.scanLine();
236 return this.tokens;
237 }
238 > yaml.ts
239 > // Scan a single logical line (up to and including the newline character)
240 > private scanLine(): void {
241 this.seenBlockColon = false;
242 // Handle blank lines / lines that are only whitespace
319 this.scanNewline();
320 }
321 > yaml.ts
322 > private scanLineContent(): void {
323 while (this.pos < this.input.length && this.peekChar() !== '\n' && this.peekChar() !== '\r') {
324 this.skipInlineWhitespace();
376 }
377 }
378 > yaml.ts
379 > /** Check if '-' is a block sequence dash (followed by space, newline, or EOF) */
380 > private isBlockDash(): boolean {
381 const next = this.input[this.pos + 1];
382 return next === undefined || next === ' ' || next === '\t' || next === '\n' || next === '\r';
383 }
384 > yaml.ts
385 > /** Check if ':' acts as a mapping value indicator (followed by space, newline, EOF, or flow indicator) */
386 > private isBlockColon(): boolean {
387 // In block context, after the first key-value colon on a line,
388 // subsequent ': ' is part of the scalar value, not a mapping indicator.
394 return false;
395 }
396 > yaml.ts
397 > /** Check if the last non-whitespace token is a JSON-like node (quoted scalar or flow end) */
398 > private lastTokenIsJsonLike(): boolean {
399 for (let i = this.tokens.length - 1; i >= 0; i--) {
400 const t = this.tokens[i];
409 return false;
410 }
411 > yaml.ts
412 > private scanQuotedScalar(quote: '\'' | '"'): void {
413 const start = this.pos;
414 this.pos++; // skip opening quote
567 }));
568 }
569 > yaml.ts
570 > private scanUnquotedScalar(): void {
571 const start = this.pos;
572 let end = this.pos;
598 }));
599 }
600 > yaml.ts
601 > /**
602 > * Check if '|' or '>' at the current position is a block scalar indicator.
603 > * Must be followed by optional indentation/chomping indicators, optional comment, then newline.
604 > */
605 > private isBlockScalarStart(): boolean {
606 let p = this.pos + 1;
607 // Skip optional indentation indicator (digit 1-9) and chomping indicator (+/-)
619 return c === '\n' || c === '\r' || c === '#';
620 }
621 > yaml.ts
622 > /**
623 > * Scan a block scalar (literal '|' or folded '>').
624 > * Parses the header line for indentation indicator and chomping mode,
625 > * then collects all content lines that are indented beyond the detected indentation.
626 > */
627 > private scanBlockScalar(style: '|' | '>'): void {
628 const start = this.pos;
629 this.pos++; // skip '|' or '>'
849 }));
850 }
851 > yaml.ts
852 > /**
853 > * Determine the parent block's indentation level for a block scalar.
854 > * Looks at preceding tokens to find the context:
855 > * - After Colon: the indentation of the line containing the mapping key
856 > * - After Dash: the column of the dash
857 > * - At document level: -1 (allows content at indent 0)
858 > */
859 > private getParentBlockIndent(blockScalarPos: number): number {
860 for (let i = this.tokens.length - 1; i >= 0; i--) {
861 const t = this.tokens[i];
883 return 0;
884 }
885 > yaml.ts
886 > /**
887 > * Get the column (0-based offset from start of line) for a position in the input.
888 > */
889 > private getColumnAt(offset: number): number {
890 let col = 0;
891 let p = offset - 1;
896 return col;
897 }
898 > yaml.ts
899 > private scanComment(): void {
900 const start = this.pos;
901 while (this.pos < this.input.length && this.input[this.pos] !== '\n' && this.input[this.pos] !== '\r') {
907 }));
908 }
909 > yaml.ts
910 > private scanNewline(): void {
911 const start = this.pos;
912 if (this.consumeNewline()) {
914 }
915 }
916 > yaml.ts
917 > private skipInlineWhitespace(): void {
918 while (this.pos < this.input.length) {
919 const ch = this.input[this.pos];
925 }
926 }
927 > yaml.ts
928 > /** Advance past a newline sequence (\r\n, \n, or \r). Returns true if a newline was consumed. */
929 > private consumeNewline(): boolean {
930 if (this.pos >= this.input.length) { return false; }
931 if (this.input[this.pos] === '\r' && this.input[this.pos + 1] === '\n') {
939 return false;
940 }
941 > yaml.ts
942 > private peekChar(): string {
943 return this.input[this.pos];
944 }
945 > } yaml.ts
946 >
947 > // -- Parser ------------------------------------------------------------------
948 >
949 > class YamlParser {
950 > private pos = 0;
951 >
952 > constructor(
953 private readonly tokens: Token[],
954 private readonly input: string,
956 private readonly options: ParseOptions,
957 ) { }
958 > yaml.ts
959 > parse(): YamlNode | undefined {
960 this.skipNewlinesAndComments();
961 // Skip document start marker (---) if present
970 return result;
971 }
972 > yaml.ts
973 > // -- helpers ----------------------------------------------------------
974 >
975 > private currentToken(): Token {
976 return this.tokens[this.pos];
977 }
978 > yaml.ts
979 > private peek(offset = 0): Token {
980 return this.tokens[Math.min(this.pos + offset, this.tokens.length - 1)];
981 }
982 > yaml.ts
983 > private advance(): Token {
984 const t = this.tokens[this.pos];
985 if (t.type !== TokenType.EOF) {
988 return t;
989 }
990 > yaml.ts
991 > private expect(type: TokenType): Token {
992 const t = this.currentToken();
993 if (t.type === type) {
996 return t;
997 }
998 > yaml.ts
999 > private emitError(message: string, startOffset: number, endOffset: number, code: string): void {
1000 this.errors.push({ message, startOffset, endOffset, code });
1001 }
1002 > yaml.ts
1003 > private skipNewlinesAndComments(): void {
1004 while (
1005 this.currentToken().type === TokenType.Newline ||
1010 }
1011 }
1012 > yaml.ts
1013 > /** Returns true if the current Indent token is followed immediately by Newline/Comment/EOF */
1014 > private isFollowedByNewlineOrComment(): boolean {
1015 const next = this.peek(1);
1016 return next.type === TokenType.Newline || next.type === TokenType.Comment || next.type === TokenType.EOF;
1017 }
1018 > yaml.ts
1019 > /**
1020 > * Determines the current indentation level.
1021 > * If the current token is an Indent, returns its indent value.
1022 > * Otherwise returns 0 (token is at column 0).
1023 > */
1024 > private currentIndent(): number {
1025 if (this.currentToken().type === TokenType.Indent) {
1026 return this.currentToken().indent;
1028 return 0;
1029 }
1030 > yaml.ts
1031 > // -- Main parse entry for a value at a given indentation --------------
1032 >
1033 > private parseValue(parentIndent: number): YamlNode | undefined {
1034 this.skipNewlinesAndComments();
1035 const token = this.currentToken();
1065 return undefined;
1066 }
1067 > yaml.ts
1068 > /** Peek past an optional Indent token to see the first content token */
1069 > private peekPastIndent(): Token {
1070 if (this.currentToken().type === TokenType.Indent) {
1071 return this.peek(1);
1073 return this.currentToken();
1074 }
1075 > yaml.ts
1076 > /** Check if tokens at current position look like a mapping entry (key: value) */
1077 > private looksLikeMapping(): boolean {
1078 let offset = 0;
1079 if (this.peek(offset).type === TokenType.Indent) { offset++; }
1084 return false;
1085 }
1086 > yaml.ts
1087 > // -- Scalar ----------------------------------------------------------
1088 >
1089 > private parseScalar(parentIndent: number = -1): YamlScalarNode {
1090 // Skip indent if present
1091 if (this.currentToken().type === TokenType.Indent) {
1100 return this.parsePlainMultiline(token, parentIndent);
1101 }
1102 > yaml.ts
1103 > /**
1104 > * Parse a multiline plain scalar. The first line's token is already consumed.
1105 > * Continuation lines must be indented deeper than `parentIndent`.
1106 > * Line folding rules:
1107 > * - Single line break → space
1108 > * - Each empty line → preserved as \n
1109 > */
1110 > private parsePlainMultiline(firstToken: Token, parentIndent: number): YamlScalarNode {
1111 let value = firstToken.value;
1112 let endOffset = firstToken.endOffset;
1249 };
1250 }
1251 > yaml.ts
1252 > // -- Block mapping ---------------------------------------------------
1253 >
1254 > private parseBlockMapping(baseIndent: number, inlineFirstEntry = false): YamlMapNode {
1255 const startOffset = this.currentToken().startOffset;
1256 const properties: { key: YamlScalarNode; value: YamlNode }[] = [];
1304 return { type: 'map', properties, style: 'block', startOffset, endOffset };
1305 }
1306 > yaml.ts
1307 > private parseMappingEntry(baseIndent: number): { key: YamlScalarNode; value: YamlNode } | undefined {
1308 // Skip indent
1309 if (this.currentToken().type === TokenType.Indent) {
1327 return { key, value };
1328 }
1329 > yaml.ts
1330 > private parseMappingValue(baseIndent: number, colonToken: Token): YamlNode {
1331 // Check if there's a value on the same line after the colon
1332 const next = this.currentToken();
1377 return this.parseValue(baseIndent) ?? this.makeEmptyScalar(colonToken.endOffset);
1378 }
1379 > yaml.ts
1380 > // -- Block sequence --------------------------------------------------
1381 >
1382 > private parseBlockSequence(baseIndent: number): YamlSequenceNode {
1383 const items: YamlNode[] = [];
1384 const startOffset = this.currentToken().startOffset;
1434 return { type: 'sequence', items, style: 'block', startOffset, endOffset };
1435 }
1436 > yaml.ts
1437 > private parseSequenceItemValue(baseIndent: number, dashToken: Token): YamlNode {
1438 const next = this.currentToken();
1439
1482 return this.parseValue(baseIndent) ?? this.makeEmptyScalar(dashToken.endOffset);
1483 }
1484 > yaml.ts
1485 > /** Calculate the start of the line containing the given offset */
1486 > private getLineStart(offset: number): number {
1487 let i = offset - 1;
1488 while (i >= 0 && this.input[i] !== '\n' && this.input[i] !== '\r') {
1491 return i + 1;
1492 }
1493 > yaml.ts
1494 > // -- Flow map --------------------------------------------------------
1495 >
1496 > private parseFlowMap(): YamlMapNode {
1497 const startToken = this.advance(); // consume '{'
1498 const properties: { key: YamlScalarNode; value: YamlNode }[] = [];
1551 };
1552 }
1553 > yaml.ts
1554 > // -- Flow sequence ---------------------------------------------------
1555 >
1556 > private parseFlowSeq(): YamlSequenceNode {
1557 const startToken = this.advance(); // consume '['
1558 const items: YamlNode[] = [];
1598 };
1599 }
1600 > yaml.ts
1601 > /**
1602 > * Parse a scalar inside a flow collection, handling multiline plain scalars.
1603 > * In flow context, plain (unquoted) scalars can span multiple lines;
1604 > * line breaks are folded into spaces.
1605 > */
1606 > private parseFlowScalar(): YamlScalarNode {
1607 const token = this.advance();
1608 // Quoted scalars are complete as-is (scanner handles their multiline folding)
1652 };
1653 }
1654 > yaml.ts
1655 > /** Parse a value in flow context (used after colon in flow mappings/implicit mappings) */
1656 > private parseFlowValue(): YamlNode {
1657 if (this.currentToken().type === TokenType.FlowMapStart) {
1658 return this.parseFlowMap();
1665 }
1666 }
1667 > yaml.ts
1668 > /** Skip whitespace, newlines, and comments inside flow collections */
1669 > private skipFlowWhitespace(): void {
1670 while (true) {
1671 const t = this.currentToken().type;
1677 }
1678 }
1679 > yaml.ts
1680 > private scalarFromToken(token: Token): YamlScalarNode {
1681 return {
1682 type: 'scalar',
1688 };
1689 }
1690 > yaml.ts
1691 > private makeEmptyScalar(offset: number): YamlScalarNode {
1692 return {
1693 type: 'scalar',
src/vs/base/common/types.ts 299 covered LOC · 31 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); types.ts
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/workbench/services/lifecycle/common/lifecycle.ts 292 covered LOC · 3 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 { CancellationToken } from '../../../../base/common/cancellation.js';
7 > import { Event } from '../../../../base/common/event.js';
8 > import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
9 >
10 > export const ILifecycleService = createDecorator<ILifecycleService>('lifecycleService');
11 >
12 > /**
13 > * An event that is send out when the window is about to close. Clients have a chance to veto
14 > * the closing by either calling veto with a boolean "true" directly or with a promise that
15 > * resolves to a boolean. Returning a promise is useful in cases of long running operations
16 > * on shutdown.
17 > *
18 > * Note: It is absolutely important to avoid long running promises if possible. Please try hard
19 > * to return a boolean directly. Returning a promise has quite an impact on the shutdown sequence!
20 > */
21 > export interface BeforeShutdownEvent {
22 >
23 > /**
24 > * The reason why the application will be shutting down.
25 > */
26 > readonly reason: ShutdownReason;
27 >
28 > /**
29 > * Allows to veto the shutdown. The veto can be a long running operation but it
30 > * will block the application from closing.
31 > *
32 > * @param id to identify the veto operation in case it takes very long or never
33 > * completes.
34 > */
35 > veto(value: boolean | Promise<boolean>, id: string): void;
36 > }
37 >
38 > export interface InternalBeforeShutdownEvent extends BeforeShutdownEvent {
39 >
40 > /**
41 > * Allows to set a veto operation to run after all other
42 > * vetos have been handled from the `BeforeShutdownEvent`
43 > *
44 > * This method is hidden from the API because it is intended
45 > * to be only used once internally.
46 > */
47 > finalVeto(vetoFn: () => boolean | Promise<boolean>, id: string): void;
48 > }
49 >
50 > /**
51 > * An event that signals an error happened during `onBeforeShutdown` veto handling.
52 > * In this case the shutdown operation will not proceed because this is an unexpected
53 > * condition that is treated like a veto.
54 > */
55 > export interface BeforeShutdownErrorEvent {
56 >
57 > /**
58 > * The reason why the application is shutting down.
59 > */
60 > readonly reason: ShutdownReason;
61 >
62 > /**
63 > * The error that happened during shutdown handling.
64 > */
65 > readonly error: Error;
66 > }
67 >
68 > export enum WillShutdownJoinerOrder {
69 >
70 > /**
71 > * Joiners to run before the `Last` joiners. This is the default order and best for
72 > * most cases. You can be sure that services are still functional at this point.
73 > */
74 > Default = 1,
75 >
76 > /**
77 > * The joiners to run last. This should ONLY be used in rare cases when you have no
78 > * dependencies to workbench services or state. The workbench may be in a state where
79 > * resources can no longer be accessed or changed.
80 > */
81 > Last
82 > }
83 >
84 > export interface IWillShutdownEventJoiner {
85 > readonly id: string;
86 > readonly label: string;
87 > readonly order?: WillShutdownJoinerOrder;
88 > }
89 >
90 > export interface IWillShutdownEventDefaultJoiner extends IWillShutdownEventJoiner {
91 > readonly order?: WillShutdownJoinerOrder.Default;
92 > }
93 >
94 > export interface IWillShutdownEventLastJoiner extends IWillShutdownEventJoiner {
95 > readonly order: WillShutdownJoinerOrder.Last;
96 > }
97 >
98 > /**
99 > * An event that is send out when the window closes. Clients have a chance to join the closing
100 > * by providing a promise from the join method. Returning a promise is useful in cases of long
101 > * running operations on shutdown.
102 > *
103 > * Note: It is absolutely important to avoid long running promises if possible. Please try hard
104 > * to return a boolean directly. Returning a promise has quite an impact on the shutdown sequence!
105 > */
106 > export interface WillShutdownEvent {
107 >
108 > /**
109 > * The reason why the application is shutting down.
110 > */
111 > readonly reason: ShutdownReason;
112 >
113 > /**
114 > * A token that will signal cancellation when the
115 > * shutdown was forced by the user.
116 > */
117 > readonly token: CancellationToken;
118 >
119 > /**
120 > * Allows to join the shutdown. The promise can be a long running operation but it
121 > * will block the application from closing.
122 > *
123 > * @param promise the promise to join the shutdown event.
124 > * @param joiner to identify the join operation in case it takes very long or never
125 > * completes.
126 > */
127 > join(promise: Promise<void>, joiner: IWillShutdownEventDefaultJoiner): void;
128 >
129 > /**
130 > * Allows to join the shutdown at the end. The promise can be a long running operation but it
131 > * will block the application from closing.
132 > *
133 > * @param promiseFn the promise to join the shutdown event.
134 > * @param joiner to identify the join operation in case it takes very long or never
135 > * completes.
136 > */
137 > join(promiseFn: (() => Promise<void>), joiner: IWillShutdownEventLastJoiner): void;
138 >
139 > /**
140 > * Allows to access the joiners that have not finished joining this event.
141 > */
142 > joiners(): IWillShutdownEventJoiner[];
143 >
144 > /**
145 > * Allows to enforce the shutdown, even when there are
146 > * pending `join` operations to complete.
147 > */
148 > force(): void;
149 > }
150 >
151 > export const enum ShutdownReason {
152 >
153 > /**
154 > * The window is closed.
155 > */
156 > CLOSE = 1,
157 >
158 > /**
159 > * The window closes because the application quits.
160 > */
161 > QUIT,
162 >
163 > /**
164 > * The window is reloaded.
165 > */
166 > RELOAD,
167 >
168 > /**
169 > * The window is loaded into a different workspace context.
170 > */
171 > LOAD
172 > }
173 >
174 > export const enum StartupKind {
175 > NewWindow = 1,
176 > ReloadedWindow = 3,
177 > ReopenedWindow = 4
178 > }
179 >
180 > export function StartupKindToString(startupKind: StartupKind): string {
181 switch (startupKind) {
182 case StartupKind.NewWindow: return 'NewWindow';
185 }
186 }
187 > lifecycle.ts
188 > export const enum LifecyclePhase {
189 >
190 > /**
191 > * The first phase signals that we are about to startup getting ready.
192 > *
193 > * Note: doing work in this phase blocks an editor from showing to
194 > * the user, so please rather consider to use `Restored` phase.
195 > */
196 > Starting = 1,
197 >
198 > /**
199 > * Services are ready and the window is about to restore its UI state.
200 > *
201 > * Note: doing work in this phase blocks an editor from showing to
202 > * the user, so please rather consider to use `Restored` phase.
203 > */
204 > Ready = 2,
205 >
206 > /**
207 > * Views, panels and editors have restored. Editors are given a bit of
208 > * time to restore their contents.
209 > */
210 > Restored = 3,
211 >
212 > /**
213 > * The last phase after views, panels and editors have restored and
214 > * some time has passed (2-5 seconds).
215 > */
216 > Eventually = 4
217 > }
218 >
219 > export function LifecyclePhaseToString(phase: LifecyclePhase): string {
220 switch (phase) {
221 case LifecyclePhase.Starting: return 'Starting';
225 }
226 }
227 > lifecycle.ts
228 > /**
229 > * A lifecycle service informs about lifecycle events of the
230 > * application, such as shutdown.
231 > */
232 > export interface ILifecycleService {
233 >
234 > readonly _serviceBrand: undefined;
235 >
236 > /**
237 > * Value indicates how this window got loaded.
238 > */
239 > readonly startupKind: StartupKind;
240 >
241 > /**
242 > * A flag indicating in what phase of the lifecycle we currently are.
243 > */
244 > phase: LifecyclePhase;
245 >
246 > /**
247 > * Fired before shutdown happens. Allows listeners to veto against the
248 > * shutdown to prevent it from happening.
249 > *
250 > * The event carries a shutdown reason that indicates how the shutdown was triggered.
251 > */
252 > readonly onBeforeShutdown: Event<BeforeShutdownEvent>;
253 >
254 > /**
255 > * Fired when the shutdown was prevented by a component giving veto.
256 > */
257 > readonly onShutdownVeto: Event<void>;
258 >
259 > /**
260 > * Fired when an error happened during `onBeforeShutdown` veto handling.
261 > * In this case the shutdown operation will not proceed because this is
262 > * an unexpected condition that is treated like a veto.
263 > *
264 > * The event carries a shutdown reason that indicates how the shutdown was triggered.
265 > */
266 > readonly onBeforeShutdownError: Event<BeforeShutdownErrorEvent>;
267 >
268 > /**
269 > * Fired when no client is preventing the shutdown from happening (from `onBeforeShutdown`).
270 > *
271 > * This event can be joined with a long running operation via `WillShutdownEvent#join()` to
272 > * handle long running shutdown operations.
273 > *
274 > * The event carries a shutdown reason that indicates how the shutdown was triggered.
275 > */
276 > readonly onWillShutdown: Event<WillShutdownEvent>;
277 >
278 > /**
279 > * A flag indicating that we are about to shutdown without further veto.
280 > */
281 > readonly willShutdown: boolean;
282 >
283 > /**
284 > * Fired when the shutdown is about to happen after long running shutdown operations
285 > * have finished (from `onWillShutdown`).
286 > *
287 > * This event should be used to dispose resources.
288 > */
289 > readonly onDidShutdown: Event<void>;
290 >
291 > /**
292 > * Returns a promise that resolves when a certain lifecycle phase
293 > * has started.
294 > */
295 > when(phase: LifecyclePhase): Promise<void>;
296 >
297 > /**
298 > * Triggers a shutdown of the workbench. Depending on native or web, this can have
299 > * different implementations and behaviour.
300 > *
301 > * **Note:** this should normally not be called. See related methods in `IHostService`
302 > * and `INativeHostService` to close a window or quit the application.
303 > */
304 > shutdown(): Promise<void>;
305 > }
src/vs/platform/mcp/common/mcpManagement.ts 281 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- mcpManagement.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { CancellationToken } from '../../../base/common/cancellation.js';
7 > import { Event } from '../../../base/common/event.js';
8 > import { IMarkdownString } from '../../../base/common/htmlContent.js';
9 > import { IIterativePager } from '../../../base/common/paging.js';
10 > import { URI } from '../../../base/common/uri.js';
11 > import { SortBy, SortOrder } from '../../extensionManagement/common/extensionManagement.js';
12 > import { createDecorator } from '../../instantiation/common/instantiation.js';
13 > import { IMcpServerIdentity } from './allowedMcpServers.js';
14 > import { IMcpSandboxConfiguration, IMcpServerConfiguration, IMcpServerVariable } from './mcpPlatformTypes.js';
15 >
16 > export type InstallSource = 'gallery' | 'local';
17 >
18 > export interface ILocalMcpServer {
19 > readonly name: string;
20 > readonly config: IMcpServerConfiguration;
21 > readonly rootSandbox?: IMcpSandboxConfiguration;
22 > readonly version?: string;
23 > readonly mcpResource: URI;
24 > readonly location?: URI;
25 > readonly displayName?: string;
26 > readonly description?: string;
27 > readonly galleryUrl?: string;
28 > readonly galleryId?: string;
29 > readonly repositoryUrl?: string;
30 > readonly readmeUrl?: URI;
31 > readonly publisher?: string;
32 > readonly publisherDisplayName?: string;
33 > readonly icon?: {
34 > readonly dark: string;
35 > readonly light: string;
36 > };
37 > readonly codicon?: string;
38 > readonly manifest?: IGalleryMcpServerConfiguration;
39 > readonly source: InstallSource;
40 > }
41 >
42 > export interface IMcpServerInput {
43 > readonly description?: string;
44 > readonly isRequired?: boolean;
45 > readonly format?: 'string' | 'number' | 'boolean' | 'filepath';
46 > readonly value?: string;
47 > readonly isSecret?: boolean;
48 > readonly default?: string;
49 > readonly choices?: readonly string[];
50 > }
51 >
52 > export interface IMcpServerVariableInput extends IMcpServerInput {
53 > readonly variables?: Record<string, IMcpServerInput>;
54 > }
55 >
56 > export interface IMcpServerPositionalArgument extends IMcpServerVariableInput {
57 > readonly type: 'positional';
58 > readonly valueHint?: string;
59 > readonly isRepeated?: boolean;
60 > }
61 >
62 > export interface IMcpServerNamedArgument extends IMcpServerVariableInput {
63 > readonly type: 'named';
64 > readonly name: string;
65 > readonly isRepeated?: boolean;
66 > }
67 >
68 > export interface IMcpServerKeyValueInput extends IMcpServerVariableInput {
69 > readonly name: string;
70 > readonly value?: string;
71 > }
72 >
73 > export type IMcpServerArgument = IMcpServerPositionalArgument | IMcpServerNamedArgument;
74 >
75 > export const enum RegistryType {
76 > NODE = 'npm',
77 > PYTHON = 'pypi',
78 > DOCKER = 'oci',
79 > NUGET = 'nuget',
80 > MCPB = 'mcpb',
81 > REMOTE = 'remote'
82 > }
83 >
84 > export const enum TransportType {
85 > STDIO = 'stdio',
86 > STREAMABLE_HTTP = 'streamable-http',
87 > SSE = 'sse'
88 > }
89 >
90 > export interface StdioTransport {
91 > readonly type: TransportType.STDIO;
92 > }
93 >
94 > export interface StreamableHttpTransport {
95 > readonly type: TransportType.STREAMABLE_HTTP;
96 > readonly url: string;
97 > readonly headers?: ReadonlyArray<IMcpServerKeyValueInput>;
98 > }
99 >
100 > export interface SseTransport {
101 > readonly type: TransportType.SSE;
102 > readonly url: string;
103 > readonly headers?: ReadonlyArray<IMcpServerKeyValueInput>;
104 > }
105 >
106 > export type Transport = StdioTransport | StreamableHttpTransport | SseTransport;
107 >
108 > export interface IMcpServerPackage {
109 > readonly registryType: RegistryType;
110 > readonly identifier: string;
111 > readonly transport: Transport;
112 > readonly version?: string;
113 > readonly registryBaseUrl?: string;
114 > readonly fileSha256?: string;
115 > readonly packageArguments?: readonly IMcpServerArgument[];
116 > readonly runtimeHint?: string;
117 > readonly runtimeArguments?: readonly IMcpServerArgument[];
118 > readonly environmentVariables?: ReadonlyArray<IMcpServerKeyValueInput>;
119 > }
120 >
121 > export interface IGalleryMcpServerConfiguration {
122 > readonly packages?: readonly IMcpServerPackage[];
123 > readonly remotes?: ReadonlyArray<SseTransport | StreamableHttpTransport>;
124 > }
125 >
126 > export const enum GalleryMcpServerStatus {
127 > Active = 'active',
128 > Deprecated = 'deprecated'
129 > }
130 >
131 > export interface IGalleryMcpServer {
132 > readonly name: string;
133 > readonly displayName: string;
134 > readonly description: string;
135 > readonly version: string;
136 > readonly isLatest: boolean;
137 > readonly status: GalleryMcpServerStatus;
138 > readonly id?: string;
139 > readonly galleryUrl?: string;
140 > readonly webUrl?: string;
141 > readonly codicon?: string;
142 > readonly icon?: {
143 > readonly dark: string;
144 > readonly light: string;
145 > };
146 > readonly lastUpdated?: number;
147 > readonly publishDate?: number;
148 > readonly repositoryUrl?: string;
149 > readonly configuration: IGalleryMcpServerConfiguration;
150 > readonly readmeUrl?: string;
151 > readonly readme?: string;
152 > readonly publisher: string;
153 > readonly publisherDisplayName?: string;
154 > readonly publisherUrl?: string;
155 > readonly publisherDomain?: { link: string; verified: boolean };
156 > readonly ratingCount?: number;
157 > readonly topics?: readonly string[];
158 > readonly license?: string;
159 > readonly starsCount?: number;
160 > }
161 >
162 > export interface IQueryOptions {
163 > text?: string;
164 > sortBy?: SortBy;
165 > sortOrder?: SortOrder;
166 > }
167 >
168 > export const IMcpGalleryService = createDecorator<IMcpGalleryService>('IMcpGalleryService');
169 > export interface IMcpGalleryService {
170 > readonly _serviceBrand: undefined;
171 > isEnabled(): boolean;
172 > query(options?: IQueryOptions, token?: CancellationToken): Promise<IIterativePager<IGalleryMcpServer>>;
173 > getMcpServersFromGallery(infos: { name: string; id?: string }[]): Promise<IGalleryMcpServer[]>;
174 > getMcpServer(url: string): Promise<IGalleryMcpServer | undefined>;
175 > getReadme(extension: IGalleryMcpServer, token: CancellationToken): Promise<string>;
176 > }
177 >
178 > export interface InstallMcpServerEvent {
179 > readonly name: string;
180 > readonly mcpResource: URI;
181 > readonly source?: IGalleryMcpServer;
182 > }
183 >
184 > export interface InstallMcpServerResult {
185 > readonly name: string;
186 > readonly mcpResource: URI;
187 > readonly source?: IGalleryMcpServer;
188 > readonly local?: ILocalMcpServer;
189 > readonly error?: Error;
190 > }
191 >
192 > export interface UninstallMcpServerEvent {
193 > readonly name: string;
194 > readonly mcpResource: URI;
195 > }
196 >
197 > export interface DidUninstallMcpServerEvent {
198 > readonly name: string;
199 > readonly mcpResource: URI;
200 > readonly error?: string;
201 > }
202 >
203 > export type InstallOptions = {
204 > packageType?: RegistryType;
205 > mcpResource?: URI;
206 > };
207 >
208 > export type UninstallOptions = {
209 > mcpResource?: URI;
210 > };
211 >
212 > export interface IInstallableMcpServer {
213 > readonly name: string;
214 > readonly config: IMcpServerConfiguration;
215 > readonly inputs?: IMcpServerVariable[];
216 > }
217 >
218 > export type McpServerConfiguration = Omit<IInstallableMcpServer, 'name'>;
219 > export interface McpServerConfigurationParseResult {
220 > readonly mcpServerConfiguration: McpServerConfiguration;
221 > readonly notices: string[];
222 > }
223 >
224 > export const IMcpManagementService = createDecorator<IMcpManagementService>('IMcpManagementService');
225 > export interface IMcpManagementService {
226 > readonly _serviceBrand: undefined;
227 > readonly onInstallMcpServer: Event<InstallMcpServerEvent>;
228 > readonly onDidInstallMcpServers: Event<readonly InstallMcpServerResult[]>;
229 > readonly onDidUpdateMcpServers: Event<readonly InstallMcpServerResult[]>;
230 > readonly onUninstallMcpServer: Event<UninstallMcpServerEvent>;
231 > readonly onDidUninstallMcpServer: Event<DidUninstallMcpServerEvent>;
232 > getInstalled(mcpResource?: URI): Promise<ILocalMcpServer[]>;
233 > canInstall(server: IGalleryMcpServer | IInstallableMcpServer): true | IMarkdownString;
234 > install(server: IInstallableMcpServer, options?: InstallOptions): Promise<ILocalMcpServer>;
235 > installFromGallery(server: IGalleryMcpServer, options?: InstallOptions): Promise<ILocalMcpServer>;
236 > updateMetadata(local: ILocalMcpServer, server: IGalleryMcpServer, profileLocation?: URI): Promise<ILocalMcpServer>;
237 > uninstall(server: ILocalMcpServer, options?: UninstallOptions): Promise<void>;
238 >
239 > getMcpServerConfigurationFromManifest(manifest: IGalleryMcpServerConfiguration, packageType: RegistryType): McpServerConfigurationParseResult;
240 > }
241 >
242 > export const IAllowedMcpServersService = createDecorator<IAllowedMcpServersService>('IAllowedMcpServersService');
243 > export interface IAllowedMcpServersService {
244 > readonly _serviceBrand: undefined;
245 >
246 > readonly onDidChangeAllowedMcpServers: Event<void>;
247 > isAllowed(mcpServer: IGalleryMcpServer | ILocalMcpServer | IInstallableMcpServer): true | IMarkdownString;
248 >
249 > /**
250 > * Checks whether an MCP server identified by name / remote URL / local command is permitted by
251 > * the `chat.mcp.allowedServers` allowlist (in addition to the `chat.mcp.access` gate). Used by
252 > * the runtime enforcement path, which does not have a gallery/local/installable representation.
253 > */
254 > isServerAllowed(identity: IMcpServerIdentity): true | IMarkdownString;
255 > }
256 >
257 > export const mcpAccessConfig = 'chat.mcp.access';
258 > export const mcpAllowedServersConfig = 'chat.mcp.allowedServers';
259 > export const mcpDeniedServersConfig = 'chat.mcp.deniedServers';
260 > export const mcpGalleryServiceUrlConfig = 'chat.mcp.gallery.serviceUrl';
261 > export const mcpGalleryServiceEnablementConfig = 'chat.mcp.gallery.enabled';
262 > export const mcpAutoStartConfig = 'chat.mcp.autostart';
263 > export const mcpAppsEnabledConfig = 'chat.mcp.apps.enabled';
264 >
265 > export interface IMcpGalleryConfig {
266 > readonly serviceUrl?: string;
267 > readonly enabled?: boolean;
268 > readonly version?: string;
269 > }
270 >
271 > export const enum McpAutoStartValue {
272 > Never = 'never',
273 > OnlyNew = 'onlyNew',
274 > NewAndOutdated = 'newAndOutdated',
275 > }
276 >
277 > export const enum McpAccessValue {
278 > None = 'none',
279 > Registry = 'registry',
280 > All = 'all',
281 > }
src/vs/platform/agentHost/common/state/protocol/channels-changeset/state.ts 277 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- state.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > // allow-any-unicode-comment-file
7 > // DO NOT EDIT -- auto-generated by scripts/sync-agent-host-protocol.ts
8 >
9 > import type { StringOrMarkdown, FileEdit, ErrorInfo } from '../common/state.js';
10 >
11 > // ─── Changesets ──────────────────────────────────────────────────────────────
12 >
13 > /**
14 > * Catalogue entry describing one changeset the server can produce for a
15 > * session.
16 > *
17 > * Catalogue entries are intentionally lightweight — just enough to render a
18 > * chip or list row without subscribing. Full per-changeset detail
19 > * ({@link ChangesetState}) lives on the subscribable URI obtained by
20 > * expanding {@link uriTemplate}.
21 > *
22 > * @category Changesets
23 > */
24 > export interface Changeset {
25 > /** Human-readable label, e.g. `"Uncommitted Changes"`. */
26 > label: string;
27 > /**
28 > * RFC 6570 URI template. Clients parse the variables directly out of the
29 > * template using the standard `{name}` syntax — they are not redeclared
30 > * here.
31 > *
32 > * Only the following template shapes are defined by this protocol; any
33 > * other variable name MUST be ignored by clients (there is no
34 > * protocol-defined way to obtain values for unknown variables):
35 > *
36 > * | Variables in template | Meaning |
37 > * | ------------------------------------------- | ------------------------------------------------------------------------------------ |
38 > * | _(none)_ | A static, session-wide changeset. The template is itself a subscribable URI. |
39 > * | `{turnId}` | Per-turn slice. Expand with a `Turn.id` from the session. |
40 > * | `{originalTurnId}` and `{modifiedTurnId}` | Diff between two turns. Both variables MUST be present. |
41 > *
42 > * Future protocol versions MAY add new well-known variables.
43 > */
44 > uriTemplate: string;
45 > /** Optional longer description. */
46 > description?: string;
47 > /**
48 > * Advisory hint describing what kind of changeset this is, so clients can
49 > * group, sort, or render an appropriate icon without parsing
50 > * {@link uriTemplate}. Recognized values include:
51 > *
52 > * - `'session'`: a static, session-wide changeset covering all changes the
53 > * agent has produced in this session.
54 > * - `'branch'`: changes relative to a base branch (e.g. a feature branch
55 > * diffed against `main`).
56 > * - `'uncommitted'`: the workspace's current uncommitted changes.
57 > * - `'turn'`: changes produced by a single turn. Typically paired with a
58 > * `{turnId}` variable in {@link uriTemplate}.
59 > * - `'compare-turns'`: a diff between two turns. Typically paired with
60 > * `{originalTurnId}` and `{modifiedTurnId}` variables in
61 > * {@link uriTemplate}.
62 > *
63 > * Implementations MAY provide additional values; clients SHOULD fall back
64 > * to a reasonable default when an unknown value is encountered.
65 > */
66 > changeKind: string;
67 > /**
68 > * Optional capability declarations for this changeset. Absent (or an empty
69 > * object) means the changeset advertises no optional capabilities.
70 > *
71 > * Because the catalogue entry is delivered up-front on
72 > * {@link ChangesetState | the session's changeset list}, clients can decide
73 > * whether to surface capability-gated UI (such as review checkboxes) without
74 > * first subscribing to the changeset URI. Mirrors the presence-flag
75 > * convention of `ClientCapabilities`.
76 > */
77 > capabilities?: ChangesetCapabilities;
78 > }
79 >
80 > /**
81 > * Optional capabilities a changeset advertises on its catalogue
82 > * {@link Changeset} entry.
83 > *
84 > * Each field is a presence flag: an empty object `{}` means "supported",
85 > * absence means "not supported". Sub-fields on individual capabilities are
86 > * reserved for future per-capability options.
87 > *
88 > * @category Changesets
89 > */
90 > export interface ChangesetCapabilities {
91 > /**
92 > * The changeset supports the per-file **review** workflow. When declared,
93 > * clients MAY surface a GitHub-style "Viewed" toggle per file and dispatch
94 > * {@link ChangesetFilesReviewChangedAction | `changeset/filesReviewChanged`} to
95 > * set each file's {@link ChangesetFile.reviewed} flag. Clients that omit
96 > * handling MUST treat the changeset as non-reviewable.
97 > */
98 > review?: Record<string, never>;
99 > }
100 >
101 > /**
102 > * Computation lifecycle of a {@link ChangesetState}.
103 > *
104 > * @category Changesets
105 > */
106 > export const enum ChangesetStatus {
107 > /** The server is still computing the contents of this changeset. */
108 > Computing = 'computing',
109 > /** The changeset has been fully computed and is up-to-date. */
110 > Ready = 'ready',
111 > /**
112 > * Computation failed. The cause is described by
113 > * {@link ChangesetState.error}.
114 > */
115 > Error = 'error',
116 > }
117 >
118 > /**
119 > * Full state for a single changeset, returned when a client subscribes to
120 > * an expanded changeset URI.
121 > *
122 > * The client already knows the URI it subscribed to, so this state does
123 > * not redundantly carry it (or the catalogue's `id`, `label`, etc.).
124 > * Aggregate counts (`additions`, `deletions`, `files`) are likewise
125 > * omitted: clients trivially compute them from `files[].edit.diff`.
126 > *
127 > * @category Changesets
128 > */
129 > export interface ChangesetState {
130 > /** Computation lifecycle. */
131 > status: ChangesetStatus;
132 > /** Present iff `status === ChangesetStatus.Error`. */
133 > error?: ErrorInfo;
134 > /** Files in this changeset, keyed by {@link ChangesetFile.id}. */
135 > files: ChangesetFile[];
136 > /**
137 > * Operations the client may invoke against this changeset. Omit when no
138 > * operations are available.
139 > */
140 > operations?: ChangesetOperation[];
141 > }
142 >
143 > /**
144 > * One file entry within a {@link ChangesetState}.
145 > *
146 > * @category Changesets
147 > */
148 > export interface ChangesetFile {
149 > /**
150 > * Stable identifier within the changeset. Typically `after.uri`
151 > * (or `before.uri` for deletions).
152 > */
153 > id: string;
154 > /**
155 > * Reuses the existing {@link FileEdit} shape. Clients derive line
156 > * additions, deletions, and rename/create/delete semantics from this.
157 > */
158 > edit: FileEdit;
159 > /**
160 > * Whether a reviewer has marked this file as reviewed (the GitHub-style
161 > * "Viewed" checkbox). Absent is equivalent to `false` — clients MUST treat
162 > * a missing value as not-yet-reviewed.
163 > *
164 > * Requires the changeset to advertise {@link ChangesetCapabilities.review}.
165 > * Clients toggle it by dispatching
166 > * {@link ChangesetFilesReviewChangedAction | `changeset/filesReviewChanged`};
167 > * the server MAY also originate it (e.g. an agent self-reviewing its own
168 > * output).
169 > *
170 > * There is no content version in the protocol, so review is **not** reset
171 > * automatically when a file's contents change under a stable id. The server,
172 > * which is the authority on what changed, resets review explicitly — either
173 > * by re-emitting the file (via {@link ChangesetFileSetAction} or
174 > * {@link ChangesetContentChangedAction}) without `reviewed: true`, or by
175 > * dispatching `changeset/filesReviewChanged` with `reviewed: false`.
176 > */
177 > reviewed?: boolean;
178 > /**
179 > * Server-defined opaque metadata, surfaced to operations and tooling
180 > * but not interpreted by the protocol.
181 > */
182 > _meta?: Record<string, unknown>;
183 > }
184 >
185 > /**
186 > * Execution lifecycle of a {@link ChangesetOperation}.
187 > *
188 > * An operation is invoked imperatively via `invokeChangesetOperation`, but
189 > * its progress and outcome are reflected back into changeset state so that
190 > * every subscriber observes a consistent view (e.g. a spinner on a "Create
191 > * Pull Request" button, or an inline error after a failed "revert").
192 > *
193 > * @category Changesets
194 > */
195 > export const enum ChangesetOperationStatus {
196 > /**
197 > * The operation is ready to be invoked. This is the default when
198 > * {@link ChangesetOperation.status} is omitted.
199 > */
200 > Idle = 'idle',
201 > /** An invocation of this operation is currently in flight. */
202 > Running = 'running',
203 > /**
204 > * The most recent invocation failed. The cause is described by
205 > * {@link ChangesetOperation.error}.
206 > */
207 > Error = 'error',
208 > /**
209 > * The operation is currently disabled and cannot be invoked.
210 > */
211 > Disabled = 'disabled',
212 > }
213 >
214 > /**
215 > * Where a {@link ChangesetOperation} can be invoked.
216 > *
217 > * @category Changesets
218 > */
219 > export const enum ChangesetOperationScope {
220 > /** Applies to the whole changeset. */
221 > Changeset = 'changeset',
222 > /** Applies to a single file within the changeset. */
223 > Resource = 'resource',
224 > /** Applies to a line range within a single file. */
225 > Range = 'range',
226 > }
227 >
228 > /**
229 > * A server-declared invokable verb the client can run against a
230 > * changeset, a file, or a range — `"stage"`, `"revert"`, `"create-pr"`,
231 > * and so on.
232 > *
233 > * The term "operation" is used deliberately to avoid colliding with the
234 > * protocol-level [Actions](/guide/actions) that mutate state.
235 > *
236 > * @category Changesets
237 > */
238 > export interface ChangesetOperation {
239 > /** Stable identifier, unique within this changeset. */
240 > id: string;
241 > /** Human-readable button/menu label. */
242 > label: string;
243 > /** Optional longer description shown on hover or in tooltips. */
244 > description?: string;
245 > /** Where this operation can be invoked. */
246 > scopes: ChangesetOperationScope[];
247 > /**
248 > * Optional confirmation prompt to show before invoking. When present,
249 > * the client MUST display this message to the user (typically in a
250 > * confirmation dialog) and only invoke the operation after the user
251 > * accepts. The presence of this field also signals that the operation
252 > * is destructive — clients SHOULD style the affirmative button
253 > * accordingly (e.g. with a warning colour).
254 > */
255 > confirmation?: StringOrMarkdown;
256 > /** Optional generic icon hint, e.g. `"check"`, `"trash"`. */
257 > icon?: string;
258 > /** Optional group identifier, used to group related operations together. */
259 > group?: string;
260 > /**
261 > * Current execution status. The server sets
262 > * {@link ChangesetOperationStatus.Running | Running} while an invocation
263 > * is in flight, {@link ChangesetOperationStatus.Error | Error} when the
264 > * most recent invocation failed, and
265 > * {@link ChangesetOperationStatus.Idle | Idle} otherwise.
266 > *
267 > * Clients SHOULD reflect this state in the UI — e.g. disabling the
268 > * control or showing a spinner while `Running`, and surfacing
269 > * {@link error} while `Error`.
270 > */
271 > status: ChangesetOperationStatus;
272 > /**
273 > * Cause of failure. Present iff
274 > * `status === ChangesetOperationStatus.Error`; otherwise omitted.
275 > */
276 > error?: ErrorInfo;
277 > }
src/vs/platform/request/common/request.ts 277 covered LOC · 15 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- request.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { streamToBuffer } from '../../../base/common/buffer.js';
7 > import { CancellationToken } from '../../../base/common/cancellation.js';
8 > import { getErrorMessage } from '../../../base/common/errors.js';
9 > import { Emitter, Event } from '../../../base/common/event.js';
10 > import { Disposable } from '../../../base/common/lifecycle.js';
11 > import { IHeaders, IRequestContext, IRequestOptions } from '../../../base/parts/request/common/request.js';
12 > import { localize } from '../../../nls.js';
13 > import { ConfigurationScope, Extensions, IConfigurationNode, IConfigurationRegistry } from '../../configuration/common/configurationRegistry.js';
14 > import { createDecorator } from '../../instantiation/common/instantiation.js';
15 > import { ILogService } from '../../log/common/log.js';
16 > import { Registry } from '../../registry/common/platform.js';
17 >
18 > export const IRequestService = createDecorator<IRequestService>('requestService');
19 >
20 > /**
21 > * Use as the {@link IRequestOptions.callSite} value to prevent
22 > * request telemetry from being emitted. This is needed for
23 > * callers such as the telemetry sender to avoid cyclical calls.
24 > */
25 > export const NO_FETCH_TELEMETRY = 'NO_FETCH_TELEMETRY';
26 >
27 > export interface IRequestCompleteEvent {
28 > readonly callSite: string;
29 > readonly latency: number;
30 > readonly statusCode: number | undefined;
31 > }
32 >
33 > export interface AuthInfo {
34 > isProxy: boolean;
35 > scheme: string;
36 > host: string;
37 > port: number;
38 > realm: string;
39 > attempt: number;
40 > }
41 >
42 > export interface Credentials {
43 > username: string;
44 > password: string;
45 > }
46 >
47 > export interface IRequestService {
48 > readonly _serviceBrand: undefined;
49 >
50 > /**
51 > * Fires when a request completes (successfully or with an error response).
52 > */
53 > readonly onDidCompleteRequest: Event<IRequestCompleteEvent>;
54 >
55 > request(options: IRequestOptions, token: CancellationToken): Promise<IRequestContext>;
56 >
57 > resolveProxy(url: string): Promise<string | undefined>;
58 > lookupAuthorization(authInfo: AuthInfo): Promise<Credentials | undefined>;
59 > lookupKerberosAuthorization(url: string): Promise<string | undefined>;
60 > loadCertificates(): Promise<string[]>;
61 > }
62 >
63 > class LoggableHeaders {
64 >
65 > private headers: IHeaders | undefined;
66 >
67 > constructor(private readonly original: IHeaders) { }
68 >
69 > toJSON(): any {
70 if (!this.headers) {
71 const headers = Object.create(null);
81 return this.headers;
82 }
83 > request.ts
84 > }
85 >
86 > export abstract class AbstractRequestService extends Disposable implements IRequestService {
87 >
88 > declare readonly _serviceBrand: undefined;
89 >
90 > private counter = 0;
91 >
92 > private readonly _onDidCompleteRequest = this._register(new Emitter<IRequestCompleteEvent>());
93 > readonly onDidCompleteRequest = this._onDidCompleteRequest.event;
94 >
95 > constructor(protected readonly logService: ILogService) {
96 super();
97 }
98 > request.ts
99 > protected async logAndRequest(options: IRequestOptions, request: () => Promise<IRequestContext>): Promise<IRequestContext> {
100 const prefix = `#${++this.counter}: ${options.url}`;
101 this.logService.trace(`${prefix} - begin`, options.type, new LoggableHeaders(options.headers ?? {}));
115 }
116 }
117 > request.ts
118 > abstract request(options: IRequestOptions, token: CancellationToken): Promise<IRequestContext>;
119 > abstract resolveProxy(url: string): Promise<string | undefined>;
120 > abstract lookupAuthorization(authInfo: AuthInfo): Promise<Credentials | undefined>;
121 > abstract lookupKerberosAuthorization(url: string): Promise<string | undefined>;
122 > abstract loadCertificates(): Promise<string[]>;
123 > }
124 >
125 > export function isSuccess(context: IRequestContext): boolean {
126 return (context.res.statusCode && context.res.statusCode >= 200 && context.res.statusCode < 300) || context.res.statusCode === 1223;
127 }
128 > request.ts
129 > export function isClientError(context: IRequestContext): boolean {
130 return !!context.res.statusCode && context.res.statusCode >= 400 && context.res.statusCode < 500;
131 }
132 > request.ts
133 > export function isServerError(context: IRequestContext): boolean {
134 return !!context.res.statusCode && context.res.statusCode >= 500 && context.res.statusCode < 600;
135 }
136 > request.ts
137 > /**
138 > * Reads a header value from an {@link IHeaders} map, tolerating array-shaped
139 > * values and case-insensitive lookups.
140 > */
141 > export function readHeader(headers: IHeaders | undefined, name: string): string | undefined {
142 if (!headers) {
143 return undefined;
149 return value;
150 }
151 > request.ts
152 > /**
153 > * Parses the `Retry-After` header as a number of seconds. Returns `undefined`
154 > * if absent or not a finite positive number. The HTTP-date form is not parsed.
155 > */
156 > export function retryAfterFromHeaders(headers: IHeaders | undefined): number | undefined {
157 const value = readHeader(headers, 'retry-after');
158 if (!value) {
162 return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;
163 }
164 > request.ts
165 > export function hasNoContent(context: IRequestContext): boolean {
166 return context.res.statusCode === 204;
167 }
168 > request.ts
169 export async function asText(context: IRequestContext): Promise<string | null> {
170 if (hasNoContent(context)) {
174 return buffer.toString();
175 }
176 > request.ts
177 export async function asTextOrError(context: IRequestContext): Promise<string | null> {
178 if (!isSuccess(context)) {
181 return asText(context);
182 }
183 > request.ts
184 export async function asJson<T = {}>(context: IRequestContext): Promise<T | null> {
185 if (!isSuccess(context)) {
198 }
199 }
200 > request.ts
201 > export function updateProxyConfigurationsScope(useHostProxy: boolean, useHostProxyDefault: boolean): void {
202 registerProxyConfigurations(useHostProxy, useHostProxyDefault);
203 }
204 > request.ts
205 > export const USER_LOCAL_AND_REMOTE_SETTINGS = [
206 > 'http.proxy',
207 > 'http.proxyStrictSSL',
208 > 'http.proxyKerberosServicePrincipal',
209 > 'http.noProxy',
210 > 'http.proxyAuthorization',
211 > 'http.proxySupport',
212 > 'http.systemCertificates',
213 > 'http.systemCertificatesNode',
214 > 'http.experimental.systemCertificatesV2',
215 > 'http.fetchAdditionalSupport',
216 > 'http.experimental.networkInterfaceCheckInterval',
217 > ];
218 >
219 > export const systemCertificatesNodeDefault = false;
220 >
221 > let proxyConfiguration: IConfigurationNode[] = [];
222 > let previousUseHostProxy: boolean | undefined = undefined;
223 > let previousUseHostProxyDefault: boolean | undefined = undefined;
224 > function registerProxyConfigurations(useHostProxy = true, useHostProxyDefault = true): void {
225 > if (previousUseHostProxy === useHostProxy && previousUseHostProxyDefault === useHostProxyDefault) {
226 return;
227 }
228 > request.ts
229 > previousUseHostProxy = useHostProxy;
230 > previousUseHostProxyDefault = useHostProxyDefault;
231 >
232 > const configurationRegistry = Registry.as<IConfigurationRegistry>(Extensions.Configuration);
233 > const oldProxyConfiguration = proxyConfiguration;
234 > proxyConfiguration = [
235 > {
236 > id: 'http',
237 > order: 15,
238 > title: localize('httpConfigurationTitle', "HTTP"),
239 > type: 'object',
240 > scope: ConfigurationScope.MACHINE,
241 > properties: {
242 > 'http.useLocalProxyConfiguration': {
243 > type: 'boolean',
244 > default: useHostProxyDefault,
245 > markdownDescription: localize('useLocalProxy', "Controls whether in the remote extension host the local proxy configuration should be used. This setting only applies as a remote setting during [remote development](https://aka.ms/vscode-remote)."),
246 > restricted: true
247 > },
248 > }
249 > },
250 > {
251 > id: 'http',
252 > order: 15,
253 > title: localize('httpConfigurationTitle', "HTTP"),
254 > type: 'object',
255 > scope: ConfigurationScope.APPLICATION,
256 > properties: {
257 > 'http.electronFetch': {
258 > type: 'boolean',
259 > default: false,
260 > description: localize('electronFetch', "Controls whether use of Electron's fetch implementation instead of Node.js' should be enabled. All local extensions will get Electron's fetch implementation for the global fetch API."),
261 > restricted: true
262 > },
263 > }
264 > },
265 > {
266 > id: 'http',
267 > order: 15,
268 > title: localize('httpConfigurationTitle', "HTTP"),
269 > type: 'object',
270 > scope: useHostProxy ? ConfigurationScope.APPLICATION : ConfigurationScope.MACHINE,
271 > properties: {
272 > 'http.proxy': {
273 > type: 'string',
274 > pattern: '^(https?|socks|socks4a?|socks5h?)://([^:]*(:[^@]*)?@)?([^:]+|\\[[:0-9a-fA-F]+\\])(:\\d+)?/?$|^$',
275 > markdownDescription: localize('proxy', "The proxy setting to use. If not set, will be inherited from the `http_proxy` and `https_proxy` environment variables. When during [remote development](https://aka.ms/vscode-remote) the {0} setting is disabled this setting can be configured in the local and the remote settings separately.", '`#http.useLocalProxyConfiguration#`'),
276 > restricted: true
277 > },
278 > 'http.proxyStrictSSL': {
279 > type: 'boolean',
280 > default: true,
281 > markdownDescription: localize('strictSSL', "Controls whether the proxy server certificate should be verified against the list of supplied CAs. When during [remote development](https://aka.ms/vscode-remote) the {0} setting is disabled this setting can be configured in the local and the remote settings separately.", '`#http.useLocalProxyConfiguration#`'),
282 > restricted: true
283 > },
284 > 'http.proxyKerberosServicePrincipal': {
285 > type: 'string',
286 > markdownDescription: localize('proxyKerberosServicePrincipal', "Overrides the principal service name for Kerberos authentication with the HTTP proxy. A default based on the proxy hostname is used when this is not set. When during [remote development](https://aka.ms/vscode-remote) the {0} setting is disabled this setting can be configured in the local and the remote settings separately.", '`#http.useLocalProxyConfiguration#`'),
287 > restricted: true
288 > },
289 > 'http.noProxy': {
290 > type: 'array',
291 > items: { type: 'string' },
292 > markdownDescription: localize('noProxy', "Specifies domain names for which proxy settings should be ignored for HTTP/HTTPS requests. When during [remote development](https://aka.ms/vscode-remote) the {0} setting is disabled this setting can be configured in the local and the remote settings separately.", '`#http.useLocalProxyConfiguration#`'),
293 > restricted: true
294 > },
295 > 'http.proxyAuthorization': {
296 > type: ['null', 'string'],
297 > default: null,
298 > markdownDescription: localize('proxyAuthorization', "The value to send as the `Proxy-Authorization` header for every network request. When during [remote development](https://aka.ms/vscode-remote) the {0} setting is disabled this setting can be configured in the local and the remote settings separately.", '`#http.useLocalProxyConfiguration#`'),
299 > restricted: true
300 > },
301 > 'http.proxySupport': {
302 > type: 'string',
303 > enum: ['off', 'on', 'fallback', 'override'],
304 > enumDescriptions: [
305 > localize('proxySupportOff', "Disable proxy support for extensions."),
306 > localize('proxySupportOn', "Enable proxy support for extensions."),
307 > localize('proxySupportFallback', "Enable proxy support for extensions, fall back to request options, when no proxy found."),
308 > localize('proxySupportOverride', "Enable proxy support for extensions, override request options."),
309 > ],
310 > default: 'override',
311 > markdownDescription: localize('proxySupport', "Use the proxy support for extensions. When during [remote development](https://aka.ms/vscode-remote) the {0} setting is disabled this setting can be configured in the local and the remote settings separately.", '`#http.useLocalProxyConfiguration#`'),
312 > restricted: true
313 > },
314 > 'http.systemCertificates': {
315 > type: 'boolean',
316 > default: true,
317 > markdownDescription: localize('systemCertificates', "Controls whether CA certificates should be loaded from the OS. On Windows and macOS, a reload of the window is required after turning this off. When during [remote development](https://aka.ms/vscode-remote) the {0} setting is disabled this setting can be configured in the local and the remote settings separately.", '`#http.useLocalProxyConfiguration#`'),
318 > restricted: true
319 > },
320 > 'http.systemCertificatesNode': {
321 > type: 'boolean',
322 > tags: ['experimental'],
323 > default: systemCertificatesNodeDefault,
324 > markdownDescription: localize('systemCertificatesNode', "Controls whether system certificates should be loaded using Node.js built-in support. Reload the window after changing this setting. When during [remote development](https://aka.ms/vscode-remote) the {0} setting is disabled this setting can be configured in the local and the remote settings separately.", '`#http.useLocalProxyConfiguration#`'),
325 > restricted: true,
326 > experiment: {
327 > mode: 'auto'
328 > }
329 > },
330 > 'http.experimental.systemCertificatesV2': {
331 > type: 'boolean',
332 > tags: ['experimental'],
333 > default: false,
334 > markdownDescription: localize('systemCertificatesV2', "Controls whether experimental loading of CA certificates from the OS should be enabled. This uses a more general approach than the default implementation. When during [remote development](https://aka.ms/vscode-remote) the {0} setting is disabled this setting can be configured in the local and the remote settings separately.", '`#http.useLocalProxyConfiguration#`'),
335 > restricted: true
336 > },
337 > 'http.fetchAdditionalSupport': {
338 > type: 'boolean',
339 > default: true,
340 > markdownDescription: localize('fetchAdditionalSupport', "Controls whether Node.js' fetch implementation should be extended with additional support. Currently proxy support ({1}) and system certificates ({2}) are added when the corresponding settings are enabled. When during [remote development](https://aka.ms/vscode-remote) the {0} setting is disabled this setting can be configured in the local and the remote settings separately.", '`#http.useLocalProxyConfiguration#`', '`#http.proxySupport#`', '`#http.systemCertificates#`'),
341 > restricted: true
342 > },
343 > 'http.webSocketAdditionalSupport': {
344 > type: 'boolean',
345 > default: true,
346 > markdownDescription: localize('webSocketAdditionalSupport', "Controls whether the built-in WebSocket implementation should be extended with additional support. Currently proxy support ({1}) and system certificates ({2}) are added when the corresponding settings are enabled. When during [remote development](https://aka.ms/vscode-remote) the {0} setting is disabled this setting can be configured in the local and the remote settings separately.", '`#http.useLocalProxyConfiguration#`', '`#http.proxySupport#`', '`#http.systemCertificates#`'),
347 > restricted: true
348 > },
349 > 'http.experimental.networkInterfaceCheckInterval': {
350 > type: 'number',
351 > default: 300,
352 > minimum: -1,
353 > tags: ['experimental'],
354 > markdownDescription: localize('networkInterfaceCheckInterval', "Controls the interval in seconds for checking network interface changes to invalidate the proxy cache. Set to -1 to disable. When during [remote development](https://aka.ms/vscode-remote) the {0} setting is disabled this setting can be configured in the local and the remote settings separately.", '`#http.useLocalProxyConfiguration#`'),
355 > restricted: true,
356 > experiment: {
357 > mode: 'auto'
358 > }
359 > }
360 > }
361 > }
362 > ];
363 > configurationRegistry.updateConfigurations({ add: proxyConfiguration, remove: oldProxyConfiguration });
364 > }
365 >
366 > registerProxyConfigurations();
src/vs/platform/configuration/common/configurationModels.ts 271 covered LOC · 92 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- configurationModels.ts
2 > * Copyright (c) Microsoft 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 { IStringDictionary } from '../../../base/common/collections.js';
8 > import { Emitter, Event } from '../../../base/common/event.js';
9 > import * as json from '../../../base/common/json.js';
10 > import { Disposable } from '../../../base/common/lifecycle.js';
11 > import { getOrSet, ResourceMap } from '../../../base/common/map.js';
12 > import * as objects from '../../../base/common/objects.js';
13 > import { IExtUri } from '../../../base/common/resources.js';
14 > import * as types from '../../../base/common/types.js';
15 > import { URI, UriComponents } from '../../../base/common/uri.js';
16 > import { addToValueTree, ConfigurationTarget, getConfigurationValue, IConfigurationChange, IConfigurationChangeEvent, IConfigurationCompareResult, IConfigurationData, IConfigurationModel, IConfigurationOverrides, IConfigurationUpdateOverrides, IConfigurationValue, IInspectValue, IOverrides, removeFromValueTree, toValuesTree } from './configuration.js';
17 > import { ConfigurationScope, Extensions, IConfigurationPropertySchema, IConfigurationRegistry, overrideIdentifiersFromKey, OVERRIDE_PROPERTY_REGEX, IRegisteredConfigurationPropertySchema } from './configurationRegistry.js';
18 > import { FileOperation, IFileService } from '../../files/common/files.js';
19 > import { ILogService } from '../../log/common/log.js';
20 > import { Registry } from '../../registry/common/platform.js';
21 > import { Workspace } from '../../workspace/common/workspace.js';
22 >
23 function freeze<T>(data: T): T {
24 return Object.isFrozen(data) ? data : objects.deepFreeze(data);
25 }
27 > type InspectValue<V> = IInspectValue<V> & { merged?: V };
28 >
29 > export class ConfigurationModel implements IConfigurationModel {
30 >
31 > static createEmptyModel(logService: ILogService): ConfigurationModel {
32 > return new ConfigurationModel({}, [], [], undefined, logService);
33 > }
34 >
35 > private readonly overrideConfigurations = new Map<string, ConfigurationModel>();
36 >
37 > constructor(
38 private readonly _contents: IStringDictionary<unknown>,
39 private readonly _keys: string[],
43 ) {
44 }
46 > private _rawConfiguration: ConfigurationModel | undefined;
47 > get rawConfiguration(): ConfigurationModel {
48 if (!this._rawConfiguration) {
49 if (this._raw) {
64 return this._rawConfiguration;
65 }
67 > get contents(): IStringDictionary<unknown> {
68 return this._contents;
69 }
71 > get overrides(): IOverrides[] {
72 return this._overrides;
73 }
75 > get keys(): string[] {
76 return this._keys;
77 }
79 > get raw(): IStringDictionary<unknown> | IStringDictionary<unknown>[] | undefined {
80 if (!this._raw) {
81 return undefined;
86 return this._raw as IStringDictionary<unknown> | IStringDictionary<unknown>[];
87 }
89 > isEmpty(): boolean {
90 return this._keys.length === 0 && Object.keys(this._contents).length === 0 && this._overrides.length === 0;
91 }
93 > getValue<V>(section: string | undefined): V | undefined {
94 return section ? getConfigurationValue<V>(this.contents, section) : this.contents as V;
95 }
97 > inspect<V>(section: string | undefined, overrideIdentifier?: string | null): InspectValue<V> {
98 const that = this;
99 return {
119 };
120 }
122 > getOverrideValue<V>(section: string | undefined, overrideIdentifier: string): V | undefined {
123 const overrideContents = this.getContentsForOverrideIdentifer(overrideIdentifier);
124 return overrideContents
126 : undefined;
127 }
129 > getKeysForOverrideIdentifier(identifier: string): string[] {
130 const keys: string[] = [];
131 for (const override of this.overrides) {
136 return arrays.distinct(keys);
137 }
139 > getAllOverrideIdentifiers(): string[] {
140 const result: string[] = [];
141 for (const override of this.overrides) {
144 return arrays.distinct(result);
145 }
147 > override(identifier: string): ConfigurationModel {
148 let overrideConfigurationModel = this.overrideConfigurations.get(identifier);
149 if (!overrideConfigurationModel) {
153 return overrideConfigurationModel;
154 }
156 > merge(...others: ConfigurationModel[]): ConfigurationModel {
157 const contents = objects.deepClone(this.contents);
158 const overrides = objects.deepClone(this.overrides);
185 return new ConfigurationModel(contents, keys, overrides, !raws.length || raws.every(raw => raw instanceof ConfigurationModel) ? undefined : raws, this.logService);
186 }
188 > private createOverrideConfigurationModel(identifier: string): ConfigurationModel {
189 const overrideContents = this.getContentsForOverrideIdentifer(identifier);
190
216 return new ConfigurationModel(contents, this.keys, this.overrides, undefined, this.logService);
217 }
219 > private mergeContents(source: IStringDictionary<unknown>, target: IStringDictionary<unknown>): void {
220 for (const key of Object.keys(target)) {
221 if (key in source) {
228 }
229 }
231 > private getContentsForOverrideIdentifer(identifier: string): IStringDictionary<unknown> | null {
232 let contentsForIdentifierOnly: IStringDictionary<unknown> | null = null;
233 let contents: IStringDictionary<unknown> | null = null;
252 return contents;
253 }
255 > toJSON(): IConfigurationModel {
256 return {
257 contents: this.contents,
260 };
261 }
263 > // Update methods
264 >
265 > public addValue(key: string, value: unknown): void {
266 this.updateValue(key, value, true);
267 }
269 > public setValue(key: string, value: unknown): void {
270 this.updateValue(key, value, false);
271 }
273 > public removeValue(key: string): void {
274 const index = this.keys.indexOf(key);
275 if (index === -1) {
282 }
283 }
285 > private updateValue(key: string, value: unknown, add: boolean): void {
286 addToValueTree(this.contents, key, value, e => this.logService.error(e));
287 add = add || this.keys.indexOf(key) === -1;
305 }
306 }
308 >
309 > export interface ConfigurationParseOptions {
310 > skipUnregistered?: boolean;
311 > scopes?: ConfigurationScope[];
312 > skipRestricted?: boolean;
313 > include?: string[];
314 > exclude?: string[];
315 > }
316 >
317 > export class ConfigurationModelParser {
318 >
319 > private _raw: IStringDictionary<unknown> | null = null;
320 > private _configurationModel: ConfigurationModel | null = null;
321 > private _restrictedConfigurations: string[] = [];
322 > private _parseErrors: json.ParseError[] = [];
323 >
324 > constructor(
325 protected readonly _name: string,
326 protected readonly logService: ILogService
327 ) { }
329 > get configurationModel(): ConfigurationModel {
330 return this._configurationModel || ConfigurationModel.createEmptyModel(this.logService);
331 }
333 > get restrictedConfigurations(): string[] {
334 return this._restrictedConfigurations;
335 }
337 > get errors(): json.ParseError[] {
338 return this._parseErrors;
339 }
341 > public parse(content: string | null | undefined, options?: ConfigurationParseOptions): void {
342 if (!types.isUndefinedOrNull(content)) {
343 const raw = this.doParseContent(content);
345 }
346 }
348 > public reparse(options: ConfigurationParseOptions): void {
349 if (this._raw) {
350 this.parseRaw(this._raw, options);
351 }
352 }
354 > public parseRaw(raw: IStringDictionary<unknown>, options?: ConfigurationParseOptions): void {
355 this._raw = raw;
356 const { contents, keys, overrides, restricted, hasExcludedProperties } = this.doParseRaw(raw, options);
358 this._restrictedConfigurations = restricted || [];
359 }
361 > private doParseContent(content: string): IStringDictionary<unknown> {
362 let raw: IStringDictionary<unknown> = {};
363 let currentProperty: string | null = null;
415 return raw;
416 }
418 > protected doParseRaw(raw: IStringDictionary<unknown>, options?: ConfigurationParseOptions): IConfigurationModel & { restricted?: string[]; hasExcludedProperties?: boolean } {
419 const registry = Registry.as<IConfigurationRegistry>(Extensions.Configuration);
420 const configurationProperties = registry.getConfigurationProperties();
427 return { contents, keys, overrides, restricted: filtered.restricted, hasExcludedProperties: filtered.hasExcludedProperties };
428 }
430 > private filter(properties: IStringDictionary<unknown>, configurationProperties: IStringDictionary<IRegisteredConfigurationPropertySchema>, excludedConfigurationProperties: IStringDictionary<IRegisteredConfigurationPropertySchema>, filterOverriddenProperties: boolean, options?: ConfigurationParseOptions): { raw: IStringDictionary<unknown>; restricted: string[]; hasExcludedProperties: boolean } {
431 let hasExcludedProperties = false;
432 if (!options?.scopes && !options?.skipRestricted && !options?.skipUnregistered && !options?.exclude?.length) {
455 return { raw, restricted, hasExcludedProperties };
456 }
458 > private shouldInclude(key: string, propertySchema: IConfigurationPropertySchema | undefined, excludedConfigurationProperties: IStringDictionary<IRegisteredConfigurationPropertySchema>, options: ConfigurationParseOptions): boolean {
459 if (options.exclude?.includes(key)) {
460 return false;
481 return options.scopes.includes(scope);
482 }
484 > private toOverrides(raw: IStringDictionary<unknown>, conflictReporter: (message: string) => void): IOverrides[] {
485 const overrides: IOverrides[] = [];
486 for (const key of Object.keys(raw)) {
500 return overrides;
501 }
503 > }
504 >
505 > export class UserSettings extends Disposable {
506 >
507 > private readonly parser: ConfigurationModelParser;
508 > protected readonly _onDidChange: Emitter<void> = this._register(new Emitter<void>());
509 > readonly onDidChange: Event<void> = this._onDidChange.event;
510 >
511 > constructor(
512 private readonly userSettingsResource: URI,
513 protected parseOptions: ConfigurationParseOptions,
526 )(() => this._onDidChange.fire()));
527 }
529 > async loadConfiguration(): Promise<ConfigurationModel> {
530 try {
531 const content = await this.fileService.readFile(this.userSettingsResource);
536 }
537 }
539 > reparse(parseOptions?: ConfigurationParseOptions): ConfigurationModel {
540 if (parseOptions) {
541 this.parseOptions = parseOptions;
544 return this.parser.configurationModel;
545 }
547 > getRestrictedSettings(): string[] {
548 return this.parser.restrictedConfigurations;
549 }
551 >
552 > class ConfigurationInspectValue<V> implements IConfigurationValue<V> {
553 >
554 > constructor(
555 private readonly key: string,
556 private readonly overrides: IConfigurationOverrides,
568 ) {
569 }
571 > get value(): V | undefined {
572 return freeze(this._value);
573 }
575 > private toInspectValue(inspectValue: IInspectValue<V> | undefined | null): IInspectValue<V> | undefined {
576 return inspectValue?.value !== undefined || inspectValue?.override !== undefined || inspectValue?.overrides !== undefined ? inspectValue : undefined;
577 }
579 > private _defaultInspectValue: InspectValue<V> | undefined;
580 > private get defaultInspectValue(): InspectValue<V> {
581 if (!this._defaultInspectValue) {
582 this._defaultInspectValue = this.defaultConfiguration.inspect<V>(this.key, this.overrides.overrideIdentifier);
584 return this._defaultInspectValue;
585 }
587 > get defaultValue(): V | undefined {
588 return this.defaultInspectValue.merged;
589 }
591 > get default(): IInspectValue<V> | undefined {
592 return this.toInspectValue(this.defaultInspectValue);
593 }
595 > private _policyInspectValue: InspectValue<V> | undefined | null;
596 > private get policyInspectValue(): InspectValue<V> | null {
597 if (this._policyInspectValue === undefined) {
598 this._policyInspectValue = this.policyConfiguration ? this.policyConfiguration.inspect<V>(this.key) : null;
600 return this._policyInspectValue;
601 }
603 > get policyValue(): V | undefined {
604 return this.policyInspectValue?.merged;
605 }
607 > get policy(): IInspectValue<V> | undefined {
608 return this.policyInspectValue?.value !== undefined ? { value: this.policyInspectValue.value } : undefined;
609 }
611 > private _applicationInspectValue: InspectValue<V> | undefined | null;
612 > private get applicationInspectValue(): InspectValue<V> | null {
613 if (this._applicationInspectValue === undefined) {
614 this._applicationInspectValue = this.applicationConfiguration ? this.applicationConfiguration.inspect<V>(this.key) : null;
616 return this._applicationInspectValue;
617 }
619 > get applicationValue(): V | undefined {
620 return this.applicationInspectValue?.merged;
621 }
623 > get application(): IInspectValue<V> | undefined {
624 return this.toInspectValue(this.applicationInspectValue);
625 }
627 > private _userInspectValue: InspectValue<V> | undefined;
628 > private get userInspectValue(): InspectValue<V> {
629 if (!this._userInspectValue) {
630 this._userInspectValue = this.userConfiguration.inspect<V>(this.key, this.overrides.overrideIdentifier);
632 return this._userInspectValue;
633 }
635 > get userValue(): V | undefined {
636 return this.userInspectValue.merged;
637 }
639 > get user(): IInspectValue<V> | undefined {
640 return this.toInspectValue(this.userInspectValue);
641 }
643 > private _userLocalInspectValue: InspectValue<V> | undefined;
644 > private get userLocalInspectValue(): InspectValue<V> {
645 if (!this._userLocalInspectValue) {
646 this._userLocalInspectValue = this.localUserConfiguration.inspect<V>(this.key, this.overrides.overrideIdentifier);
648 return this._userLocalInspectValue;
649 }
651 > get userLocalValue(): V | undefined {
652 return this.userLocalInspectValue.merged;
653 }
655 > get userLocal(): IInspectValue<V> | undefined {
656 return this.toInspectValue(this.userLocalInspectValue);
657 }
659 > private _userRemoteInspectValue: InspectValue<V> | undefined;
660 > private get userRemoteInspectValue(): InspectValue<V> {
661 if (!this._userRemoteInspectValue) {
662 this._userRemoteInspectValue = this.remoteUserConfiguration.inspect<V>(this.key, this.overrides.overrideIdentifier);
664 return this._userRemoteInspectValue;
665 }
667 > get userRemoteValue(): V | undefined {
668 return this.userRemoteInspectValue.merged;
669 }
671 > get userRemote(): IInspectValue<V> | undefined {
672 return this.toInspectValue(this.userRemoteInspectValue);
673 }
675 > private _workspaceInspectValue: InspectValue<V> | undefined | null;
676 > private get workspaceInspectValue(): InspectValue<V> | null {
677 if (this._workspaceInspectValue === undefined) {
678 this._workspaceInspectValue = this.workspaceConfiguration ? this.workspaceConfiguration.inspect<V>(this.key, this.overrides.overrideIdentifier) : null;
680 return this._workspaceInspectValue;
681 }
683 > get workspaceValue(): V | undefined {
684 return this.workspaceInspectValue?.merged;
685 }
687 > get workspace(): IInspectValue<V> | undefined {
688 return this.toInspectValue(this.workspaceInspectValue);
689 }
691 > private _workspaceFolderInspectValue: InspectValue<V> | undefined | null;
692 > private get workspaceFolderInspectValue(): InspectValue<V> | null {
693 if (this._workspaceFolderInspectValue === undefined) {
694 this._workspaceFolderInspectValue = this.folderConfigurationModel ? this.folderConfigurationModel.inspect<V>(this.key, this.overrides.overrideIdentifier) : null;
696 return this._workspaceFolderInspectValue;
697 }
699 > get workspaceFolderValue(): V | undefined {
700 return this.workspaceFolderInspectValue?.merged;
701 }
703 > get workspaceFolder(): IInspectValue<V> | undefined {
704 return this.toInspectValue(this.workspaceFolderInspectValue);
705 }
707 > private _memoryInspectValue: InspectValue<V> | undefined;
708 > private get memoryInspectValue(): InspectValue<V> {
709 if (this._memoryInspectValue === undefined) {
710 this._memoryInspectValue = this.memoryConfigurationModel.inspect<V>(this.key, this.overrides.overrideIdentifier);
712 return this._memoryInspectValue;
713 }
715 > get memoryValue(): V | undefined {
716 return this.memoryInspectValue.merged;
717 }
719 > get memory(): IInspectValue<V> | undefined {
720 return this.toInspectValue(this.memoryInspectValue);
721 }
723 > }
724 >
725 > export class Configuration {
726 >
727 > private _workspaceConsolidatedConfiguration: ConfigurationModel | null = null;
728 > private _foldersConsolidatedConfigurations = new ResourceMap<ConfigurationModel>();
729 >
730 > constructor(
731 private _defaultConfiguration: ConfigurationModel,
732 private _policyConfiguration: ConfigurationModel,
960
961 private _userConfiguration: ConfigurationModel | null = null;
962 > get userConfiguration(): ConfigurationModel { configurationModels.ts
963 if (!this._userConfiguration) {
964 if (this._remoteUserConfiguration.isEmpty()) {
971 return this._userConfiguration;
972 }
974 > get localUserConfiguration(): ConfigurationModel {
975 return this._localUserConfiguration;
976 }
978 > get remoteUserConfiguration(): ConfigurationModel {
979 return this._remoteUserConfiguration;
980 }
982 > get workspaceConfiguration(): ConfigurationModel {
983 return this._workspaceConfiguration;
984 }
986 > get folderConfigurations(): ResourceMap<ConfigurationModel> {
987 return this._folderConfigurations;
988 }
990 > private getConsolidatedConfigurationModel(section: string | undefined, overrides: IConfigurationOverrides, workspace: Workspace | undefined): ConfigurationModel {
991 let configurationModel = this.getConsolidatedConfigurationModelForResource(overrides, workspace);
992 if (overrides.overrideIdentifier) {
1002 return configurationModel;
1003 }
1005 > private getConsolidatedConfigurationModelForResource({ resource }: IConfigurationOverrides, workspace: Workspace | undefined): ConfigurationModel {
1006 let consolidateConfiguration = this.getWorkspaceConsolidatedConfiguration();
1007
1019 return consolidateConfiguration;
1020 }
1022 > private getWorkspaceConsolidatedConfiguration(): ConfigurationModel {
1023 if (!this._workspaceConsolidatedConfiguration) {
1024 this._workspaceConsolidatedConfiguration = this._defaultConfiguration.merge(this.applicationConfiguration, this.userConfiguration, this._workspaceConfiguration, this._memoryConfiguration);
1026 return this._workspaceConsolidatedConfiguration;
1027 }
1029 > private getFolderConsolidatedConfiguration(folder: URI): ConfigurationModel {
1030 let folderConsolidatedConfiguration = this._foldersConsolidatedConfigurations.get(folder);
1031 if (!folderConsolidatedConfiguration) {
1041 return folderConsolidatedConfiguration;
1042 }
1044 > private getFolderConfigurationModelForResource(resource: URI | null | undefined, workspace: Workspace | undefined): ConfigurationModel | undefined {
1045 if (workspace && resource) {
1046 const root = workspace.getFolder(resource);
1051 return undefined;
1052 }
1054 > toData(): IConfigurationData {
1055 return {
1056 defaults: {
1094 };
1095 }
1097 > allKeys(): string[] {
1098 const keys: Set<string> = new Set<string>();
1099 this._defaultConfiguration.keys.forEach(key => keys.add(key));
1103 return [...keys.values()];
1104 }
1106 > protected allOverrideIdentifiers(): string[] {
1107 const keys: Set<string> = new Set<string>();
1108 this._defaultConfiguration.getAllOverrideIdentifiers().forEach(key => keys.add(key));
1112 return [...keys.values()];
1113 }
1115 > protected getAllKeysForOverrideIdentifier(overrideIdentifier: string): string[] {
1116 const keys: Set<string> = new Set<string>();
1117 this._defaultConfiguration.getKeysForOverrideIdentifier(overrideIdentifier).forEach(key => keys.add(key));
1121 return [...keys.values()];
1122 }
1124 > static parse(data: IConfigurationData, logService: ILogService): Configuration {
1125 const defaultConfiguration = this.parseConfigurationModel(data.defaults, logService);
1126 const policyConfiguration = this.parseConfigurationModel(data.policy, logService);
1146 );
1147 }
1149 > private static parseConfigurationModel(model: IConfigurationModel, logService: ILogService): ConfigurationModel {
1150 return new ConfigurationModel(model.contents, model.keys, model.overrides, model.raw, logService);
1151 }
1153 > }
1154 >
1155 > export function mergeChanges(...changes: IConfigurationChange[]): IConfigurationChange {
1156 if (changes.length === 0) {
1157 return { keys: [], overrides: [] };
1173 return { keys: [...keysSet.values()], overrides };
1174 }
1176 > export class ConfigurationChangeEvent implements IConfigurationChangeEvent {
1177 >
1178 > private readonly _marker = '\n';
1179 > private readonly _markerCode1 = this._marker.charCodeAt(0);
1180 > private readonly _markerCode2 = '.'.charCodeAt(0);
1181 > private readonly _affectsConfigStr: string;
1182 >
1183 > readonly affectedKeys = new Set<string>();
1184 > source!: ConfigurationTarget;
1185 >
1186 > constructor(
1187 readonly change: IConfigurationChange,
1188 private readonly previous: { workspace?: Workspace; data: IConfigurationData } | undefined,
1206 }
1207 }
1209 > private _previousConfiguration: Configuration | undefined = undefined;
1210 > get previousConfiguration(): Configuration | undefined {
1211 if (!this._previousConfiguration && this.previous) {
1212 this._previousConfiguration = Configuration.parse(this.previous.data, this.logService);
1214 return this._previousConfiguration;
1215 }
1217 > affectsConfiguration(section: string, overrides?: IConfigurationOverrides): boolean {
1218 // we have one large string with all keys that have changed. we pad (marker) the section
1219 // and check that either find it padded or before a segment character
1240 return true;
1241 }
1243 >
1244 function compare(from: ConfigurationModel | undefined, to: ConfigurationModel | undefined): IConfigurationCompareResult {
1245 const { added, removed, updated } = compareConfigurationContents(to?.rawConfiguration, from?.rawConfiguration);
1274 return { added, removed, updated, overrides };
1275 }
1277 function compareConfigurationContents(to: { keys: string[]; contents: IStringDictionary<unknown> } | undefined, from: { keys: string[]; contents: IStringDictionary<unknown> } | undefined) {
1278 const added = to
src/vs/workbench/contrib/scm/common/scm.ts 266 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- scm.ts
2 > * Copyright (c) Microsoft 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 { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
8 > import { Event } from '../../../../base/common/event.js';
9 > import { IDisposable } from '../../../../base/common/lifecycle.js';
10 > import { Command } from '../../../../editor/common/languages.js';
11 > import { IAction } from '../../../../base/common/actions.js';
12 > import { IMenu } from '../../../../platform/actions/common/actions.js';
13 > import { ThemeIcon } from '../../../../base/common/themables.js';
14 > import { IMarkdownString } from '../../../../base/common/htmlContent.js';
15 > import { ResourceTree } from '../../../../base/common/resourceTree.js';
16 > import { ISCMHistoryProvider } from './history.js';
17 > import { ITextModel } from '../../../../editor/common/model.js';
18 > import { IObservable } from '../../../../base/common/observable.js';
19 > import { ISCMArtifact, ISCMArtifactGroup, ISCMArtifactProvider } from './artifact.js';
20 >
21 > export const VIEWLET_ID = 'workbench.view.scm';
22 > export const VIEW_PANE_ID = 'workbench.scm';
23 > export const REPOSITORIES_VIEW_PANE_ID = 'workbench.scm.repositories';
24 > export const HISTORY_VIEW_PANE_ID = 'workbench.scm.history';
25 >
26 > export const enum ViewMode {
27 > List = 'list',
28 > Tree = 'tree'
29 > }
30 >
31 > export interface IBaselineResourceProvider {
32 > getBaselineResource(resource: URI): Promise<URI>;
33 > }
34 >
35 > export const ISCMService = createDecorator<ISCMService>('scm');
36 >
37 > export interface ISCMResourceDecorations {
38 > icon?: URI | ThemeIcon;
39 > iconDark?: URI | ThemeIcon;
40 > tooltip?: string;
41 > strikeThrough?: boolean;
42 > faded?: boolean;
43 > }
44 >
45 > export interface ISCMResource {
46 > readonly resourceGroup: ISCMResourceGroup;
47 > readonly sourceUri: URI;
48 > readonly decorations: ISCMResourceDecorations;
49 > readonly contextValue: string | undefined;
50 > readonly command: Command | undefined;
51 > readonly multiDiffEditorOriginalUri: URI | undefined;
52 > readonly multiDiffEditorModifiedUri: URI | undefined;
53 > open(preserveFocus: boolean): Promise<void>;
54 > }
55 >
56 > export interface ISCMResourceGroup {
57 > readonly id: string;
58 > readonly provider: ISCMProvider;
59 >
60 > readonly resources: readonly ISCMResource[];
61 > readonly resourceTree: ResourceTree<ISCMResource, ISCMResourceGroup>;
62 > readonly onDidChangeResources: Event<void>;
63 >
64 > readonly label: string;
65 > contextValue: string | undefined;
66 > readonly hideWhenEmpty: boolean;
67 > readonly onDidChange: Event<void>;
68 >
69 > readonly multiDiffEditorEnableViewChanges: boolean;
70 > }
71 >
72 > export interface ISCMProvider extends IDisposable {
73 > readonly id: string;
74 > readonly parentId?: string;
75 > readonly providerId: string;
76 > readonly label: string;
77 > readonly name: string;
78 >
79 > readonly groups: readonly ISCMResourceGroup[];
80 > readonly onDidChangeResourceGroups: Event<void>;
81 > readonly onDidChangeResources: Event<void>;
82 >
83 > readonly rootUri?: URI;
84 > readonly iconPath?: URI | { light: URI; dark: URI } | ThemeIcon;
85 > readonly isHidden?: boolean;
86 > readonly inputBoxTextModel: ITextModel;
87 > readonly contextValue: IObservable<string | undefined>;
88 > readonly count: IObservable<number | undefined>;
89 > readonly commitTemplate: IObservable<string>;
90 > readonly artifactProvider: IObservable<ISCMArtifactProvider | undefined>;
91 > readonly historyProvider: IObservable<ISCMHistoryProvider | undefined>;
92 > readonly acceptInputCommand?: Command;
93 > readonly actionButton: IObservable<ISCMActionButtonDescriptor | undefined>;
94 > readonly statusBarCommands: IObservable<readonly Command[] | undefined>;
95 >
96 > getOriginalResource(uri: URI): Promise<URI | null>;
97 > }
98 >
99 > export interface ISCMInputValueProviderContext {
100 > readonly resourceGroupId: string;
101 > readonly resources: readonly URI[];
102 > }
103 >
104 > export const enum InputValidationType {
105 > Error = 0,
106 > Warning = 1,
107 > Information = 2
108 > }
109 >
110 > export interface IInputValidation {
111 > message: string | IMarkdownString;
112 > type: InputValidationType;
113 > }
114 >
115 > export interface IInputValidator {
116 > (value: string, cursorPosition: number): Promise<IInputValidation | undefined>;
117 > }
118 >
119 > export enum SCMInputChangeReason {
120 > HistoryPrevious,
121 > HistoryNext
122 > }
123 >
124 > export interface ISCMInputChangeEvent {
125 > readonly value: string;
126 > readonly reason?: SCMInputChangeReason;
127 > }
128 >
129 > export interface ISCMActionButtonDescriptor {
130 > command: Command & { shortTitle?: string };
131 > secondaryCommands?: Command[][];
132 > enabled: boolean;
133 > }
134 >
135 > export interface ISCMActionButton {
136 > readonly type: 'actionButton';
137 > readonly repository: ISCMRepository;
138 > readonly button: ISCMActionButtonDescriptor;
139 > }
140 >
141 > export interface ISCMInput {
142 > readonly repository: ISCMRepository;
143 >
144 > readonly value: string;
145 > setValue(value: string, fromKeyboard: boolean): void;
146 > readonly onDidChange: Event<ISCMInputChangeEvent>;
147 >
148 > placeholder: string;
149 > readonly onDidChangePlaceholder: Event<string>;
150 >
151 > validateInput: IInputValidator;
152 > readonly onDidChangeValidateInput: Event<void>;
153 >
154 > enabled: boolean;
155 > readonly onDidChangeEnablement: Event<boolean>;
156 >
157 > visible: boolean;
158 > readonly onDidChangeVisibility: Event<boolean>;
159 >
160 > setFocus(): void;
161 > readonly onDidChangeFocus: Event<void>;
162 >
163 > showValidationMessage(message: string | IMarkdownString, type: InputValidationType): void;
164 > readonly onDidChangeValidationMessage: Event<IInputValidation>;
165 >
166 > clearValidation(): void;
167 > readonly onDidClearValidation: Event<void>;
168 >
169 > showNextHistoryValue(): void;
170 > showPreviousHistoryValue(): void;
171 > }
172 >
173 > export interface ISCMRepository extends IDisposable {
174 > readonly id: string;
175 > readonly provider: ISCMProvider;
176 > readonly input: ISCMInput;
177 > }
178 >
179 > export interface ISCMService {
180 >
181 > readonly _serviceBrand: undefined;
182 > readonly onDidAddRepository: Event<ISCMRepository>;
183 > readonly onDidRemoveRepository: Event<ISCMRepository>;
184 > readonly repositories: Iterable<ISCMRepository>;
185 > readonly repositoryCount: number;
186 >
187 > registerSCMProvider(provider: ISCMProvider): ISCMRepository;
188 >
189 > getRepository(id: string): ISCMRepository | undefined;
190 > getRepository(resource: URI): ISCMRepository | undefined;
191 > }
192 >
193 > export interface ISCMTitleMenu {
194 > readonly actions: IAction[];
195 > readonly secondaryActions: IAction[];
196 > readonly onDidChangeTitle: Event<void>;
197 > readonly menu: IMenu;
198 > }
199 >
200 > export interface ISCMRepositoryMenus {
201 > readonly titleMenu: ISCMTitleMenu;
202 > getRepositoryMenu(repository: ISCMRepository): IMenu;
203 > getRepositoryContextMenu(repository: ISCMRepository): IMenu;
204 > getResourceGroupMenu(group: ISCMResourceGroup): IMenu;
205 > getResourceMenu(resource: ISCMResource): IMenu;
206 > getResourceFolderMenu(group: ISCMResourceGroup): IMenu;
207 > getArtifactGroupMenu(artifactGroup: ISCMArtifactGroup): IMenu;
208 > getArtifactMenu(artifactGroup: ISCMArtifactGroup, artifact: ISCMArtifact): IMenu;
209 > }
210 >
211 > export interface ISCMMenus {
212 > getRepositoryMenus(provider: ISCMProvider): ISCMRepositoryMenus;
213 > }
214 >
215 > export const enum ISCMRepositorySortKey {
216 > DiscoveryTime = 'discoveryTime',
217 > Name = 'name',
218 > Path = 'path'
219 > }
220 >
221 > export const enum ISCMRepositorySelectionMode {
222 > Single = 'single',
223 > Multiple = 'multiple'
224 > }
225 >
226 > export const ISCMViewService = createDecorator<ISCMViewService>('scmView');
227 >
228 > export interface ISCMViewVisibleRepositoryChangeEvent {
229 > readonly added: Iterable<ISCMRepository>;
230 > readonly removed: Iterable<ISCMRepository>;
231 > }
232 >
233 > export interface ISCMViewService {
234 > readonly _serviceBrand: undefined;
235 >
236 > readonly menus: ISCMMenus;
237 > readonly selectionModeConfig: IObservable<ISCMRepositorySelectionMode>;
238 > readonly explorerEnabledConfig: IObservable<boolean>;
239 > readonly graphShowIncomingChangesConfig: IObservable<boolean>;
240 > readonly graphShowOutgoingChangesConfig: IObservable<boolean>;
241 >
242 > repositories: ISCMRepository[];
243 > readonly onDidChangeRepositories: Event<ISCMViewVisibleRepositoryChangeEvent>;
244 > readonly didFinishLoadingRepositories: IObservable<boolean>;
245 >
246 > visibleRepositories: readonly ISCMRepository[];
247 > readonly onDidChangeVisibleRepositories: Event<ISCMViewVisibleRepositoryChangeEvent>;
248 >
249 > isVisible(repository: ISCMRepository): boolean;
250 > toggleVisibility(repository: ISCMRepository, visible?: boolean): void;
251 >
252 > toggleSortKey(sortKey: ISCMRepositorySortKey): void;
253 > toggleSelectionMode(selectionMode: ISCMRepositorySelectionMode): void;
254 >
255 > readonly focusedRepository: ISCMRepository | undefined;
256 > readonly onDidFocusRepository: Event<ISCMRepository | undefined>;
257 > focus(repository: ISCMRepository): void;
258 >
259 > /**
260 > * The active repository is the repository selected in the Source Control Repositories view
261 > * or the repository associated with the active editor. The active repository is shown in the
262 > * Source Control Repository status bar item.
263 > */
264 > readonly activeRepository: IObservable<{ repository: ISCMRepository; pinned: boolean } | undefined>;
265 > pinActiveRepository(repository: ISCMRepository | undefined): void;
266 > }
src/vs/platform/userDataProfile/common/userDataProfile.ts 256 covered LOC · 28 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- userDataProfile.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { hash } from '../../../base/common/hash.js';
7 > import { Emitter, Event } from '../../../base/common/event.js';
8 > import { Disposable } from '../../../base/common/lifecycle.js';
9 > import { basename, joinPath } from '../../../base/common/resources.js';
10 > import { URI, UriDto } from '../../../base/common/uri.js';
11 > import { localize } from '../../../nls.js';
12 > import { IEnvironmentService } from '../../environment/common/environment.js';
13 > import { FileOperationResult, IFileService, toFileOperationResult } from '../../files/common/files.js';
14 > import { createDecorator } from '../../instantiation/common/instantiation.js';
15 > import { ILogService } from '../../log/common/log.js';
16 > import { IAnyWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier } from '../../workspace/common/workspace.js';
17 > import { IStringDictionary } from '../../../base/common/collections.js';
18 > import { IUriIdentityService } from '../../uriIdentity/common/uriIdentity.js';
19 > import { Promises } from '../../../base/common/async.js';
20 > import { generateUuid } from '../../../base/common/uuid.js';
21 > import { escapeRegExpCharacters } from '../../../base/common/strings.js';
22 > import { isString, Mutable } from '../../../base/common/types.js';
23 >
24 > export const AGENTS_WINDOW_PROFILE_ID = 'agents';
25 >
26 > const AGENTS_WINDOW_PROFILE_FLAGS: UseDefaultProfileFlags = {
27 > settings: true,
28 > keybindings: true,
29 > prompts: true,
30 > mcp: true,
31 > languageModels: true,
32 > snippets: true,
33 > tasks: true,
34 > extensions: true,
35 > };
36 >
37 > export const enum ProfileResourceType {
38 > Settings = 'settings',
39 > Keybindings = 'keybindings',
40 > Snippets = 'snippets',
41 > Prompts = 'prompts',
42 > Tasks = 'tasks',
43 > Extensions = 'extensions',
44 > GlobalState = 'globalState',
45 > Mcp = 'mcp',
46 > LanguageModels = 'languageModels',
47 > }
48 >
49 > /**
50 > * Flags to indicate whether to use the default profile or not.
51 > */
52 > export type UseDefaultProfileFlags = { [key in ProfileResourceType]?: boolean };
53 > export type ProfileResourceTypeFlags = UseDefaultProfileFlags;
54 > export type SettingValue = string | boolean | number | undefined | null | object;
55 > export type ISettingsDictionary = Record<string, SettingValue>;
56 >
57 > export interface IUserDataProfile {
58 > readonly id: string;
59 > readonly isDefault: boolean;
60 > readonly name: string;
61 > readonly icon?: string;
62 > readonly location: URI;
63 > readonly globalStorageHome: URI;
64 > readonly settingsResource: URI;
65 > readonly keybindingsResource: URI;
66 > readonly tasksResource: URI;
67 > readonly snippetsHome: URI;
68 > readonly promptsHome: URI;
69 > readonly extensionsResource: URI;
70 > readonly mcpResource: URI;
71 > readonly languageModelsResource: URI;
72 > readonly agentPluginsHome: URI;
73 > readonly cacheHome: URI;
74 > readonly useDefaultFlags?: UseDefaultProfileFlags;
75 > readonly isInternal?: boolean;
76 > readonly isTransient?: boolean;
77 > readonly isAgentsWindowProfile?: boolean;
78 > readonly workspaces?: readonly URI[];
79 > }
80 >
81 > export function isUserDataProfile(thing: unknown): thing is IUserDataProfile {
82 const candidate = thing as IUserDataProfile | undefined;
83
99 );
100 }
102 > export interface IParsedUserDataProfileTemplate {
103 > readonly name: string;
104 > readonly icon?: string;
105 > readonly settings?: ISettingsDictionary;
106 > readonly globalState?: IStringDictionary<string>;
107 > }
108 >
109 > export interface ISystemProfileTemplate extends IParsedUserDataProfileTemplate {
110 > readonly id: string;
111 > }
112 >
113 > export type DidChangeProfilesEvent = { readonly added: readonly IUserDataProfile[]; readonly removed: readonly IUserDataProfile[]; readonly updated: readonly IUserDataProfile[]; readonly all: readonly IUserDataProfile[] };
114 >
115 > export type WillCreateProfileEvent = {
116 > profile: IUserDataProfile;
117 > join(promise: Promise<void>): void;
118 > };
119 >
120 > export type WillRemoveProfileEvent = {
121 > profile: IUserDataProfile;
122 > join(promise: Promise<void>): void;
123 > };
124 >
125 > export interface IUserDataProfileOptions {
126 > readonly icon?: string;
127 > readonly useDefaultFlags?: UseDefaultProfileFlags;
128 > readonly transient?: boolean;
129 > readonly workspaces?: readonly URI[];
130 > }
131 >
132 > export interface IUserDataProfileUpdateOptions extends Omit<IUserDataProfileOptions, 'icon'> {
133 > readonly name?: string;
134 > readonly icon?: string | null;
135 > }
136 >
137 > export const IUserDataProfilesService = createDecorator<IUserDataProfilesService>('IUserDataProfilesService');
138 > export interface IUserDataProfilesService {
139 > readonly _serviceBrand: undefined;
140 >
141 > readonly profilesHome: URI;
142 > readonly defaultProfile: IUserDataProfile;
143 >
144 > readonly onDidChangeProfiles: Event<DidChangeProfilesEvent>;
145 > readonly profiles: readonly IUserDataProfile[];
146 >
147 > readonly onDidResetWorkspaces: Event<void>;
148 >
149 > createNamedProfile(name: string, options?: IUserDataProfileOptions, workspaceIdentifier?: IAnyWorkspaceIdentifier): Promise<IUserDataProfile>;
150 > createTransientProfile(workspaceIdentifier?: IAnyWorkspaceIdentifier): Promise<IUserDataProfile>;
151 > createProfile(id: string, name: string, options?: IUserDataProfileOptions, workspaceIdentifier?: IAnyWorkspaceIdentifier): Promise<IUserDataProfile>;
152 > updateProfile(profile: IUserDataProfile, options?: IUserDataProfileUpdateOptions,): Promise<IUserDataProfile>;
153 > removeProfile(profile: IUserDataProfile): Promise<void>;
154 >
155 > setProfileForWorkspace(workspaceIdentifier: IAnyWorkspaceIdentifier, profile: IUserDataProfile): Promise<void>;
156 > resetWorkspaces(): Promise<void>;
157 >
158 > cleanUp(): Promise<void>;
159 > cleanUpTransientProfiles(): Promise<void>;
160 > }
161 >
162 > export function reviveProfile(profile: UriDto<IUserDataProfile>, scheme: string): IUserDataProfile {
163 return {
164 id: profile.id,
185 };
186 }
188 > export function toUserDataProfile(id: string, name: string, location: URI, profilesCacheHome: URI, options?: IUserDataProfileOptions, defaultProfile?: IUserDataProfile): IUserDataProfile {
189 const isAgentsWindowProfile = id === AGENTS_WINDOW_PROFILE_ID;
190 return {
212 };
213 }
215 > export type UserDataProfilesObject = {
216 > profiles: IUserDataProfile[];
217 > emptyWindows: Map<string, IUserDataProfile>;
218 > };
219 >
220 > export type StoredUserDataProfile = {
221 > name: string;
222 > location: URI;
223 > icon?: string;
224 > useDefaultFlags?: UseDefaultProfileFlags;
225 > };
226 >
227 > export type StoredProfileAssociations = {
228 > workspaces?: IStringDictionary<string>;
229 > emptyWindows?: IStringDictionary<string>;
230 > };
231 >
232 > const SYSTEM_PROFILES_HOME = 'builtin';
233 >
234 > export class UserDataProfilesService extends Disposable implements IUserDataProfilesService {
235 >
236 > readonly _serviceBrand: undefined;
237 >
238 > protected static readonly PROFILES_KEY = 'userDataProfiles';
239 > protected static readonly PROFILE_ASSOCIATIONS_KEY = 'profileAssociations';
240 >
241 > readonly profilesHome: URI;
242 > private readonly profilesCacheHome: URI;
243 >
244 > get defaultProfile(): IUserDataProfile { return this.profiles[0]; }
245 > get profiles(): IUserDataProfile[] { return [...this.profilesObject.profiles, ...this.transientProfilesObject.profiles]; }
246 >
247 > protected readonly _onDidChangeProfiles = this._register(new Emitter<DidChangeProfilesEvent>());
248 > readonly onDidChangeProfiles = this._onDidChangeProfiles.event;
249 >
250 > protected readonly _onWillCreateProfile = this._register(new Emitter<WillCreateProfileEvent>());
251 > readonly onWillCreateProfile = this._onWillCreateProfile.event;
252 >
253 > protected readonly _onWillRemoveProfile = this._register(new Emitter<WillRemoveProfileEvent>());
254 > readonly onWillRemoveProfile = this._onWillRemoveProfile.event;
255 >
256 > private readonly _onDidResetWorkspaces = this._register(new Emitter<void>());
257 > readonly onDidResetWorkspaces = this._onDidResetWorkspaces.event;
258 >
259 > private profileCreationPromises = new Map<string, Promise<IUserDataProfile>>();
260 >
261 > protected readonly transientProfilesObject: UserDataProfilesObject = {
262 > profiles: [],
263 > emptyWindows: new Map()
264 > };
265 >
266 > constructor(
267 @IEnvironmentService protected environmentService: IEnvironmentService,
268 @IFileService protected fileService: IFileService,
274 this.profilesCacheHome = joinPath(this.environmentService.cacheHome, 'CachedProfilesData');
275 }
277 > init(): void {
278 this._profilesObject = undefined;
279 }
281 > protected _profilesObject: UserDataProfilesObject | undefined;
282 > protected get profilesObject(): UserDataProfilesObject {
283 if (!this._profilesObject) {
284 const defaultProfile = this.createDefaultProfile();
336 return this._profilesObject;
337 }
339 > private isInvalidProfile(storedProfile: StoredUserDataProfile): boolean {
340 if (!storedProfile.name) {
341 return true;
349 return false;
350 }
352 > protected createDefaultProfile() {
353 const defaultProfile = toUserDataProfile('__default__profile__', localize('defaultProfile', "Default"), this.environmentService.userRoamingDataHome, this.profilesCacheHome);
354 return { ...defaultProfile, extensionsResource: this.getDefaultProfileExtensionsLocation() ?? defaultProfile.extensionsResource, isDefault: true };
355 }
357 > async createTransientProfile(workspaceIdentifier?: IAnyWorkspaceIdentifier): Promise<IUserDataProfile> {
358 const namePrefix = `Temp`;
359 const nameRegEx = new RegExp(`${escapeRegExpCharacters(namePrefix)}\\s(\\d+)`);
367 return this.createProfile(hash(generateUuid()).toString(16), name, { transient: true }, workspaceIdentifier);
368 }
370 > async createNamedProfile(name: string, options?: IUserDataProfileOptions, workspaceIdentifier?: IAnyWorkspaceIdentifier): Promise<IUserDataProfile> {
371 return this.createProfile(hash(generateUuid()).toString(16), name, options, workspaceIdentifier);
372 }
374 > async createProfile(id: string, name: string, options?: IUserDataProfileOptions, workspaceIdentifier?: IAnyWorkspaceIdentifier): Promise<IUserDataProfile> {
375 const profile = await this.doCreateProfile(id, name, options, workspaceIdentifier);
376
377 return profile;
378 }
380 > private async doCreateProfile(id: string, name: string, options?: IUserDataProfileOptions, workspaceIdentifier?: IAnyWorkspaceIdentifier): Promise<IUserDataProfile> {
381 if (!isString(name) || !name) {
382 throw new Error('Name of the profile is mandatory and must be of type `string`');
428 return profileCreationPromise;
429 }
431 > async updateProfile(profile: IUserDataProfile, options: IUserDataProfileUpdateOptions): Promise<IUserDataProfile> {
432 if (profile.isAgentsWindowProfile) {
433 throw new Error('Cannot update agents window profile');
481 return updatedProfile;
482 }
484 > async removeProfile(profileToRemove: IUserDataProfile): Promise<void> {
485 if (profileToRemove.isDefault) {
486 throw new Error('Cannot remove default profile');
515 }
516 }
518 > async setProfileForWorkspace(workspaceIdentifier: IAnyWorkspaceIdentifier, profileToSet: IUserDataProfile): Promise<void> {
519 const profile = this.profiles.find(p => p.id === profileToSet.id);
520 if (!profile) {
534 }
535 }
537 > unsetWorkspace(workspaceIdentifier: IAnyWorkspaceIdentifier, transient: boolean = false): void {
538 const workspace = this.getWorkspace(workspaceIdentifier);
539 if (URI.isUri(workspace)) {
547 }
548 }
550 > async resetWorkspaces(): Promise<void> {
551 this.transientProfilesObject.emptyWindows.clear();
552 this.profilesObject.emptyWindows.clear();
557 this._onDidResetWorkspaces.fire();
558 }
560 > async cleanUp(): Promise<void> {
561 try {
562 if (await this.fileService.exists(this.profilesHome)) {
587 }
588 }
590 > async cleanUpTransientProfiles(): Promise<void> {
591 const unAssociatedTransientProfiles = this.transientProfilesObject.profiles.filter(p => !this.isProfileAssociatedToWorkspace(p));
592 await Promise.allSettled(unAssociatedTransientProfiles.map(p => this.removeProfile(p)));
593 }
595 > getProfileForWorkspace(workspaceIdentifier: IAnyWorkspaceIdentifier): IUserDataProfile | undefined {
596 const workspace = this.getWorkspace(workspaceIdentifier);
597
604 : (this.profilesObject.emptyWindows.get(workspace) ?? this.transientProfilesObject.emptyWindows.get(workspace));
605 }
607 > protected getWorkspace(workspaceIdentifier: IAnyWorkspaceIdentifier): URI | string {
608 if (isSingleFolderWorkspaceIdentifier(workspaceIdentifier)) {
609 return workspaceIdentifier.uri;
614 return workspaceIdentifier.id;
615 }
617 > private isProfileAssociatedToWorkspace(profile: IUserDataProfile): boolean {
618 if (profile.workspaces?.length) {
619 return true;
627 return false;
628 }
630 > private updateProfiles(added: IUserDataProfile[], removed: IUserDataProfile[], updated: IUserDataProfile[], donotTrigger: boolean = false): void {
631 const allProfiles: Mutable<IUserDataProfile>[] = [...this.profiles, ...added];
632
679 }
680 }
682 > protected triggerProfilesChanges(added: IUserDataProfile[], removed: IUserDataProfile[], updated: IUserDataProfile[]) {
683 this._onDidChangeProfiles.fire({ added, removed, updated, all: this.profiles });
684 }
686 > private updateEmptyWindowAssociation(windowId: string, newProfile: IUserDataProfile | undefined, transient: boolean): void {
687 // Force transient if the new profile to associate is transient
688 transient = newProfile?.isTransient ? true : transient;
706 }
707 }
709 > private updateStoredProfiles(profiles: IUserDataProfile[]): void {
710 const storedProfiles: StoredUserDataProfile[] = [];
711 const workspaces: IStringDictionary<string> = {};
739 this._profilesObject = undefined;
740 }
742 > protected getStoredProfiles(): StoredUserDataProfile[] { return []; }
743 > protected saveStoredProfiles(storedProfiles: StoredUserDataProfile[]): void { throw new Error('not implemented'); }
744 >
745 > protected getStoredProfileAssociations(): StoredProfileAssociations { return {}; }
746 > protected saveStoredProfileAssociations(storedProfileAssociations: StoredProfileAssociations): void { throw new Error('not implemented'); }
747 > protected getDefaultProfileExtensionsLocation(): URI | undefined { return undefined; }
748 > }
749 >
750 > export class InMemoryUserDataProfilesService extends UserDataProfilesService {
751 private storedProfiles: StoredUserDataProfile[] = [];
752 protected override getStoredProfiles(): StoredUserDataProfile[] { return this.storedProfiles; }
754
755 private storedProfileAssociations: StoredProfileAssociations = {};
756 > protected override getStoredProfileAssociations(): StoredProfileAssociations { return this.storedProfileAssociations; } userDataProfile.ts
757 > protected override saveStoredProfileAssociations(storedProfileAssociations: StoredProfileAssociations): void { this.storedProfileAssociations = storedProfileAssociations; }
758 > }
src/vs/workbench/contrib/testing/common/testItemCollection.ts 255 covered LOC · 29 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- testItemCollection.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { Barrier, isThenable, RunOnceScheduler } from '../../../../base/common/async.js';
7 > import { Emitter } from '../../../../base/common/event.js';
8 > import { Disposable } from '../../../../base/common/lifecycle.js';
9 > import { assertNever } from '../../../../base/common/assert.js';
10 > import { applyTestItemUpdate, ITestItem, ITestTag, namespaceTestTag, TestDiffOpType, TestItemExpandState, TestsDiff, TestsDiffOp } from './testTypes.js';
11 > import { TestId } from './testId.js';
12 > import { URI } from '../../../../base/common/uri.js';
13 >
14 > /**
15 > * @private
16 > */
17 > interface CollectionItem<T> {
18 > readonly fullId: TestId;
19 > actual: T;
20 > expand: TestItemExpandState;
21 > /**
22 > * Number of levels of items below this one that are expanded. May be infinite.
23 > */
24 > expandLevels?: number;
25 > resolveBarrier?: Barrier;
26 > }
27 >
28 > export const enum TestItemEventOp {
29 > Upsert,
30 > SetTags,
31 > UpdateCanResolveChildren,
32 > RemoveChild,
33 > SetProp,
34 > Bulk,
35 > DocumentSynced,
36 > }
37 >
38 > export interface ITestItemUpsertChild {
39 > op: TestItemEventOp.Upsert;
40 > item: ITestItemLike;
41 > }
42 >
43 > export interface ITestItemUpdateCanResolveChildren {
44 > op: TestItemEventOp.UpdateCanResolveChildren;
45 > state: boolean;
46 > }
47 >
48 > export interface ITestItemSetTags {
49 > op: TestItemEventOp.SetTags;
50 > new: ITestTag[];
51 > old: ITestTag[];
52 > }
53 >
54 > export interface ITestItemRemoveChild {
55 > op: TestItemEventOp.RemoveChild;
56 > id: string;
57 > }
58 >
59 > export interface ITestItemSetProp {
60 > op: TestItemEventOp.SetProp;
61 > update: Partial<ITestItem>;
62 > }
63 > export interface ITestItemBulkReplace {
64 > op: TestItemEventOp.Bulk;
65 > ops: (ITestItemUpsertChild | ITestItemRemoveChild)[];
66 > }
67 >
68 > export interface ITestItemDocumentSynced {
69 > op: TestItemEventOp.DocumentSynced;
70 > }
71 >
72 > export type ExtHostTestItemEvent =
73 > | ITestItemSetTags
74 > | ITestItemUpsertChild
75 > | ITestItemRemoveChild
76 > | ITestItemUpdateCanResolveChildren
77 > | ITestItemSetProp
78 > | ITestItemBulkReplace
79 > | ITestItemDocumentSynced;
80 >
81 > export interface ITestItemApi<T> {
82 > controllerId: string;
83 > parent?: T;
84 > listener?: (evt: ExtHostTestItemEvent) => void;
85 > }
86 >
87 > export interface ITestItemCollectionOptions<T> {
88 > /** Controller ID to use to prefix these test items. */
89 > controllerId: string;
90 >
91 > /** Gets the document version at the given URI, if it's open */
92 > getDocumentVersion(uri: URI | undefined): number | undefined;
93 >
94 > /** Gets API for the given test item, used to listen for events and set parents. */
95 > getApiFor(item: T): ITestItemApi<T>;
96 >
97 > /** Converts the full test item to the common interface. */
98 > toITestItem(item: T): ITestItem;
99 >
100 > /** Gets children for the item. */
101 > getChildren(item: T): ITestChildrenLike<T>;
102 >
103 > /** Root to use for the new test collection. */
104 > root: T;
105 > }
106 >
107 > const strictEqualComparator = <T>(a: T, b: T) => a === b;
108 > const diffableProps: { [K in keyof ITestItem]?: (a: ITestItem[K], b: ITestItem[K]) => boolean } = {
109 > range: (a, b) => {
110 if (a === b) { return true; }
111 if (!a || !b) { return false; }
112 return a.equalsRange(b);
113 },
114 > busy: strictEqualComparator, testItemCollection.ts
115 > label: strictEqualComparator,
116 > description: strictEqualComparator,
117 > error: strictEqualComparator,
118 > sortText: strictEqualComparator,
119 > tags: (a, b) => {
120 if (a.length !== b.length) {
121 return false;
128 return true;
129 },
131 >
132 > const diffableEntries = Object.entries(diffableProps) as readonly [keyof ITestItem, (a: unknown, b: unknown) => boolean][];
133 >
134 > const diffTestItems = (a: ITestItem, b: ITestItem) => {
135 let output: Record<string, unknown> | undefined;
136 for (const [key, cmp] of diffableEntries) {
146 return output as Partial<ITestItem> | undefined;
147 };
149 > export interface ITestChildrenLike<T> extends Iterable<[string, T]> {
150 > get(id: string): T | undefined;
151 > delete(id: string): void;
152 > }
153 >
154 > export interface ITestItemLike {
155 > id: string;
156 > tags: readonly ITestTag[];
157 > uri?: URI;
158 > canResolveChildren: boolean;
159 > }
160 >
161 > /**
162 > * Maintains a collection of test items for a single controller.
163 > */
164 > export class TestItemCollection<T extends ITestItemLike> extends Disposable {
165 > private readonly debounceSendDiff = this._register(new RunOnceScheduler(() => this.flushDiff(), 200));
166 > private readonly diffOpEmitter = this._register(new Emitter<TestsDiff>());
167 > private _resolveHandler?: (item: T | undefined) => Promise<void> | void;
168 >
169 > public get root() {
170 > return this.options.root;
171 > }
172 >
173 > public readonly tree = new Map</* full test id */string, CollectionItem<T>>();
174 > private readonly tags = new Map<string, { label?: string; refCount: number }>();
175 >
176 > protected diff: TestsDiff = [];
177 >
178 > constructor(private readonly options: ITestItemCollectionOptions<T>) {
179 super();
180 this.root.canResolveChildren = true;
181 this.upsertItem(this.root, undefined);
182 }
184 > /**
185 > * Handler used for expanding test items.
186 > */
187 > public set resolveHandler(handler: undefined | ((item: T | undefined) => void)) {
188 this._resolveHandler = handler;
189 for (const test of this.tree.values()) {
191 }
192 }
194 > public get resolveHandler() {
195 return this._resolveHandler;
196 }
198 > /**
199 > * Fires when an operation happens that should result in a diff.
200 > */
201 > public readonly onDidGenerateDiff = this.diffOpEmitter.event;
202 >
203 > /**
204 > * Gets a diff of all changes that have been made, and clears the diff queue.
205 > */
206 > public collectDiff() {
207 const diff = this.diff;
208 this.diff = [];
209 return diff;
210 }
212 > /**
213 > * Pushes a new diff entry onto the collected diff list.
214 > */
215 > public pushDiff(diff: TestsDiffOp) {
216 switch (diff.op) {
217 case TestDiffOpType.DocumentSynced: {
249 }
250 }
252 > /**
253 > * Expands the test and the given number of `levels` of children. If levels
254 > * is < 0, then all children will be expanded. If it's 0, then only this
255 > * item will be expanded.
256 > */
257 > public expand(testId: string, levels: number): Promise<void> | void {
258 const internal = this.tree.get(testId);
259 if (!internal) {
278 }
279 }
281 > public override dispose() {
282 for (const item of this.tree.values()) {
283 this.options.getApiFor(item.actual).listener = undefined;
288 super.dispose();
289 }
291 > private onTestItemEvent(internal: CollectionItem<T>, evt: ExtHostTestItemEvent) {
292 switch (evt.op) {
293 case TestItemEventOp.RemoveChild:
331 }
332 }
334 > private documentSynced(uri: URI | undefined) {
335 if (uri) {
336 this.pushDiff({
341 }
342 }
344 > private upsertItem(actual: T, parent: CollectionItem<T> | undefined): void {
345 const fullId = TestId.fromExtHostTestItem(actual, this.root.id, parent?.actual);
346
434 this.documentSynced(internal.actual.uri);
435 }
437 > private diffTagRefs(newTags: readonly ITestTag[], oldTags: readonly ITestTag[], extId: string) {
438 const toDelete = new Set(oldTags.map(t => t.id));
439 for (const tag of newTags) {
450 toDelete.forEach(this.decrementTagRefs, this);
451 }
453 > private incrementTagRefs(tag: ITestTag) {
454 const existing = this.tags.get(tag.id);
455 if (existing) {
464 }
465 }
467 > private decrementTagRefs(tagId: string) {
468 const existing = this.tags.get(tagId);
469 if (existing && !--existing.refCount) {
472 }
473 }
475 > private setItemParent(actual: T, parent: CollectionItem<T> | undefined) {
476 this.options.getApiFor(actual).parent = parent && parent.actual !== this.root ? parent.actual : undefined;
477 }
479 > private connectItem(actual: T, internal: CollectionItem<T>, parent: CollectionItem<T> | undefined) {
480 this.setItemParent(actual, parent);
481 const api = this.options.getApiFor(actual);
484 this.updateExpandability(internal);
485 }
487 > private connectItemAndChildren(actual: T, internal: CollectionItem<T>, parent: CollectionItem<T> | undefined) {
488 this.connectItem(actual, internal, parent);
489
493 }
494 }
496 > /**
497 > * Updates the `expand` state of the item. Should be called whenever the
498 > * resolved state of the item changes. Can automatically expand the item
499 > * if requested by a consumer.
500 > */
501 > private updateExpandability(internal: CollectionItem<T>) {
502 let newState: TestItemExpandState;
503 if (!this._resolveHandler) {
524 }
525 }
527 > /**
528 > * Expands all children of the item, "levels" deep. If levels is 0, only
529 > * the children will be expanded. If it's 1, the children and their children
530 > * will be expanded. If it's <0, it's a no-op.
531 > */
532 > private expandChildren(internal: CollectionItem<T>, levels: number): Promise<void> | void {
533 if (levels < 0) {
534 return;
547 }
548 }
550 > /**
551 > * Calls `discoverChildren` on the item, refreshing all its tests.
552 > */
553 > private resolveChildren(internal: CollectionItem<T>) {
554 if (internal.resolveBarrier) {
555 return internal.resolveBarrier;
589 return internal.resolveBarrier;
590 }
592 > private pushExpandStateUpdate(internal: CollectionItem<T>) {
593 this.pushDiff({ op: TestDiffOpType.Update, item: { extId: internal.fullId.toString(), expand: internal.expand } });
594 }
596 > private removeItem(childId: string) {
597 const childItem = this.tree.get(childId);
598 if (!childItem) {
621 }
622 }
624 > /**
625 > * Immediately emits any pending diffs on the collection.
626 > */
627 > public flushDiff() {
628 const diff = this.collectDiff();
629 if (diff.length) {
631 }
632 }
634 >
635 > /** Implementation of vscode.TestItemCollection */
636 > export interface ITestItemChildren<T extends ITestItemLike> extends Iterable<[string, T]> {
637 > readonly size: number;
638 > replace(items: readonly T[]): void;
639 > forEach(callback: (item: T, collection: this) => unknown, thisArg?: unknown): void;
640 > add(item: T): void;
641 > delete(itemId: string): void;
642 > get(itemId: string): T | undefined;
643 >
644 > toJSON(): readonly T[];
645 > }
646 >
647 > export class DuplicateTestItemError extends Error {
648 > constructor(id: string) {
649 super(`Attempted to insert a duplicate test item ID ${id}`);
650 }
652 >
653 > export class InvalidTestItemError extends Error {
654 > constructor(id: string) {
655 super(`TestItem with ID "${id}" is invalid. Make sure to create it from the createTestItem method.`);
656 }
658 >
659 > export class MixedTestItemController extends Error {
660 > constructor(id: string, ctrlA: string, ctrlB: string) {
661 super(`TestItem with ID "${id}" is from controller "${ctrlA}" and cannot be added as a child of an item from controller "${ctrlB}".`);
662 }
664 >
665 > export const createTestItemChildren = <T extends ITestItemLike>(api: ITestItemApi<T>, getApi: (item: T) => ITestItemApi<T>, checkCtor: Function): ITestItemChildren<T> => {
666 let mapped = new Map<string, T>();
667
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/workbench/common/contextkeys.ts 250 covered LOC · 10 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- contextkeys.ts
2 > * Copyright (c) Microsoft 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 { URI } from '../../base/common/uri.js';
8 > import { localize } from '../../nls.js';
9 > import { IContextKeyService, IContextKey, RawContextKey } from '../../platform/contextkey/common/contextkey.js';
10 > import { basename, dirname, extname, isEqual } from '../../base/common/resources.js';
11 > import { ILanguageService } from '../../editor/common/languages/language.js';
12 > import { IFileService } from '../../platform/files/common/files.js';
13 > import { IModelService } from '../../editor/common/services/model.js';
14 > import { Schemas } from '../../base/common/network.js';
15 > import { EditorInput } from './editor/editorInput.js';
16 > import { IEditorResolverService } from '../services/editor/common/editorResolverService.js';
17 > import { DEFAULT_EDITOR_ASSOCIATION, isDiffEditorInput } from './editor.js';
18 >
19 > //#region < --- Workbench --- >
20 >
21 > export const WorkbenchStateContext = new RawContextKey<string>('workbenchState', undefined, { type: 'string', description: localize('workbenchState', "The kind of workspace opened in the window, either 'empty' (no workspace), 'folder' (single folder) or 'workspace' (multi-root workspace)") });
22 > export const WorkspaceFolderCountContext = new RawContextKey<number>('workspaceFolderCount', 0, localize('workspaceFolderCount', "The number of root folders in the workspace"));
23 >
24 > export const OpenFolderWorkspaceSupportContext = new RawContextKey<boolean>('openFolderWorkspaceSupport', true, true);
25 > export const EnterMultiRootWorkspaceSupportContext = new RawContextKey<boolean>('enterMultiRootWorkspaceSupport', true, true);
26 > export const EmptyWorkspaceSupportContext = new RawContextKey<boolean>('emptyWorkspaceSupport', true, true);
27 >
28 > export const DirtyWorkingCopiesContext = new RawContextKey<boolean>('dirtyWorkingCopies', false, localize('dirtyWorkingCopies', "Whether there are any working copies with unsaved changes"));
29 >
30 > export const RemoteNameContext = new RawContextKey<string>('remoteName', '', localize('remoteName', "The name of the remote the window is connected to or an empty string if not connected to any remote"));
31 >
32 > export const VirtualWorkspaceContext = new RawContextKey<string>('virtualWorkspace', '', localize('virtualWorkspace', "The scheme of the current workspace is from a virtual file system or an empty string."));
33 > export const TemporaryWorkspaceContext = new RawContextKey<boolean>('temporaryWorkspace', false, localize('temporaryWorkspace', "The scheme of the current workspace is from a temporary file system."));
34 >
35 > export const IsSessionsWindowContext = new RawContextKey<boolean>('isSessionsWindow', false, localize('isSessionsWindow', "Whether the current window is a agent sessions window."));
36 >
37 > export const HasWebFileSystemAccess = new RawContextKey<boolean>('hasWebFileSystemAccess', false, true); // Support for FileSystemAccess web APIs (https://wicg.github.io/file-system-access)
38 >
39 > export const EmbedderIdentifierContext = new RawContextKey<string | undefined>('embedderIdentifier', undefined, localize('embedderIdentifier', 'The identifier of the embedder according to the product service, if one is defined'));
40 >
41 > export const InAutomationContext = new RawContextKey<boolean>('inAutomation', false, localize('inAutomation', "Whether VS Code is running under automation/smoke test"));
42 >
43 > //#endregion
44 >
45 > //#region < --- Window --- >
46 >
47 > export const IsMainWindowFullscreenContext = new RawContextKey<boolean>('isFullscreen', false, localize('isFullscreen', "Whether the main window is in fullscreen mode"));
48 > export const IsAuxiliaryWindowFocusedContext = new RawContextKey<boolean>('isAuxiliaryWindowFocusedContext', false, localize('isAuxiliaryWindowFocusedContext', "Whether an auxiliary window is focused"));
49 >
50 > export const IsWindowAlwaysOnTopContext = new RawContextKey<boolean>('isWindowAlwaysOnTop', false, localize('isWindowAlwaysOnTop', "Whether the window is always on top"));
51 >
52 > export const IsAuxiliaryWindowContext = new RawContextKey<boolean>('isAuxiliaryWindow', false, localize('isAuxiliaryWindow', "Window is an auxiliary window"));
53 >
54 >
55 > //#endregion
56 >
57 >
58 > //#region < --- Editor --- >
59 >
60 > // Editor State Context Keys
61 > export const ActiveEditorDirtyContext = new RawContextKey<boolean>('activeEditorIsDirty', false, localize('activeEditorIsDirty', "Whether the active editor has unsaved changes"));
62 > export const ActiveEditorPinnedContext = new RawContextKey<boolean>('activeEditorIsNotPreview', false, localize('activeEditorIsNotPreview', "Whether the active editor is not in preview mode"));
63 > export const ActiveEditorFirstInGroupContext = new RawContextKey<boolean>('activeEditorIsFirstInGroup', false, localize('activeEditorIsFirstInGroup', "Whether the active editor is the first one in its group"));
64 > export const ActiveEditorLastInGroupContext = new RawContextKey<boolean>('activeEditorIsLastInGroup', false, localize('activeEditorIsLastInGroup', "Whether the active editor is the last one in its group"));
65 > export const ActiveEditorStickyContext = new RawContextKey<boolean>('activeEditorIsPinned', false, localize('activeEditorIsPinned', "Whether the active editor is pinned"));
66 > export const ActiveEditorReadonlyContext = new RawContextKey<boolean>('activeEditorIsReadonly', false, localize('activeEditorIsReadonly', "Whether the active editor is read-only"));
67 > export const ActiveCompareEditorCanSwapContext = new RawContextKey<boolean>('activeCompareEditorCanSwap', false, localize('activeCompareEditorCanSwap', "Whether the active compare editor can swap sides"));
68 > export const ActiveEditorCanToggleReadonlyContext = new RawContextKey<boolean>('activeEditorCanToggleReadonly', true, localize('activeEditorCanToggleReadonly', "Whether the active editor can toggle between being read-only or writeable"));
69 > export const ActiveEditorCanRevertContext = new RawContextKey<boolean>('activeEditorCanRevert', false, localize('activeEditorCanRevert', "Whether the active editor can revert"));
70 > export const ActiveEditorCanSplitInGroupContext = new RawContextKey<boolean>('activeEditorCanSplitInGroup', true);
71 >
72 > // Editor Kind Context Keys
73 > export const ActiveEditorContext = new RawContextKey<string | null>('activeEditor', null, { type: 'string', description: localize('activeEditor', "The identifier of the active editor") });
74 > export const ActiveEditorAvailableEditorIdsContext = new RawContextKey<string>('activeEditorAvailableEditorIds', '', localize('activeEditorAvailableEditorIds', "The available editor identifiers that are usable for the active editor"));
75 > export const TextCompareEditorVisibleContext = new RawContextKey<boolean>('textCompareEditorVisible', false, localize('textCompareEditorVisible', "Whether a text compare editor is visible"));
76 > export const TextCompareEditorActiveContext = new RawContextKey<boolean>('textCompareEditorActive', false, localize('textCompareEditorActive', "Whether a text compare editor is active"));
77 > export const SideBySideEditorActiveContext = new RawContextKey<boolean>('sideBySideEditorActive', false, localize('sideBySideEditorActive', "Whether a side by side editor is active"));
78 > export const ActiveCustomEditorDiffCanToggleLayoutContext = new RawContextKey<boolean>('activeCustomEditorDiffCanToggleLayout', false, localize('activeCustomEditorDiffCanToggleLayout', "Whether the active custom editor diff can toggle between inline and side by side layout"));
79 > export const ActiveCustomEditorTextDiffContext = new RawContextKey<boolean>('activeCustomEditorTextDiff', false, localize('activeCustomEditorTextDiff', "Whether the active custom editor diff is backed by text documents"));
80 >
81 > // Editor Group Context Keys
82 > export const EditorGroupEditorsCountContext = new RawContextKey<number>('groupEditorsCount', 0, localize('groupEditorsCount', "The number of opened editor groups"));
83 > export const IsTopRightEditorGroupContext = new RawContextKey<boolean>('isTopRightEditorGroup', false, localize('isTopRightEditorGroup', "Whether the editor group is the top right editor group in the editor part"));
84 > export const ActiveEditorGroupEmptyContext = new RawContextKey<boolean>('activeEditorGroupEmpty', false, localize('activeEditorGroupEmpty', "Whether the active editor group is empty"));
85 > export const ActiveEditorGroupIndexContext = new RawContextKey<number>('activeEditorGroupIndex', 0, localize('activeEditorGroupIndex', "The index of the active editor group"));
86 > export const ActiveEditorGroupLastContext = new RawContextKey<boolean>('activeEditorGroupLast', false, localize('activeEditorGroupLast', "Whether the active editor group is the last group"));
87 > export const ActiveEditorGroupLockedContext = new RawContextKey<boolean>('activeEditorGroupLocked', false, localize('activeEditorGroupLocked', "Whether the active editor group is locked"));
88 > export const MultipleEditorGroupsContext = new RawContextKey<boolean>('multipleEditorGroups', false, localize('multipleEditorGroups', "Whether there are multiple editor groups opened"));
89 > export const SingleEditorGroupsContext = MultipleEditorGroupsContext.toNegated();
90 > export const MultipleEditorsSelectedInGroupContext = new RawContextKey<boolean>('multipleEditorsSelectedInGroup', false, localize('multipleEditorsSelectedInGroup', "Whether multiple editors have been selected in an editor group"));
91 > export const TwoEditorsSelectedInGroupContext = new RawContextKey<boolean>('twoEditorsSelectedInGroup', false, localize('twoEditorsSelectedInGroup', "Whether exactly two editors have been selected in an editor group"));
92 > export const SelectedEditorsInGroupFileOrUntitledResourceContextKey = new RawContextKey<boolean>('SelectedEditorsInGroupFileOrUntitledResourceContextKey', true, localize('SelectedEditorsInGroupFileOrUntitledResourceContextKey', "Whether all selected editors in a group have a file or untitled resource associated"));
93 >
94 > // Editor Part Context Keys
95 > export const EditorPartMultipleEditorGroupsContext = new RawContextKey<boolean>('editorPartMultipleEditorGroups', false, localize('editorPartMultipleEditorGroups', "Whether there are multiple editor groups opened in an editor part"));
96 > export const EditorPartSingleEditorGroupsContext = EditorPartMultipleEditorGroupsContext.toNegated();
97 > export const EditorPartMaximizedEditorGroupContext = new RawContextKey<boolean>('editorPartMaximizedEditorGroup', false, localize('editorPartEditorGroupMaximized', "Editor Part has a maximized group"));
98 >
99 > export const EditorPartModalContext = new RawContextKey<boolean>('editorPartModal', false, localize('editorPartModal', "Whether focus is in a modal editor part"));
100 > export const EditorPartModalVisibleContext = new RawContextKey<boolean>('editorPartModalVisible', false, localize('editorPartModalVisible', "Whether a modal editor part is visible"));
101 > export const EditorPartModalMaximizedContext = new RawContextKey<boolean>('editorPartModalMaximized', false, localize('editorPartModalMaximized', "Whether the modal editor part is maximized"));
102 > export const EditorPartModalNavigationContext = new RawContextKey<boolean>('editorPartModalNavigation', false, localize('editorPartModalNavigation', "Whether the modal editor part has navigation context"));
103 > export const EditorPartModalSidebarContext = new RawContextKey<boolean>('editorPartModalSidebar', false, localize('editorPartModalSidebar', "Whether the modal editor part has a sidebar"));
104 > export const EditorPartModalSidebarVisibleContext = new RawContextKey<boolean>('editorPartModalSidebarVisible', false, localize('editorPartModalSidebarVisible', "Whether the modal editor part sidebar is visible"));
105 >
106 > // Editor Layout Context Keys
107 > export const EditorsVisibleContext = new RawContextKey<boolean>('editorIsOpen', false, localize('editorIsOpen', "Whether an editor is open"));
108 > export const EditorAreaFocusContext = new RawContextKey<boolean>('editorAreaFocus', false, localize('editorAreaFocus', "Whether the editor area (any editor part) has keyboard focus"));
109 > export const InEditorZenModeContext = new RawContextKey<boolean>('inZenMode', false, localize('inZenMode', "Whether Zen mode is enabled"));
110 > export const IsMainEditorCenteredLayoutContext = new RawContextKey<boolean>('isCenteredLayout', false, localize('isMainEditorCenteredLayout', "Whether centered layout is enabled for the main editor"));
111 > export const SplitEditorsVertically = new RawContextKey<boolean>('splitEditorsVertically', false, localize('splitEditorsVertically', "Whether editors split vertically"));
112 > export const MainEditorAreaVisibleContext = new RawContextKey<boolean>('mainEditorAreaVisible', true, localize('mainEditorAreaVisible', "Whether the editor area in the main window is visible"));
113 > export const EditorTabsVisibleContext = new RawContextKey<boolean>('editorTabsVisible', true, localize('editorTabsVisible', "Whether editor tabs are visible"));
114 >
115 > //#endregion
116 >
117 >
118 > //#region < --- Side Bar --- >
119 >
120 > export const SideBarVisibleContext = new RawContextKey<boolean>('sideBarVisible', false, localize('sideBarVisible', "Whether the sidebar is visible"));
121 > export const SidebarFocusContext = new RawContextKey<boolean>('sideBarFocus', false, localize('sideBarFocus', "Whether the sidebar has keyboard focus"));
122 > export const ActiveViewletContext = new RawContextKey<string>('activeViewlet', '', localize('activeViewlet', "The identifier of the active viewlet"));
123 >
124 > //#endregion
125 >
126 >
127 > //#region < --- Status Bar --- >
128 >
129 > export const StatusBarFocused = new RawContextKey<boolean>('statusBarFocused', false, localize('statusBarFocused', "Whether the status bar has keyboard focus"));
130 >
131 > //#endregion
132 >
133 > //#region < --- Title Bar --- >
134 >
135 > export const TitleBarStyleContext = new RawContextKey<string>('titleBarStyle', 'custom', localize('titleBarStyle', "Style of the window title bar"));
136 > export const TitleBarVisibleContext = new RawContextKey<boolean>('titleBarVisible', false, localize('titleBarVisible', "Whether the title bar is visible"));
137 > export const IsCompactTitleBarContext = new RawContextKey<boolean>('isCompactTitleBar', false, localize('isCompactTitleBar', "Title bar is in compact mode"));
138 >
139 > //#endregion
140 >
141 >
142 > //#region < --- Banner --- >
143 >
144 > export const BannerFocused = new RawContextKey<boolean>('bannerFocused', false, localize('bannerFocused', "Whether the banner has keyboard focus"));
145 >
146 > //#endregion
147 >
148 >
149 > //#region < --- Notifications --- >
150 >
151 > export const NotificationFocusedContext = new RawContextKey<boolean>('notificationFocus', true, localize('notificationFocus', "Whether a notification has keyboard focus"));
152 > export const NotificationsCenterVisibleContext = new RawContextKey<boolean>('notificationCenterVisible', false, localize('notificationCenterVisible', "Whether the notifications center is visible"));
153 > export const NotificationsToastsVisibleContext = new RawContextKey<boolean>('notificationToastsVisible', false, localize('notificationToastsVisible', "Whether a notification toast is visible"));
154 >
155 > //#endregion
156 >
157 >
158 > //#region < --- Auxiliary Bar --- >
159 >
160 > export const ActiveAuxiliaryContext = new RawContextKey<string>('activeAuxiliary', '', localize('activeAuxiliary', "The identifier of the active auxiliary panel"));
161 > export const AuxiliaryBarFocusContext = new RawContextKey<boolean>('auxiliaryBarFocus', false, localize('auxiliaryBarFocus', "Whether the auxiliary bar has keyboard focus"));
162 > export const AuxiliaryBarVisibleContext = new RawContextKey<boolean>('auxiliaryBarVisible', false, localize('auxiliaryBarVisible', "Whether the auxiliary bar is visible"));
163 > export const SecondarySideBarVisibleContext = new RawContextKey<boolean>('secondarySideBarVisible', false, localize('secondarySideBarVisible', "Whether the layout surface representing the secondary side bar is visible"));
164 > export const AuxiliaryBarMaximizedContext = new RawContextKey<boolean>('auxiliaryBarMaximized', false, localize('auxiliaryBarMaximized', "Whether the auxiliary bar is maximized"));
165 >
166 > //#endregion
167 >
168 >
169 > //#region < --- Panel --- >
170 >
171 > export const ActivePanelContext = new RawContextKey<string>('activePanel', '', localize('activePanel', "The identifier of the active panel"));
172 > export const PanelFocusContext = new RawContextKey<boolean>('panelFocus', false, localize('panelFocus', "Whether the panel has keyboard focus"));
173 > export const PanelPositionContext = new RawContextKey<string>('panelPosition', 'bottom', localize('panelPosition', "The position of the panel, always 'bottom'"));
174 > export const PanelAlignmentContext = new RawContextKey<string>('panelAlignment', 'center', localize('panelAlignment', "The alignment of the panel, either 'center', 'left', 'right' or 'justify'"));
175 > export const PanelVisibleContext = new RawContextKey<boolean>('panelVisible', false, localize('panelVisible', "Whether the panel is visible"));
176 > export const PanelMaximizedContext = new RawContextKey<boolean>('panelMaximized', false, localize('panelMaximized', "Whether the panel is maximized"));
177 >
178 > //#endregion
179 >
180 >
181 > //#region < --- Views --- >
182 >
183 > export const FocusedViewContext = new RawContextKey<string>('focusedView', '', localize('focusedView', "The identifier of the view that has keyboard focus"));
184 > export function getVisbileViewContextKey(viewId: string): string { return `view.${viewId}.visible`; }
185 >
186 > //#endregion
187 >
188 >
189 > //#region < --- Resources --- >
190 >
191 > abstract class AbstractResourceContextKey {
192 >
193 > // NOTE: DO NOT CHANGE THE DEFAULT VALUE TO ANYTHING BUT
194 > // UNDEFINED! IT IS IMPORTANT THAT DEFAULTS ARE INHERITED
195 > // FROM THE PARENT CONTEXT AND ONLY UNDEFINED DOES THIS
196 >
197 > static readonly Scheme = new RawContextKey<string>('resourceScheme', undefined, { type: 'string', description: localize('resourceScheme', "The scheme of the resource") });
198 > static readonly Filename = new RawContextKey<string>('resourceFilename', undefined, { type: 'string', description: localize('resourceFilename', "The file name of the resource") });
199 > static readonly Dirname = new RawContextKey<string>('resourceDirname', undefined, { type: 'string', description: localize('resourceDirname', "The folder name the resource is contained in") });
200 > static readonly Path = new RawContextKey<string>('resourcePath', undefined, { type: 'string', description: localize('resourcePath', "The full path of the resource") });
201 > static readonly LangId = new RawContextKey<string>('resourceLangId', undefined, { type: 'string', description: localize('resourceLangId', "The language identifier of the resource") });
202 > static readonly Resource = new RawContextKey<string>('resource', undefined, { type: 'URI', description: localize('resource', "The full value of the resource including scheme and path") });
203 > static readonly Extension = new RawContextKey<string>('resourceExtname', undefined, { type: 'string', description: localize('resourceExtname', "The extension name of the resource") });
204 > static readonly HasResource = new RawContextKey<boolean>('resourceSet', undefined, { type: 'boolean', description: localize('resourceSet', "Whether a resource is present or not") });
205 > static readonly IsFileSystemResource = new RawContextKey<boolean>('isFileSystemResource', undefined, { type: 'boolean', description: localize('isFileSystemResource', "Whether the resource is backed by a file system provider") });
206 >
207 > protected _value: URI | undefined;
208 > protected readonly _resourceKey: IContextKey<string | null>;
209 > protected readonly _schemeKey: IContextKey<string | null>;
210 > protected readonly _filenameKey: IContextKey<string | null>;
211 > protected readonly _dirnameKey: IContextKey<string | null>;
212 > protected readonly _pathKey: IContextKey<string | null>;
213 > protected readonly _langIdKey: IContextKey<string | null>;
214 > protected readonly _extensionKey: IContextKey<string | null>;
215 > protected readonly _hasResource: IContextKey<boolean>;
216 > protected readonly _isFileSystemResource: IContextKey<boolean>;
217 >
218 > constructor(
219 @IContextKeyService protected readonly _contextKeyService: IContextKeyService,
220 @IFileService protected readonly _fileService: IFileService,
232 this._isFileSystemResource = AbstractResourceContextKey.IsFileSystemResource.bindTo(this._contextKeyService);
233 }
235 > protected _setLangId(): void {
236 const value = this.get();
237 if (!value) {
242 this._langIdKey.set(langId);
243 }
245 > set(value: URI | null | undefined) {
246 value = value ?? undefined;
247 if (isEqual(this._value, value)) {
261 });
262 }
264 > protected uriToPath(uri: URI): string {
265 if (uri.scheme === Schemas.file) {
266 return uri.fsPath;
268 return uri.path;
269 }
271 > reset(): void {
272 this._value = undefined;
273 this._contextKeyService.bufferChangeEvents(() => {
283 });
284 }
286 > get(): URI | undefined {
287 return this._value;
288 }
289 > } contextkeys.ts
290 >
291 > export class ResourceContextKey extends AbstractResourceContextKey {
292 >
293 > private readonly _disposables = new DisposableStore();
294 >
295 > constructor(
296 @IContextKeyService contextKeyService: IContextKeyService,
297 @IFileService fileService: IFileService,
315 }));
316 }
318 > dispose(): void {
319 this._disposables.dispose();
320 }
321 > } contextkeys.ts
322 >
323 > /**
324 > * This is a version of ResourceContextKey that is not disposable and has no listeners for model change events.
325 > * It will configure itself for the state/presence of a model only when created and not update.
326 > */
327 > export class StaticResourceContextKey extends AbstractResourceContextKey { }
328 >
329 >
330 > //#endregion
331 >
332 > export function applyAvailableEditorIds(contextKey: IContextKey<string>, editor: EditorInput | undefined | null, editorResolverService: IEditorResolverService): void {
333 if (!editor) {
334 contextKey.set('');
339 contextKey.set(editors.join(','));
340 }
342 function getAvailableEditorIds(editor: EditorInput, editorResolverService: IEditorResolverService): string[] {
343 // Non text editor untitled files cannot be easily serialized between
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/platform/theme/common/iconRegistry.ts 247 covered LOC · 15 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- iconRegistry.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { RunOnceScheduler } from '../../../base/common/async.js';
7 > import { Codicon } from '../../../base/common/codicons.js';
8 > import { getCodiconFontCharacters } from '../../../base/common/codiconsUtil.js';
9 > import { ThemeIcon, IconIdentifier } from '../../../base/common/themables.js';
10 > import { Emitter, Event } from '../../../base/common/event.js';
11 > import { IJSONSchema, IJSONSchemaMap } from '../../../base/common/jsonSchema.js';
12 > import { isString } from '../../../base/common/types.js';
13 > import { URI } from '../../../base/common/uri.js';
14 > import { localize } from '../../../nls.js';
15 > import { Extensions as JSONExtensions, IJSONContributionRegistry } from '../../jsonschemas/common/jsonContributionRegistry.js';
16 > import * as platform from '../../registry/common/platform.js';
17 > import { Disposable } from '../../../base/common/lifecycle.js';
18 >
19 > // ------ API types
20 >
21 >
22 > // icon registry
23 > export const Extensions = {
24 > IconContribution: 'base.contributions.icons'
25 > };
26 >
27 > export type IconDefaults = ThemeIcon | IconDefinition;
28 >
29 > export interface IconDefinition {
30 > readonly font?: IconFontContribution; // undefined for the default font (codicon)
31 > readonly fontCharacter: string;
32 > }
33 >
34 >
35 > export interface IconContribution {
36 > readonly id: string;
37 > description: string | undefined;
38 > readonly deprecationMessage?: string;
39 > readonly defaults: IconDefaults;
40 > }
41 >
42 > export namespace IconContribution {
43 > export function getDefinition(contribution: IconContribution, registry: IIconRegistry): IconDefinition | undefined {
44 let definition = contribution.defaults;
45 while (ThemeIcon.isThemeIcon(definition)) {
52 return definition;
53 }
55 >
56 > export interface IconFontContribution {
57 > readonly id: string;
58 > readonly definition: IconFontDefinition;
59 > }
60 >
61 > export interface IconFontDefinition {
62 > readonly weight?: string;
63 > readonly style?: string;
64 > readonly src: IconFontSource[];
65 > }
66 >
67 > export namespace IconFontDefinition {
68 > export function toJSONObject(iconFont: IconFontDefinition): any {
69 return {
70 weight: iconFont.weight,
73 };
74 }
75 > export function fromJSONObject(json: any): IconFontDefinition | undefined { iconRegistry.ts
76 const stringOrUndef = (s: any) => isString(s) ? s : undefined;
77 if (json && Array.isArray(json.src) && json.src.every((s: any) => isString(s.format) && isString(s.location))) {
84 return undefined;
85 }
87 >
88 >
89 > export interface IconFontSource {
90 > readonly location: URI;
91 > readonly format: string;
92 > }
93 >
94 > export interface IIconRegistry {
95 >
96 > readonly onDidChange: Event<void>;
97 >
98 > /**
99 > * Register a icon to the registry.
100 > * @param id The icon id
101 > * @param defaults The default values
102 > * @param description The description
103 > */
104 > registerIcon(id: IconIdentifier, defaults: IconDefaults, description?: string): ThemeIcon;
105 >
106 > /**
107 > * Deregister a icon from the registry.
108 > */
109 > deregisterIcon(id: IconIdentifier): void;
110 >
111 > /**
112 > * Get all icon contributions
113 > */
114 > getIcons(): IconContribution[];
115 >
116 > /**
117 > * Get the icon for the given id
118 > */
119 > getIcon(id: IconIdentifier): IconContribution | undefined;
120 >
121 > /**
122 > * JSON schema for an object to assign icon values to one of the icon contributions.
123 > */
124 > getIconSchema(): IJSONSchema;
125 >
126 > /**
127 > * JSON schema to for a reference to a icon contribution.
128 > */
129 > getIconReferenceSchema(): IJSONSchema;
130 >
131 > /**
132 > * Register a icon font to the registry.
133 > * @param id The icon font id
134 > * @param definition The icon font definition
135 > */
136 > registerIconFont(id: string, definition: IconFontDefinition): IconFontDefinition;
137 >
138 > /**
139 > * Deregister an icon font to the registry.
140 > */
141 > deregisterIconFont(id: string): void;
142 >
143 > /**
144 > * Get the icon font for the given id
145 > */
146 > getIconFont(id: string): IconFontDefinition | undefined;
147 > }
148 >
149 > // regexes for validation of font properties
150 >
151 > export const fontIdRegex = /^([\w_-]+)$/;
152 > export const fontStyleRegex = /^(normal|italic|(oblique[ \w\s-]+))$/;
153 > export const fontWeightRegex = /^(normal|bold|lighter|bolder|(\d{0-1000}))$/;
154 > export const fontSizeRegex = /^([\w_.%+-]+)$/;
155 > export const fontFormatRegex = /^woff|woff2|truetype|opentype|embedded-opentype|svg$/;
156 > export const fontColorRegex = /^#[0-9a-fA-F]{0,6}$/;
157 >
158 > export const fontIdErrorMessage = localize('schema.fontId.formatError', 'The font ID must only contain letters, numbers, underscores and dashes.');
159 >
160 > class IconRegistry extends Disposable implements IIconRegistry {
161 >
162 > private readonly _onDidChange = this._register(new Emitter<void>());
163 > readonly onDidChange: Event<void> = this._onDidChange.event;
164 >
165 > private iconsById: { [key: string]: IconContribution };
166 > private iconSchema: IJSONSchema & { properties: IJSONSchemaMap } = {
167 > definitions: {
168 > icons: {
169 > type: 'object',
170 > properties: {
171 > fontId: { type: 'string', description: localize('iconDefinition.fontId', 'The id of the font to use. If not set, the font that is defined first is used.'), pattern: fontIdRegex.source, patternErrorMessage: fontIdErrorMessage },
172 > fontCharacter: { type: 'string', description: localize('iconDefinition.fontCharacter', 'The font character associated with the icon definition.') }
173 > },
174 > additionalProperties: false,
175 > defaultSnippets: [{ body: { fontCharacter: '\\\\e030' } }]
176 > }
177 > },
178 > type: 'object',
179 > properties: {}
180 > };
181 > private iconReferenceSchema: IJSONSchema & { enum: string[]; enumDescriptions: string[] } = { type: 'string', pattern: `^${ThemeIcon.iconNameExpression}$`, enum: [], enumDescriptions: [] };
182 >
183 > private iconFontsById: { [key: string]: IconFontDefinition };
184 >
185 > constructor() {
186 > super();
187 > this.iconsById = {};
188 > this.iconFontsById = {};
189 > }
190 >
191 > public registerIcon(id: string, defaults: IconDefaults, description?: string, deprecationMessage?: string): ThemeIcon {
192 > const existing = this.iconsById[id];
193 > if (existing) {
194 if (description && !existing.description) {
195 existing.description = description;
203 return existing;
204 }
205 > const iconContribution: IconContribution = { id, description, defaults, deprecationMessage }; iconRegistry.ts
206 > this.iconsById[id] = iconContribution;
207 > const propertySchema: IJSONSchema = { $ref: '#/definitions/icons' };
208 > if (deprecationMessage) {
209 propertySchema.deprecationMessage = deprecationMessage;
210 }
211 > if (description) { iconRegistry.ts
212 > propertySchema.markdownDescription = `${description}: $(${id})`;
213 > }
214 > this.iconSchema.properties[id] = propertySchema;
215 > this.iconReferenceSchema.enum.push(id);
216 > this.iconReferenceSchema.enumDescriptions.push(description || '');
217 >
218 > this._onDidChange.fire();
219 > return { id };
220 > }
221 >
222 >
223 > public deregisterIcon(id: string): void {
224 delete this.iconsById[id];
225 delete this.iconSchema.properties[id];
231 this._onDidChange.fire();
232 }
234 > public getIcons(): IconContribution[] {
235 return Object.keys(this.iconsById).map(id => this.iconsById[id]);
236 }
238 > public getIcon(id: string): IconContribution | undefined {
239 return this.iconsById[id];
240 }
242 > public getIconSchema(): IJSONSchema {
243 > return this.iconSchema;
244 > }
245 >
246 > public getIconReferenceSchema(): IJSONSchema {
247 return this.iconReferenceSchema;
248 }
250 > public registerIconFont(id: string, definition: IconFontDefinition): IconFontDefinition {
251 const existing = this.iconFontsById[id];
252 if (existing) {
257 return definition;
258 }
260 > public deregisterIconFont(id: string): void {
261 delete this.iconFontsById[id];
262 }
264 > public getIconFont(id: string): IconFontDefinition | undefined {
265 return this.iconFontsById[id];
266 }
268 > public override toString() {
269 const sorter = (i1: IconContribution, i2: IconContribution) => {
270 return i1.id.localeCompare(i2.id);
297 return reference.join('\n');
298 }
300 > }
301 >
302 > const iconRegistry = new IconRegistry();
303 > platform.Registry.add(Extensions.IconContribution, iconRegistry);
304 >
305 > export function registerIcon(id: string, defaults: IconDefaults, description: string, deprecationMessage?: string): ThemeIcon {
306 > return iconRegistry.registerIcon(id, defaults, description, deprecationMessage);
307 > }
308 >
309 > export function getIconRegistry(): IIconRegistry {
310 return iconRegistry;
311 }
313 > function initialize() {
314 > const codiconFontCharacters = getCodiconFontCharacters();
315 > for (const icon in codiconFontCharacters) {
316 > const fontCharacter = '\\' + codiconFontCharacters[icon].toString(16);
317 > iconRegistry.registerIcon(icon, { fontCharacter });
318 > }
319 > }
320 > initialize();
321 >
322 > export const iconsSchemaId = 'vscode://schemas/icons';
323 >
324 > const schemaRegistry = platform.Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution);
325 > schemaRegistry.registerSchema(iconsSchemaId, iconRegistry.getIconSchema());
326 >
327 > const delayer = new RunOnceScheduler(() => schemaRegistry.notifySchemaChanged(iconsSchemaId), 200);
328 > iconRegistry.onDidChange(() => {
329 > if (!delayer.isScheduled()) {
330 > delayer.schedule();
331 > }
332 > });
333 >
334 > //setTimeout(_ => console.log(iconRegistry.toString()), 5000);
335 >
336 >
337 > // common icons
338 >
339 > export const widgetClose = registerIcon('widget-close', Codicon.close, localize('widgetClose', 'Icon for the close action in widgets.'));
340 >
341 > export const gotoPreviousLocation = registerIcon('goto-previous-location', Codicon.arrowUp, localize('previousChangeIcon', 'Icon for goto previous editor location.'));
342 > export const gotoNextLocation = registerIcon('goto-next-location', Codicon.arrowDown, localize('nextChangeIcon', 'Icon for goto next editor location.'));
343 >
344 > export const syncing = ThemeIcon.modify(Codicon.sync, 'spin');
345 > export const spinningLoading = ThemeIcon.modify(Codicon.loading, 'spin');
src/vs/platform/agentHost/common/state/protocol/channels-root/state.ts 244 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- state.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > // allow-any-unicode-comment-file
7 > // DO NOT EDIT -- auto-generated by scripts/sync-agent-host-protocol.ts
8 >
9 > import type { ConfigSchema, JsonPrimitive, ProtectedResourceMetadata } from '../common/state.js';
10 > import type { TerminalInfo } from '../channels-terminal/state.js';
11 > import type { Customization } from '../channels-session/state.js';
12 >
13 > // ─── Root State ──────────────────────────────────────────────────────────────
14 >
15 > /**
16 > * Policy configuration state for a model.
17 > *
18 > * @category Root State
19 > */
20 > export const enum PolicyState {
21 > Enabled = 'enabled',
22 > Disabled = 'disabled',
23 > Unconfigured = 'unconfigured',
24 > }
25 >
26 > /**
27 > * Global state shared with every client subscribed to `ahp-root://`.
28 > *
29 > * @category Root State
30 > */
31 > export interface RootState {
32 > /** Available agent backends and their models */
33 > agents: AgentInfo[];
34 > /** Number of active (non-disposed) sessions on the server */
35 > activeSessions?: number;
36 > /** Known terminals on the server. Subscribe to individual terminal URIs for full state. */
37 > terminals?: TerminalInfo[];
38 > /** Agent host configuration schema and current values */
39 > config?: RootConfigState;
40 > /**
41 > * Additional implementation-defined metadata about the agent host itself.
42 > *
43 > * Clients MAY look for well-known keys here to provide enhanced UI.
44 > */
45 > _meta?: Record<string, unknown>;
46 > }
47 >
48 > /**
49 > * @category Root State
50 > */
51 > export interface AgentInfo {
52 > /** Agent provider ID (e.g. `'copilot'`) */
53 > provider: string;
54 > /** Human-readable name */
55 > displayName: string;
56 > /** Description string */
57 > description: string;
58 > /** Available models for this agent */
59 > models: SessionModelInfo[];
60 > /**
61 > * Protected resources this agent requires authentication for.
62 > *
63 > * Each entry describes an OAuth 2.0 protected resource using
64 > * [RFC 9728](https://datatracker.ietf.org/doc/html/rfc9728) semantics.
65 > * Clients should obtain tokens from the declared `authorization_servers`
66 > * and push them via the `authenticate` command before creating sessions
67 > * with this agent.
68 > *
69 > * @see {@link /specification/authentication | Authentication}
70 > */
71 > protectedResources?: ProtectedResourceMetadata[];
72 > /**
73 > * Customizations associated with this agent.
74 > *
75 > * Either container customizations —
76 > * {@link PluginCustomization | `PluginCustomization`} entries the agent
77 > * bundles, plus {@link DirectoryCustomization | `DirectoryCustomization`}
78 > * entries it watches in any workspace it's used with — or top-level
79 > * {@link McpServerCustomization | `McpServerCustomization`} entries
80 > * the agent host declares directly. When a session is created with
81 > * this agent, these entries are augmented (e.g. directory URIs are
82 > * resolved against the workspace, children are parsed) and propagated
83 > * into the session's `customizations` list.
84 > */
85 > customizations?: Customization[];
86 > /**
87 > * Static capabilities the agent advertises about itself. Clients use these
88 > * to gate features (multi-chat, fork) instead of switching on the provider
89 > * id.
90 > */
91 > capabilities?: AgentCapabilities;
92 > }
93 >
94 > /**
95 > * Static capabilities an {@link AgentInfo} advertises. Modelled after MCP
96 > * capabilities: each field is opt-in and its presence (an empty object `{}`)
97 > * signals support, while absence means the feature is unsupported and the
98 > * corresponding client commands MUST NOT be used. Sub-fields carry
99 > * per-capability options.
100 > *
101 > * @category Root State
102 > */
103 > export interface AgentCapabilities {
104 > /**
105 > * The agent can host more than one concurrent chat per session. When absent,
106 > * clients MUST NOT call `createChat` to open chats beyond the default one the
107 > * session starts with. An empty object `{}` advertises multi-chat without
108 > * source-based creation; set {@link MultipleChatsCapability.fork} or
109 > * {@link MultipleChatsCapability.sideChat} to allow the corresponding mode.
110 > */
111 > multipleChats?: MultipleChatsCapability;
112 > /**
113 > * The session's agent can be granted tool access to more than one working
114 > * directory. The directories are treated as equal peers except where the
115 > * agent advertises {@link MultipleWorkingDirectoriesCapability.requiresPrimary}
116 > * (some backends need one directory designated as a primary root).
117 > *
118 > * When absent, clients MUST NOT mutate a session's or chat's working-directory
119 > * set and MUST NOT set more than one entry in
120 > * {@link CreateSessionParams.workingDirectories}.
121 > */
122 > multipleWorkingDirectories?: MultipleWorkingDirectoriesCapability;
123 > }
124 >
125 > /**
126 > * Options for the {@link AgentCapabilities.multipleChats} capability.
127 > *
128 > * @category Root State
129 > */
130 > export interface MultipleChatsCapability {
131 > /**
132 > * The agent can fork a chat from a specific turn. When absent or `false`,
133 > * clients MUST NOT pass a {@link ChatSource} with `kind: "fork"` to
134 > * `createChat`.
135 > * Forking always implies multi-chat support.
136 > */
137 > fork?: boolean;
138 > /**
139 > * The agent can create a side chat from a specific turn. When absent or
140 > * `false`, clients MUST NOT pass a {@link ChatSource} with
141 > * `kind: "sideChat"` to `createChat`.
142 > *
143 > * A side chat receives the source turn as context without copying the source
144 > * transcript into its own visible history. The source is identified by a
145 > * stable `turnId`, which the host resolves against the source chat's current
146 > * `activeTurn` or retained history. When it names the current active turn,
147 > * the host snapshots the available partial assistant response at creation
148 > * time. Side-chat support always implies multi-chat support.
149 > */
150 > sideChat?: boolean;
151 > }
152 >
153 > /**
154 > * Options for the {@link AgentCapabilities.multipleWorkingDirectories} capability.
155 > *
156 > * @category Root State
157 > */
158 > export interface MultipleWorkingDirectoriesCapability {
159 > /**
160 > * The agent requires each chat to designate one of its working directories as
161 > * the **primary** — a distinguished root the chat is centered on (e.g. the
162 > * agent's process root for that chat, the default location for relative
163 > * paths). Primary is a **per-chat** notion, fixed at chat creation. When
164 > * `true`, a client SHOULD supply {@link CreateChatParams.primaryWorkingDirectory}
165 > * (and {@link CreateSessionParams.primaryWorkingDirectory}, which seeds the
166 > * session's default chat); a host MAY reject creation that omits it, or fall
167 > * back to the first entry of the chat's working directories. The chosen
168 > * primary is reported (read-only) on {@link ChatState.primaryWorkingDirectory}.
169 > *
170 > * When absent or `false`, the agent has no primary — all directories are
171 > * equal peers and clients need not designate one.
172 > */
173 > requiresPrimary?: boolean;
174 > }
175 >
176 > /**
177 > * @category Root State
178 > */
179 > export interface SessionModelInfo {
180 > /** Model identifier */
181 > id: string;
182 > /** Provider this model belongs to */
183 > provider: string;
184 > /** Human-readable model name */
185 > name: string;
186 > /** Maximum context window size */
187 > maxContextWindow?: number;
188 > /** Maximum number of output tokens the model can generate */
189 > maxOutputTokens?: number;
190 > /** Maximum number of prompt (input) tokens the model accepts */
191 > maxPromptTokens?: number;
192 > /** Whether the model supports vision */
193 > supportsVision?: boolean;
194 > /** Policy configuration state */
195 > policyState?: PolicyState;
196 > /**
197 > * Configuration schema describing model-specific options (e.g. thinking
198 > * level). Clients present this as a form and pass the resolved values in
199 > * {@link ModelSelection.config} when creating or changing sessions.
200 > */
201 > configSchema?: ConfigSchema;
202 > /**
203 > * Additional provider-specific metadata for this model.
204 > *
205 > * Clients MAY look for well-known keys here to provide enhanced UI.
206 > * For example, a `pricing` key may carry model pricing metadata.
207 > */
208 > _meta?: Record<string, unknown>;
209 > }
210 >
211 > /**
212 > * A model selection: the chosen model ID together with any model-specific
213 > * configuration values whose keys correspond to the model's
214 > * {@link SessionModelInfo.configSchema}.
215 > *
216 > * @category Root State
217 > */
218 > export interface ModelSelection {
219 > /** Model identifier */
220 > id: string;
221 > /**
222 > * Model-specific configuration values. Values are JSON primitives: most
223 > * pickers produce strings, but some (e.g. a numeric context-size picker)
224 > * produce numbers or booleans, which are carried through as-is.
225 > */
226 > config?: Record<string, JsonPrimitive>;
227 > }
228 >
229 > // ─── Root Config Types ───────────────────────────────────────────────────────
230 >
231 > /**
232 > * Live agent-host configuration metadata.
233 > *
234 > * The schema describes the available configuration properties and the values
235 > * contain the current value for each resolved property.
236 > *
237 > * @category Root State
238 > */
239 > export interface RootConfigState {
240 > /** JSON Schema describing available configuration properties */
241 > schema: ConfigSchema;
242 > /** Current configuration values */
243 > values: Record<string, unknown>;
244 > }
src/vs/platform/tunnel/common/tunnel.ts 230 covered LOC · 33 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- tunnel.ts
2 > * Copyright (c) Microsoft 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 { Emitter, Event } from '../../../base/common/event.js';
8 > import { IDisposable, Disposable } from '../../../base/common/lifecycle.js';
9 > import { OperatingSystem } from '../../../base/common/platform.js';
10 > import { URI } from '../../../base/common/uri.js';
11 > import { IConfigurationService } from '../../configuration/common/configuration.js';
12 > import { createDecorator } from '../../instantiation/common/instantiation.js';
13 > import { ILogService } from '../../log/common/log.js';
14 > import { IAddressProvider } from '../../remote/common/remoteAgentConnection.js';
15 > import { TunnelPrivacy } from '../../remote/common/remoteAuthorityResolver.js';
16 >
17 > export const ITunnelService = createDecorator<ITunnelService>('tunnelService');
18 > export const ISharedTunnelsService = createDecorator<ISharedTunnelsService>('sharedTunnelsService');
19 >
20 > export interface RemoteTunnel {
21 > readonly tunnelRemotePort: number;
22 > readonly tunnelRemoteHost: string;
23 > readonly tunnelLocalPort?: number;
24 > readonly localAddress: string;
25 > readonly privacy: string;
26 > readonly protocol?: string;
27 > dispose(silent?: boolean): Promise<void>;
28 > }
29 >
30 > export function isRemoteTunnel(something: unknown): something is RemoteTunnel {
31 const asTunnel: Partial<RemoteTunnel> = something as Partial<RemoteTunnel>;
32 return !!(asTunnel.tunnelRemotePort && asTunnel.tunnelRemoteHost && asTunnel.localAddress && asTunnel.privacy && asTunnel.dispose);
33 }
34 > tunnel.ts
35 > export interface TunnelOptions {
36 > remoteAddress: { port: number; host: string };
37 > localAddressPort?: number;
38 > label?: string;
39 > public?: boolean;
40 > privacy?: string;
41 > protocol?: string;
42 > }
43 >
44 > export enum TunnelProtocol {
45 > Http = 'http',
46 > Https = 'https'
47 > }
48 >
49 > export enum TunnelPrivacyId {
50 > ConstantPrivate = 'constantPrivate', // private, and changing is unsupported
51 > Private = 'private',
52 > Public = 'public'
53 > }
54 >
55 > export interface TunnelCreationOptions {
56 > elevationRequired?: boolean;
57 > }
58 >
59 > export interface TunnelProviderFeatures {
60 > elevation: boolean;
61 > /**
62 > * @deprecated
63 > */
64 > public?: boolean;
65 > privacyOptions: TunnelPrivacy[];
66 > protocol: boolean;
67 > }
68 >
69 > export interface ITunnelProvider {
70 > forwardPort(tunnelOptions: TunnelOptions, tunnelCreationOptions: TunnelCreationOptions): Promise<RemoteTunnel | string | undefined> | undefined;
71 > }
72 >
73 > export function isTunnelProvider(addressOrTunnelProvider: IAddressProvider | ITunnelProvider): addressOrTunnelProvider is ITunnelProvider {
74 return !!(addressOrTunnelProvider as ITunnelProvider).forwardPort;
75 }
76 > tunnel.ts
77 > export enum ProvidedOnAutoForward {
78 > Notify = 1,
79 > OpenBrowser = 2,
80 > OpenPreview = 3,
81 > Silent = 4,
82 > Ignore = 5,
83 > OpenBrowserOnce = 6
84 > }
85 >
86 > export interface ProvidedPortAttributes {
87 > port: number;
88 > autoForwardAction: ProvidedOnAutoForward;
89 > }
90 >
91 > export interface PortAttributesProvider {
92 > providePortAttributes(ports: number[], pid: number | undefined, commandLine: string | undefined, token: CancellationToken): Promise<ProvidedPortAttributes[]>;
93 > }
94 >
95 > export interface ITunnel {
96 > remoteAddress: { port: number; host: string };
97 >
98 > /**
99 > * The complete local address(ex. localhost:1234)
100 > */
101 > localAddress: string;
102 >
103 > /**
104 > * @deprecated Use privacy instead
105 > */
106 > public?: boolean;
107 >
108 > privacy?: string;
109 >
110 > protocol?: string;
111 >
112 > /**
113 > * Implementers of Tunnel should fire onDidDispose when dispose is called.
114 > */
115 > readonly onDidDispose: Event<void>;
116 >
117 > dispose(): Promise<void> | void;
118 > }
119 >
120 > export interface ISharedTunnelsService {
121 > readonly _serviceBrand: undefined;
122 >
123 > openTunnel(authority: string, addressProvider: IAddressProvider | undefined, remoteHost: string | undefined, remotePort: number, localHost: string, localPort?: number, elevateIfNeeded?: boolean, privacy?: string, protocol?: string): Promise<RemoteTunnel | string | undefined> | undefined;
124 > }
125 >
126 > export interface ITunnelService {
127 > readonly _serviceBrand: undefined;
128 >
129 > readonly tunnels: Promise<readonly RemoteTunnel[]>;
130 > readonly canChangePrivacy: boolean;
131 > readonly privacyOptions: TunnelPrivacy[];
132 > readonly onTunnelOpened: Event<RemoteTunnel>;
133 > readonly onTunnelClosed: Event<{ host: string; port: number }>;
134 > readonly canElevate: boolean;
135 > readonly canChangeProtocol: boolean;
136 > readonly hasTunnelProvider: boolean;
137 > readonly onAddedTunnelProvider: Event<void>;
138 >
139 > canTunnel(uri: URI): boolean;
140 > openTunnel(addressProvider: IAddressProvider | undefined, remoteHost: string | undefined, remotePort: number, localHost?: string, localPort?: number, elevateIfNeeded?: boolean, privacy?: string, protocol?: string): Promise<RemoteTunnel | string | undefined> | undefined;
141 > getExistingTunnel(remoteHost: string, remotePort: number): Promise<RemoteTunnel | string | undefined>;
142 > setEnvironmentTunnel(remoteHost: string, remotePort: number, localAddress: string, privacy: string, protocol: string): void;
143 > closeTunnel(remoteHost: string, remotePort: number): Promise<void>;
144 > setTunnelProvider(provider: ITunnelProvider | undefined): IDisposable;
145 > setTunnelFeatures(features: TunnelProviderFeatures): void;
146 > isPortPrivileged(port: number): boolean;
147 > }
148 >
149 > export function extractLocalHostUriMetaDataForPortMapping(uri: URI): { address: string; port: number } | undefined {
150 if (uri.scheme !== 'http' && uri.scheme !== 'https') {
151 return undefined;
160 };
161 }
162 > tunnel.ts
163 > export function extractQueryLocalHostUriMetaDataForPortMapping(uri: URI): { address: string; port: number } | undefined {
164 if (uri.scheme !== 'http' && uri.scheme !== 'https' || !uri.query) {
165 return undefined;
177 return undefined;
178 }
179 > tunnel.ts
180 > export const LOCALHOST_ADDRESSES = ['localhost', '127.0.0.1', '0:0:0:0:0:0:0:1', '::1'];
181 > export function isLocalhost(host: string): boolean {
182 return LOCALHOST_ADDRESSES.indexOf(host) >= 0;
183 }
184 > tunnel.ts
185 > export const ALL_INTERFACES_ADDRESSES = ['0.0.0.0', '0:0:0:0:0:0:0:0', '::'];
186 > export function isAllInterfaces(host: string): boolean {
187 return ALL_INTERFACES_ADDRESSES.indexOf(host) >= 0;
188 }
189 > tunnel.ts
190 > export function isPortPrivileged(port: number, host: string, os: OperatingSystem, osRelease: string): boolean {
191 if (os === OperatingSystem.Windows) {
192 return false;
205 return port < 1024;
206 }
207 > tunnel.ts
208 > export class DisposableTunnel {
209 > private _onDispose: Emitter<void> = new Emitter();
210 > readonly onDidDispose: Event<void> = this._onDispose.event;
211 >
212 > constructor(
213 public readonly remoteAddress: { port: number; host: string },
214 public readonly localAddress: { port: number; host: string } | string,
215 private readonly _dispose: () => Promise<void>) { }
216 > tunnel.ts
217 > dispose(): Promise<void> {
218 this._onDispose.fire();
219 this._onDispose.dispose();
220 return this._dispose();
221 }
222 > } tunnel.ts
223 >
224 > export abstract class AbstractTunnelService extends Disposable implements ITunnelService {
225 > declare readonly _serviceBrand: undefined;
226 >
227 > private _onTunnelOpened = this._register(new Emitter<RemoteTunnel>());
228 > public onTunnelOpened: Event<RemoteTunnel> = this._onTunnelOpened.event;
229 > private _onTunnelClosed = this._register(new Emitter<{ host: string; port: number }>());
230 > public onTunnelClosed: Event<{ host: string; port: number }> = this._onTunnelClosed.event;
231 > private _onAddedTunnelProvider = this._register(new Emitter<void>());
232 > public onAddedTunnelProvider: Event<void> = this._onAddedTunnelProvider.event;
233 > protected readonly _tunnels = new Map</*host*/ string, Map</* port */ number, { refcount: number; readonly value: Promise<RemoteTunnel | string | undefined> }>>();
234 > protected _tunnelProvider: ITunnelProvider | undefined;
235 > protected _canElevate: boolean = false;
236 > private _canChangeProtocol: boolean = true;
237 > private _privacyOptions: TunnelPrivacy[] = [];
238 > private _factoryInProgress: Set<number/*port*/> = new Set();
239 >
240 > public constructor(
241 @ILogService protected readonly logService: ILogService,
242 @IConfigurationService protected readonly configurationService: IConfigurationService
243 ) { super(); }
244 > tunnel.ts
245 > get hasTunnelProvider(): boolean {
246 return !!this._tunnelProvider;
247 }
248 > tunnel.ts
249 > protected get defaultTunnelHost(): string {
250 const settingValue = this.configurationService.getValue('remote.localPortHost');
251 return (!settingValue || settingValue === 'localhost') ? '127.0.0.1' : '0.0.0.0';
252 }
253 > tunnel.ts
254 > setTunnelProvider(provider: ITunnelProvider | undefined): IDisposable {
255 this._tunnelProvider = provider;
256 if (!provider) {
273 };
274 }
275 > tunnel.ts
276 > setTunnelFeatures(features: TunnelProviderFeatures): void {
277 this._canElevate = features.elevation;
278 this._privacyOptions = features.privacyOptions;
279 this._canChangeProtocol = features.protocol;
280 }
281 > tunnel.ts
282 > public get canChangeProtocol(): boolean {
283 return this._canChangeProtocol;
284 }
285 > tunnel.ts
286 > public get canElevate(): boolean {
287 return this._canElevate;
288 }
289 > tunnel.ts
290 > public get canChangePrivacy() {
291 return this._privacyOptions.length > 0;
292 }
293 > tunnel.ts
294 > public get privacyOptions() {
295 return this._privacyOptions;
296 }
297 > tunnel.ts
298 > public get tunnels(): Promise<readonly RemoteTunnel[]> {
299 return this.getTunnels();
300 }
301 > tunnel.ts
302 > private async getTunnels(): Promise<readonly RemoteTunnel[]> {
303 const tunnels: RemoteTunnel[] = [];
304 const tunnelArray = Array.from(this._tunnels.values());
314 return tunnels;
315 }
316 > tunnel.ts
317 > override async dispose(): Promise<void> {
318 super.dispose();
319 for (const portMap of this._tunnels.values()) {
325 this._tunnels.clear();
326 }
327 > tunnel.ts
328 > setEnvironmentTunnel(remoteHost: string, remotePort: number, localAddress: string, privacy: string, protocol: string): void {
329 this.addTunnelToMap(remoteHost, remotePort, Promise.resolve({
330 tunnelRemoteHost: remoteHost,
336 }));
337 }
338 > tunnel.ts
339 > async getExistingTunnel(remoteHost: string, remotePort: number): Promise<RemoteTunnel | string | undefined> {
340 if (isAllInterfaces(remoteHost) || isLocalhost(remoteHost)) {
341 remoteHost = LOCALHOST_ADDRESSES[0];
349 return undefined;
350 }
351 > tunnel.ts
352 > openTunnel(addressProvider: IAddressProvider | undefined, remoteHost: string | undefined, remotePort: number, localHost?: string, localPort?: number, elevateIfNeeded: boolean = false, privacy?: string, protocol?: string): Promise<RemoteTunnel | string | undefined> | undefined {
353 this.logService.trace(`ForwardedPorts: (TunnelService) openTunnel request for ${remoteHost}:${remotePort} on local port ${localPort}.`);
354 const addressOrTunnelProvider = this._tunnelProvider ?? addressProvider;
398 });
399 }
400 > tunnel.ts
401 > private makeTunnel(tunnel: RemoteTunnel): RemoteTunnel {
402 return {
403 tunnelRemotePort: tunnel.tunnelRemotePort,
420 };
421 }
422 > tunnel.ts
423 > private async tryDisposeTunnel(remoteHost: string, remotePort: number, tunnel: { refcount: number; readonly value: Promise<RemoteTunnel | string | undefined> }): Promise<void> {
424 if (tunnel.refcount <= 0) {
425 this.logService.trace(`ForwardedPorts: (TunnelService) Tunnel is being disposed ${remoteHost}:${remotePort}.`);
436 }
437 }
438 > tunnel.ts
439 > async closeTunnel(remoteHost: string, remotePort: number): Promise<void> {
440 this.logService.trace(`ForwardedPorts: (TunnelService) close request for ${remoteHost}:${remotePort} `);
441 const portMap = this._tunnels.get(remoteHost);
446 }
447 }
448 > tunnel.ts
449 > protected addTunnelToMap(remoteHost: string, remotePort: number, tunnel: Promise<RemoteTunnel | string | undefined>) {
450 if (!this._tunnels.has(remoteHost)) {
451 this._tunnels.set(remoteHost, new Map());
453 this._tunnels.get(remoteHost)!.set(remotePort, { refcount: 1, value: tunnel });
454 }
455 > tunnel.ts
456 > private async removeEmptyOrErrorTunnelFromMap(remoteHost: string, remotePort: number) {
457 const hostMap = this._tunnels.get(remoteHost);
458 if (hostMap) {
467 }
468 }
469 > tunnel.ts
470 > protected getTunnelFromMap(remoteHost: string, remotePort: number): { refcount: number; readonly value: Promise<RemoteTunnel | string | undefined> } | undefined {
471 const hosts = [remoteHost];
472 // Order matters. We want the original host to be first.
489 return undefined;
490 }
491 > tunnel.ts
492 > canTunnel(uri: URI): boolean {
493 return !!extractLocalHostUriMetaDataForPortMapping(uri);
494 }
495 > tunnel.ts
496 > public abstract isPortPrivileged(port: number): boolean;
497 >
498 > protected abstract retainOrCreateTunnel(addressProvider: IAddressProvider | ITunnelProvider, remoteHost: string, remotePort: number, localHost: string, localPort: number | undefined, elevateIfNeeded: boolean, privacy?: string, protocol?: string): Promise<RemoteTunnel | string | undefined> | undefined;
499 >
500 > protected createWithProvider(tunnelProvider: ITunnelProvider, remoteHost: string, remotePort: number, localPort: number | undefined, elevateIfNeeded: boolean, privacy?: string, protocol?: string): Promise<RemoteTunnel | string | undefined> | undefined {
501 this.logService.trace(`ForwardedPorts: (TunnelService) Creating tunnel with provider ${remoteHost}:${remotePort} on local port ${localPort}.`);
502 const key = remotePort;
src/vs/nls.ts 224 covered LOC · 19 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; nls.ts
143 > if (typeof data === 'number') {
144 message = lookupMessage(data, originalMessage);
145 > } else { nls.ts
146 > message = originalMessage;
147 > }
148 >
149 > const value = _format(message, args);
150 >
151 > return {
152 > value,
153 > original: originalMessage === message ? value : _format(originalMessage, args)
154 > };
155 > }
156 > nls.ts
157 > export interface INLSLanguagePackConfiguration {
158 >
159 > /**
160 > * The path to the translations config file that contains pointers to
161 > * all message bundles for `main` and extensions.
162 > */
163 > readonly translationsConfigFile: string;
164 >
165 > /**
166 > * The path to the file containing the translations for this language
167 > * pack as flat string array.
168 > */
169 > readonly messagesFile: string;
170 >
171 > /**
172 > * The path to the file that can be used to signal a corrupt language
173 > * pack, for example when reading the `messagesFile` fails. This will
174 > * instruct the application to re-create the cache on next startup.
175 > */
176 > readonly corruptMarkerFile: string;
177 > }
178 >
179 > export interface INLSConfiguration {
180 >
181 > /**
182 > * Locale as defined in `argv.json` or `app.getLocale()`.
183 > */
184 > readonly userLocale: string;
185 >
186 > /**
187 > * Locale as defined by the OS (e.g. `app.getPreferredSystemLanguages()`).
188 > */
189 > readonly osLocale: string;
190 >
191 > /**
192 > * The actual language of the UI that ends up being used considering `userLocale`
193 > * and `osLocale`.
194 > */
195 > readonly resolvedLanguage: string;
196 >
197 > /**
198 > * Defined if a language pack is used that is not the
199 > * default english language pack. This requires a language
200 > * pack to be installed as extension.
201 > */
202 > readonly languagePack?: INLSLanguagePackConfiguration;
203 >
204 > /**
205 > * The path to the file containing the default english messages
206 > * as flat string array. The file is only present in built
207 > * versions of the application.
208 > */
209 > readonly defaultMessagesFile: string;
210 >
211 > /**
212 > * Below properties are deprecated and only there to continue support
213 > * for `vscode-nls` module that depends on them.
214 > * Refs https://github.com/microsoft/vscode-nls/blob/main/src/node/main.ts#L36-L46
215 > */
216 > /** @deprecated */
217 > readonly locale: string;
218 > /** @deprecated */
219 > readonly availableLanguages: Record<string, string>;
220 > /** @deprecated */
221 > readonly _languagePackSupport?: boolean;
222 > /** @deprecated */
223 > readonly _languagePackId?: string;
224 > /** @deprecated */
225 > readonly _translationsConfigFile?: string;
226 > /** @deprecated */
227 > readonly _cacheRoot?: string;
228 > /** @deprecated */
229 > readonly _resolvedLanguagePackCoreLocation?: string;
230 > /** @deprecated */
231 > readonly _corruptedFile?: string;
232 > }
233 >
234 > export interface ILanguagePack {
235 > readonly hash: string;
236 > readonly label: string | undefined;
237 > readonly extensions: {
238 > readonly extensionIdentifier: { readonly id: string; readonly uuid?: string };
239 > readonly version: string;
240 > }[];
241 > readonly translations: Record<string, string | undefined>;
242 > }
243 >
244 > export type ILanguagePacks = Record<string, ILanguagePack | undefined>;
src/vs/base/common/filters.ts 212 covered LOC · 47 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- filters.ts
2 > * Copyright (c) Microsoft 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 { LRUCache } from './map.js';
8 > import { getKoreanAltChars } from './naturalLanguage/korean.js';
9 > import { tryNormalizeToBase } from './normalization.js';
10 > import * as strings from './strings.js';
11 >
12 > export interface IFilter {
13 > // Returns null if word doesn't match.
14 > (word: string, wordToMatchAgainst: string): IMatch[] | null;
15 > }
16 >
17 > export interface IMatch {
18 > start: number;
19 > end: number;
20 > }
21 >
22 > // Combined filters
23 >
24 > /**
25 > * @returns A filter which combines the provided set
26 > * of filters with an or. The *first* filters that
27 > * matches defined the return value of the returned
28 > * filter.
29 > */
30 > export function or(...filter: IFilter[]): IFilter {
31 > return function (word: string, wordToMatchAgainst: string): IMatch[] | null {
32 for (let i = 0, len = filter.length; i < len; i++) {
33 const match = filter[i](word, wordToMatchAgainst);
38 return null;
39 };
40 > } filters.ts
41 >
42 > // Prefix
43 >
44 > export const matchesStrictPrefix: IFilter = _matchesPrefix.bind(undefined, false);
45 > export const matchesPrefix: IFilter = _matchesPrefix.bind(undefined, true);
46 >
47 function _matchesPrefix(ignoreCase: boolean, word: string, wordToMatchAgainst: string): IMatch[] | null {
48 if (!wordToMatchAgainst || wordToMatchAgainst.length < word.length) {
63 return word.length > 0 ? [{ start: 0, end: word.length }] : [];
64 }
65 > filters.ts
66 > // Contiguous Substring
67 >
68 > export function matchesContiguousSubString(word: string, wordToMatchAgainst: string): IMatch[] | null {
69 if (word.length > wordToMatchAgainst.length) {
70 return null;
78 return [{ start: index, end: index + word.length }];
79 }
80 > filters.ts
81 > export function matchesBaseContiguousSubString(word: string, wordToMatchAgainst: string): IMatch[] | null {
82 if (word.length > wordToMatchAgainst.length) {
83 return null;
93 return [{ start: index, end: index + word.length }];
94 }
95 > filters.ts
96 > // Substring
97 >
98 > export function matchesSubString(word: string, wordToMatchAgainst: string): IMatch[] | null {
99 if (word.length > wordToMatchAgainst.length) {
100 return null;
103 return _matchesSubString(word.toLowerCase(), wordToMatchAgainst.toLowerCase(), 0, 0);
104 }
105 > filters.ts
106 function _matchesSubString(word: string, wordToMatchAgainst: string, i: number, j: number): IMatch[] | null {
107 if (i === word.length) {
121 }
122 }
123 > filters.ts
124 > // CamelCase
125 >
126 function isLower(code: number): boolean {
127 return CharCode.a <= code && code <= CharCode.z;
128 }
129 > filters.ts
130 > export function isUpper(code: number): boolean {
131 return CharCode.A <= code && code <= CharCode.Z;
132 }
133 > filters.ts
134 function isNumber(code: number): boolean {
135 return CharCode.Digit0 <= code && code <= CharCode.Digit9;
136 }
137 > filters.ts
138 function isWhitespace(code: number): boolean {
139 return (
144 );
145 }
146 > filters.ts
147 > const wordSeparators = new Set<number>();
148 > // These are chosen as natural word separators based on written text.
149 > // It is a subset of the word separators used by the monaco editor.
150 > '()[]{}<>`\'"-/;:,.?!'
151 > .split('')
152 > .forEach(s => wordSeparators.add(s.charCodeAt(0)));
153 >
154 function isWordSeparator(code: number): boolean {
155 return isWhitespace(code) || wordSeparators.has(code);
156 }
157 > filters.ts
158 function charactersMatch(codeA: number, codeB: number): boolean {
159 return (codeA === codeB) || (isWordSeparator(codeA) && isWordSeparator(codeB));
160 }
161 > filters.ts
162 > const alternateCharsCache: Map<number, ArrayLike<number> | undefined> = new Map();
163 > /**
164 > * Gets alternative codes to the character code passed in. This comes in the
165 > * form of an array of character codes, all of which must match _in order_ to
166 > * successfully match.
167 > *
168 > * @param code The character code to check.
169 > */
170 function getAlternateCodes(code: number): ArrayLike<number> | undefined {
171 if (alternateCharsCache.has(code)) {
186 return result;
187 }
188 > filters.ts
189 function isAlphanumeric(code: number): boolean {
190 return isLower(code) || isUpper(code) || isNumber(code);
191 }
192 > filters.ts
193 function join(head: IMatch, tail: IMatch[]): IMatch[] {
194 if (tail.length === 0) {
201 return tail;
202 }
203 > filters.ts
204 function nextAnchor(camelCaseWord: string, start: number): number {
205 for (let i = start; i < camelCaseWord.length; i++) {
211 return camelCaseWord.length;
212 }
213 > filters.ts
214 function _matchesCamelCase(word: string, camelCaseWord: string, i: number, j: number): IMatch[] | null {
215 if (i === word.length) {
230 }
231 }
232 > filters.ts
233 > interface ICamelCaseAnalysis {
234 > upperPercent: number;
235 > lowerPercent: number;
236 > alphaPercent: number;
237 > numericPercent: number;
238 > }
239 >
240 > // Heuristic to avoid computing camel case matcher for words that don't
241 > // look like camelCaseWords.
242 function analyzeCamelCaseWord(word: string): ICamelCaseAnalysis {
243 let upper = 0, lower = 0, alpha = 0, numeric = 0, code = 0;
259 return { upperPercent, lowerPercent, alphaPercent, numericPercent };
260 }
261 > filters.ts
262 function isUpperCaseWord(analysis: ICamelCaseAnalysis): boolean {
263 const { upperPercent, lowerPercent } = analysis;
264 return lowerPercent === 0 && upperPercent > 0.6;
265 }
266 > filters.ts
267 function isCamelCaseWord(analysis: ICamelCaseAnalysis): boolean {
268 const { upperPercent, lowerPercent, alphaPercent, numericPercent } = analysis;
269 return lowerPercent > 0.2 && upperPercent < 0.8 && alphaPercent > 0.6 && numericPercent < 0.2;
270 }
271 > filters.ts
272 > // Heuristic to avoid computing camel case matcher for words that don't
273 > // look like camel case patterns.
274 function isCamelCasePattern(word: string): boolean {
275 let upper = 0, lower = 0, code = 0, whitespace = 0;
289 }
290 }
291 > filters.ts
292 > export function matchesCamelCase(word: string, camelCaseWord: string): IMatch[] | null {
293 if (!camelCaseWord) {
294 return null;
330 return result;
331 }
332 > filters.ts
333 > // Matches beginning of words supporting non-ASCII languages
334 > // If `contiguous` is true then matches word with beginnings of the words in the target. E.g. "pul" will match "Git: Pull"
335 > // Otherwise also matches sub string of the word with beginnings of the words in the target. E.g. "gp" or "g p" will match "Git: Pull"
336 > // Useful in cases where the target is words (e.g. command labels)
337 >
338 > export function matchesWords(word: string, target: string, contiguous: boolean = false): IMatch[] | null {
339 if (!target || target.length === 0) {
340 return null;
361 return result;
362 }
363 > filters.ts
364 function cloneMatches(matches: IMatch[] | null): IMatch[] | null {
365 if (matches === null) {
372 return result;
373 }
374 > filters.ts
375 function _matchesWords(word: string, target: string, wordIndex: number, targetIndex: number, contiguous: boolean, memo: Map<number, IMatch[] | null>): IMatch[] | null {
376 if (wordIndex === word.length) {
391 return computed;
392 }
393 > filters.ts
394 function _matchesWordsCompute(word: string, target: string, wordIndex: number, targetIndex: number, contiguous: boolean, memo: Map<number, IMatch[] | null>): IMatch[] | null {
395 let targetIndexOffset = 0;
440 return join({ start: targetIndex, end: targetIndex + targetIndexOffset + 1 }, result);
441 }
442 > filters.ts
443 function nextWord(word: string, start: number): number {
444 for (let i = start; i < word.length; i++) {
450 return word.length;
451 }
452 > filters.ts
453 > // Fuzzy
454 >
455 > const fuzzyContiguousFilter = or(matchesPrefix, matchesCamelCase, matchesContiguousSubString);
456 > const fuzzySeparateFilter = or(matchesPrefix, matchesCamelCase, matchesSubString);
457 > const fuzzyRegExpCache = new LRUCache<string, RegExp>(10000); // bounded to 10000 elements
458 >
459 > export function matchesFuzzy(word: string, wordToMatchAgainst: string, enableSeparateSubstringMatching = false): IMatch[] | null {
460 if (typeof word !== 'string' || typeof wordToMatchAgainst !== 'string') {
461 return null; // return early for invalid input
478 return enableSeparateSubstringMatching ? fuzzySeparateFilter(word, wordToMatchAgainst) : fuzzyContiguousFilter(word, wordToMatchAgainst);
479 }
480 > filters.ts
481 > /**
482 > * Match pattern against word in a fuzzy way. As in IntelliSense and faster and more
483 > * powerful than `matchesFuzzy`
484 > */
485 > export function matchesFuzzy2(pattern: string, word: string): IMatch[] | null {
486 const score = fuzzyScore(pattern, pattern.toLowerCase(), 0, word, word.toLowerCase(), 0, { firstMatchCanBeWeak: true, boostFullMatch: true });
487 return score ? createMatches(score) : null;
488 }
489 > filters.ts
490 > export function anyScore(pattern: string, lowPattern: string, patternPos: number, word: string, lowWord: string, wordPos: number): FuzzyScore {
491 const max = Math.min(13, pattern.length);
492 for (; patternPos < max; patternPos++) {
498 return [0, wordPos];
499 }
500 > filters.ts
501 > //#region --- fuzzyScore ---
502 >
503 > export function createMatches(score: undefined | FuzzyScore): IMatch[] {
504 if (typeof score === 'undefined') {
505 return [];
518 return res;
519 }
520 > filters.ts
521 > const _maxLen = 128;
522 >
523 > function initTable() {
524 > const table: number[][] = [];
525 > const row: number[] = [];
526 > for (let i = 0; i <= _maxLen; i++) {
527 > row[i] = 0;
528 > }
529 > for (let i = 0; i <= _maxLen; i++) {
530 > table.push(row.slice(0));
531 > }
532 > return table;
533 > }
534 >
535 > function initArr(maxLen: number) {
536 > const row: number[] = [];
537 > for (let i = 0; i <= maxLen; i++) {
538 > row[i] = 0;
539 > }
540 > return row;
541 > }
542 >
543 > const _minWordMatchPos = initArr(2 * _maxLen); // min word position for a certain pattern position
544 > const _maxWordMatchPos = initArr(2 * _maxLen); // max word position for a certain pattern position
545 > const _diag = initTable(); // the length of a contiguous diagonal match
546 > const _table = initTable();
547 > const _arrows = <Arrow[][]>initTable();
548 > const _debug = false;
549 >
550 function printTable(table: number[][], pattern: string, patternLen: number, word: string, wordLen: number): string {
551 function pad(s: string, n: number, pad = ' ') {
567 return ret;
568 }
569 > filters.ts
570 function printTables(pattern: string, patternStart: number, word: string, wordStart: number): void {
571 pattern = pattern.substr(patternStart);
575 console.log(printTable(_diag, pattern, pattern.length, word, word.length));
576 }
577 > filters.ts
578 function isSeparatorAtPos(value: string, index: number): boolean {
579 if (index < 0 || index >= value.length) {
610 }
611 }
612 > filters.ts
613 function isWhitespaceAtPos(value: string, index: number): boolean {
614 if (index < 0 || index >= value.length) {
624 }
625 }
626 > filters.ts
627 function isUpperCaseAtPos(pos: number, word: string, wordLow: string): boolean {
628 return word[pos] !== wordLow[pos];
629 }
630 > filters.ts
631 > export function isPatternInWord(patternLow: string, patternPos: number, patternLen: number, wordLow: string, wordPos: number, wordLen: number, fillMinWordPosArr = false): boolean {
632 while (patternPos < patternLen && wordPos < wordLen) {
633 if (patternLow[patternPos] === wordLow[wordPos]) {
642 return patternPos === patternLen; // pattern must be exhausted
643 }
644 > filters.ts
645 > const enum Arrow { Diag = 1, Left = 2, LeftLeft = 3 }
646 >
647 > /**
648 > * An array representing a fuzzy match.
649 > *
650 > * 0. the score
651 > * 1. the offset at which matching started
652 > * 2. `<match_pos_N>`
653 > * 3. `<match_pos_1>`
654 > * 4. `<match_pos_0>` etc
655 > */
656 > export type FuzzyScore = [score: number, wordStart: number, ...matches: number[]];
657 >
658 > export namespace FuzzyScore {
659 > /**
660 > * No matches and value `-100`
661 > */
662 > export const Default: FuzzyScore = ([-100, 0]);
663 >
664 > export function isDefault(score?: FuzzyScore): score is [-100, 0] {
665 return !score || (score.length === 2 && score[0] === -100 && score[1] === 0);
666 }
667 > } filters.ts
668 >
669 > export abstract class FuzzyScoreOptions {
670 >
671 > static default = { boostFullMatch: true, firstMatchCanBeWeak: false };
672 >
673 > constructor(
674 readonly firstMatchCanBeWeak: boolean,
675 readonly boostFullMatch: boolean,
676 ) { }
677 > } filters.ts
678 >
679 > export interface FuzzyScorer {
680 > (pattern: string, lowPattern: string, patternPos: number, word: string, lowWord: string, wordPos: number, options?: FuzzyScoreOptions): FuzzyScore | undefined;
681 > }
682 >
683 > export function fuzzyScore(pattern: string, patternLow: string, patternStart: number, word: string, wordLow: string, wordStart: number, options: FuzzyScoreOptions = FuzzyScoreOptions.default): FuzzyScore | undefined {
684
685 const patternLen = pattern.length > _maxLen ? _maxLen : pattern.length;
832 return result;
833 }
834 > filters.ts
835 function _fillInMaxWordMatchPos(patternLen: number, wordLen: number, patternStart: number, wordStart: number, patternLow: string, wordLow: string) {
836 let patternPos = patternLen - 1;
844 }
845 }
846 > filters.ts
847 function _doScore(
848 pattern: string, patternLow: string, patternPos: number, patternStart: number,
913 return score;
914 }
915 > filters.ts
916 > //#endregion
917 >
918 >
919 > //#region --- graceful ---
920 >
921 > export function fuzzyScoreGracefulAggressive(pattern: string, lowPattern: string, patternPos: number, word: string, lowWord: string, wordPos: number, options?: FuzzyScoreOptions): FuzzyScore | undefined {
922 return fuzzyScoreWithPermutations(pattern, lowPattern, patternPos, word, lowWord, wordPos, true, options);
923 }
924 > filters.ts
925 > export function fuzzyScoreGraceful(pattern: string, lowPattern: string, patternPos: number, word: string, lowWord: string, wordPos: number, options?: FuzzyScoreOptions): FuzzyScore | undefined {
926 return fuzzyScoreWithPermutations(pattern, lowPattern, patternPos, word, lowWord, wordPos, false, options);
927 }
928 > filters.ts
929 function fuzzyScoreWithPermutations(pattern: string, lowPattern: string, patternPos: number, word: string, lowWord: string, wordPos: number, aggressive: boolean, options?: FuzzyScoreOptions): FuzzyScore | undefined {
930 let top = fuzzyScore(pattern, lowPattern, patternPos, word, lowWord, wordPos, options);
959 return top;
960 }
961 > filters.ts
962 function nextTypoPermutation(pattern: string, patternPos: number): string | undefined {
963
978 + pattern.slice(patternPos + 2);
979 }
980 > filters.ts
981 > //#endregion
src/vs/base/parts/storage/common/storage.ts 212 covered LOC · 33 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- storage.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { ThrottledDelayer } from '../../../common/async.js';
7 > import { Event, PauseableEmitter } from '../../../common/event.js';
8 > import { Disposable, IDisposable } from '../../../common/lifecycle.js';
9 > import { parse, stringify } from '../../../common/marshalling.js';
10 > import { isObject, isUndefined, isUndefinedOrNull } from '../../../common/types.js';
11 >
12 > export enum StorageHint {
13 >
14 > // A hint to the storage that the storage
15 > // does not exist on disk yet. This allows
16 > // the storage library to improve startup
17 > // time by not checking the storage for data.
18 > STORAGE_DOES_NOT_EXIST,
19 >
20 > // A hint to the storage that the storage
21 > // is backed by an in-memory storage.
22 > STORAGE_IN_MEMORY
23 > }
24 >
25 > export interface IStorageOptions {
26 > readonly hint?: StorageHint;
27 > }
28 >
29 > export interface IUpdateRequest {
30 > readonly insert?: Map<string, string>;
31 > readonly delete?: Set<string>;
32 > }
33 >
34 > export interface IStorageItemsChangeEvent {
35 > readonly changed?: Map<string, string>;
36 > readonly deleted?: Set<string>;
37 > }
38 >
39 > export function isStorageItemsChangeEvent(thing: unknown): thing is IStorageItemsChangeEvent {
40 const candidate = thing as IStorageItemsChangeEvent | undefined;
41
42 return candidate?.changed instanceof Map || candidate?.deleted instanceof Set;
43 }
44 > storage.ts
45 > export interface IStorageDatabase {
46 >
47 > readonly onDidChangeItemsExternal: Event<IStorageItemsChangeEvent>;
48 >
49 > getItems(): Promise<Map<string, string>>;
50 > updateItems(request: IUpdateRequest): Promise<void>;
51 >
52 > optimize(): Promise<void>;
53 >
54 > close(recovery?: () => Map<string, string>): Promise<void>;
55 > }
56 >
57 > export interface IStorageChangeEvent {
58 >
59 > /**
60 > * The `key` of the storage entry that was changed
61 > * or was removed.
62 > */
63 > readonly key: string;
64 >
65 > /**
66 > * A hint how the storage change event was triggered. If
67 > * `true`, the storage change was triggered by an external
68 > * source, such as:
69 > * - another process (for example another window)
70 > * - operations such as settings sync or profiles change
71 > */
72 > readonly external?: boolean;
73 > }
74 >
75 > export type StorageValue = string | boolean | number | undefined | null | object;
76 >
77 > export interface IStorage extends IDisposable {
78 >
79 > readonly onDidChangeStorage: Event<IStorageChangeEvent>;
80 >
81 > readonly items: Map<string, string>;
82 > readonly size: number;
83 >
84 > init(): Promise<void>;
85 >
86 > get(key: string, fallbackValue: string): string;
87 > get(key: string, fallbackValue?: string): string | undefined;
88 >
89 > getBoolean(key: string, fallbackValue: boolean): boolean;
90 > getBoolean(key: string, fallbackValue?: boolean): boolean | undefined;
91 >
92 > getNumber(key: string, fallbackValue: number): number;
93 > getNumber(key: string, fallbackValue?: number): number | undefined;
94 >
95 > getObject<T extends object>(key: string, fallbackValue: T): T;
96 > getObject<T extends object>(key: string, fallbackValue?: T): T | undefined;
97 >
98 > set(key: string, value: StorageValue, external?: boolean): Promise<void>;
99 > delete(key: string, external?: boolean): Promise<void>;
100 >
101 > flush(delay?: number): Promise<void>;
102 > whenFlushed(): Promise<void>;
103 >
104 > optimize(): Promise<void>;
105 >
106 > close(): Promise<void>;
107 > }
108 >
109 > export enum StorageState {
110 > None,
111 > Initialized,
112 > Closed
113 > }
114 >
115 > export class Storage extends Disposable implements IStorage {
116 >
117 > private static readonly DEFAULT_FLUSH_DELAY = 100;
118 >
119 > private readonly _onDidChangeStorage = this._register(new PauseableEmitter<IStorageChangeEvent>());
120 > readonly onDidChangeStorage = this._onDidChangeStorage.event;
121 >
122 > private state = StorageState.None;
123 >
124 > private cache = new Map<string, string>();
125 >
126 > private readonly flushDelayer = this._register(new ThrottledDelayer<void>(Storage.DEFAULT_FLUSH_DELAY));
127 >
128 > private pendingDeletes = new Set<string>();
129 > private pendingInserts = new Map<string, string>();
130 >
131 > private pendingClose: Promise<void> | undefined = undefined;
132 >
133 > private readonly whenFlushedCallbacks: Function[] = [];
134 >
135 > constructor(
136 protected readonly database: IStorageDatabase,
137 private readonly options: IStorageOptions = Object.create(null)
141 this.registerListeners();
142 }
143 > storage.ts
144 > private registerListeners(): void {
145 this._register(this.database.onDidChangeItemsExternal(e => this.onDidChangeItemsExternal(e)));
146 }
147 > storage.ts
148 > private onDidChangeItemsExternal(e: IStorageItemsChangeEvent): void {
149 this._onDidChangeStorage.pause();
150
161 }
162 }
163 > storage.ts
164 > private acceptExternal(key: string, value: string | undefined): void {
165 if (this.state === StorageState.Closed) {
166 return; // Return early if we are already closed
188 }
189 }
190 > storage.ts
191 > get items(): Map<string, string> {
192 return this.cache;
193 }
194 > storage.ts
195 > get size(): number {
196 return this.cache.size;
197 }
198 > storage.ts
199 > async init(): Promise<void> {
200 if (this.state !== StorageState.None) {
201 return; // either closed or already initialized
213 this.cache = await this.database.getItems();
214 }
215 > storage.ts
216 > get(key: string, fallbackValue: string): string;
217 > get(key: string, fallbackValue?: string): string | undefined;
218 > get(key: string, fallbackValue?: string): string | undefined {
219 const value = this.cache.get(key);
220
225 return value;
226 }
227 > storage.ts
228 > getBoolean(key: string, fallbackValue: boolean): boolean;
229 > getBoolean(key: string, fallbackValue?: boolean): boolean | undefined;
230 > getBoolean(key: string, fallbackValue?: boolean): boolean | undefined {
231 const value = this.get(key);
232
237 return value === 'true';
238 }
239 > storage.ts
240 > getNumber(key: string, fallbackValue: number): number;
241 > getNumber(key: string, fallbackValue?: number): number | undefined;
242 > getNumber(key: string, fallbackValue?: number): number | undefined {
243 const value = this.get(key);
244
249 return parseInt(value, 10);
250 }
251 > storage.ts
252 > getObject(key: string, fallbackValue: object): object;
253 > getObject(key: string, fallbackValue?: object | undefined): object | undefined;
254 > getObject(key: string, fallbackValue?: object): object | undefined {
255 const value = this.get(key);
256
261 return parse(value);
262 }
263 > storage.ts
264 > async set(key: string, value: string | boolean | number | null | undefined | object, external = false): Promise<void> {
265 if (this.state === StorageState.Closed) {
266 return; // Return early if we are already closed
292 return this.doFlush();
293 }
294 > storage.ts
295 > async delete(key: string, external = false): Promise<void> {
296 if (this.state === StorageState.Closed) {
297 return; // Return early if we are already closed
316 return this.doFlush();
317 }
318 > storage.ts
319 > async optimize(): Promise<void> {
320 if (this.state === StorageState.Closed) {
321 return; // Return early if we are already closed
328 return this.database.optimize();
329 }
330 > storage.ts
331 > async close(): Promise<void> {
332 if (!this.pendingClose) {
333 this.pendingClose = this.doClose();
336 return this.pendingClose;
337 }
338 > storage.ts
339 > private async doClose(): Promise<void> {
340
341 // Update state
356 await this.database.close(() => this.cache);
357 }
358 > storage.ts
359 > private get hasPending() {
360 return this.pendingInserts.size > 0 || this.pendingDeletes.size > 0;
361 }
362 > storage.ts
363 > private async flushPending(): Promise<void> {
364 if (!this.hasPending) {
365 return; // return early if nothing to do
383 });
384 }
385 > storage.ts
386 > async flush(delay?: number): Promise<void> {
387 if (
388 this.state === StorageState.Closed || // Return early if we are already closed
394 return this.doFlush(delay);
395 }
396 > storage.ts
397 > private async doFlush(delay?: number): Promise<void> {
398 if (this.options.hint === StorageHint.STORAGE_IN_MEMORY) {
399 return this.flushPending(); // return early if in-memory
402 return this.flushDelayer.trigger(() => this.flushPending(), delay);
403 }
404 > storage.ts
405 > async whenFlushed(): Promise<void> {
406 if (!this.hasPending) {
407 return; // return early if nothing to do
410 return new Promise(resolve => this.whenFlushedCallbacks.push(resolve));
411 }
412 > storage.ts
413 > isInMemory(): boolean {
414 return this.options.hint === StorageHint.STORAGE_IN_MEMORY;
415 }
416 > } storage.ts
417 >
418 > export class InMemoryStorageDatabase implements IStorageDatabase {
419
420 readonly onDidChangeItemsExternal = Event.None;
421
422 private readonly items = new Map<string, string>();
423 > storage.ts
424 > async getItems(): Promise<Map<string, string>> {
425 return this.items;
426 }
427 > storage.ts
428 > async updateItems(request: IUpdateRequest): Promise<void> {
429 request.insert?.forEach((value, key) => this.items.set(key, value));
430
431 request.delete?.forEach(key => this.items.delete(key));
432 }
433 > storage.ts
434 > async optimize(): Promise<void> { }
435 > async close(): Promise<void> { }
436 > }
437 >
438 >
439 > export const MIGRATED_KEY = '__$__migratedStorageMarker';
440 >
441 > export class MigratingStorage extends Storage {
442
443 private migratedKeys: Set<string> = new Set();
444 private fallbackStorage: IStorage | undefined = undefined;
445 private isFallbackStorageReadonly: boolean = false;
446 > storage.ts
447 > override async init(): Promise<void> {
448 await super.init();
449
451 this.migratedKeys = this.loadMigratedKeys();
452 }
453 > storage.ts
454 > public setFallbackStorage(storage: IStorage, isReadonly: boolean): void {
455 this.fallbackStorage = storage;
456 this.isFallbackStorageReadonly = isReadonly;
457 }
458 > storage.ts
459 > private static readonly INTERNAL_KEY_PREFIX = '__$__';
460 >
461 > override get(key: string, fallbackValue: string): string;
462 > override get(key: string, fallbackValue?: string): string | undefined;
463 > override get(key: string, fallbackValue?: string): string | undefined {
464 if (!key.startsWith(MigratingStorage.INTERNAL_KEY_PREFIX) && !this.migratedKeys.has(key) && isUndefined(super.get(key))) {
465 // Check fallback storage and auto-migrate on hit.
480 return super.get(key, fallbackValue);
481 }
482 > storage.ts
483 > private loadMigratedKeys(): Set<string> {
484 const raw = super.get(MIGRATED_KEY);
485 if (raw) {
492 return new Set();
493 }
494 > storage.ts
495 > private persistMigratedKeys(): void {
496 this.set(MIGRATED_KEY, JSON.stringify([...this.migratedKeys]));
497 }
498 > } storage.ts
499
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/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/workbench/contrib/chat/common/actions/chatContextKeys.ts 204 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- chatContextKeys.ts
2 > * Copyright (c) Microsoft 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 { ContextKeyExpr, RawContextKey } from '../../../../../platform/contextkey/common/contextkey.js';
8 > import { IsWebContext } from '../../../../../platform/contextkey/common/contextkeys.js';
9 > import { RemoteNameContext } from '../../../../common/contextkeys.js';
10 > import { ViewContainerLocation } from '../../../../common/views.js';
11 > import { ChatEntitlementContextKeys } from '../../../../services/chat/common/chatEntitlementService.js';
12 > import { ChatAccountPolicyGateActiveContext } from '../../../../services/policies/common/accountPolicyService.js';
13 > import { ChatAgentLocation, ChatModeKind, ChatPermissionLevel } from '../constants.js';
14 >
15 > export namespace ChatContextKeys {
16 > export const responseVote = new RawContextKey<string>('chatSessionResponseVote', '', { type: 'string', description: localize('interactiveSessionResponseVote', "When the response has been voted up, is set to 'up'. When voted down, is set to 'down'. Otherwise an empty string.") });
17 > export const responseDetectedAgentCommand = new RawContextKey<boolean>('chatSessionResponseDetectedAgentOrCommand', false, { type: 'boolean', description: localize('chatSessionResponseDetectedAgentOrCommand', "When the agent or command was automatically detected") });
18 > export const responseSupportsIssueReporting = new RawContextKey<boolean>('chatResponseSupportsIssueReporting', false, { type: 'boolean', description: localize('chatResponseSupportsIssueReporting', "True when the current chat response supports issue reporting.") });
19 > export const responseIsFiltered = new RawContextKey<boolean>('chatSessionResponseFiltered', false, { type: 'boolean', description: localize('chatResponseFiltered', "True when the chat response was filtered out by the server.") });
20 > export const responseHasError = new RawContextKey<boolean>('chatSessionResponseError', false, { type: 'boolean', description: localize('chatResponseErrored', "True when the chat response resulted in an error.") });
21 > export const requestInProgress = new RawContextKey<boolean>('chatSessionRequestInProgress', false, { type: 'boolean', description: localize('interactiveSessionRequestInProgress', "True when the current request is still in progress.") });
22 > export const hasActiveRequest = new RawContextKey<boolean>('chatSessionHasActiveRequest', false, { type: 'boolean', description: localize('chatSessionHasActiveRequest', "True when the current chat response has not completed, regardless of intermediate states like tool calls or elicitations.") });
23 > export const currentlyEditing = new RawContextKey<boolean>('chatSessionCurrentlyEditing', false, { type: 'boolean', description: localize('interactiveSessionCurrentlyEditing', "True when the current request is being edited.") });
24 > export const currentlyEditingInput = new RawContextKey<boolean>('chatSessionCurrentlyEditingInput', false, { type: 'boolean', description: localize('interactiveSessionCurrentlyEditingInput', "True when the current request input at the bottom is being edited.") });
25 >
26 > export const enum EditingRequestType {
27 > Sent = 's',
28 > Queue = 'q',
29 > Steer = 'st',
30 > }
31 > export const editingRequestType = new RawContextKey<EditingRequestType | undefined>('chatEditingSentRequest', undefined, { type: 'string', description: localize('chatEditingSentRequest', "The type of the current editing request.") });
32 >
33 > export const isResponse = new RawContextKey<boolean>('chatResponse', false, { type: 'boolean', description: localize('chatResponse', "The chat item is a response.") });
34 > export const isRequest = new RawContextKey<boolean>('chatRequest', false, { type: 'boolean', description: localize('chatRequest', "The chat item is a request") });
35 > export const isFirstRequest = new RawContextKey<boolean>('chatFirstRequest', false, { type: 'boolean', description: localize('chatFirstRequest', "The chat item is the first request in the session.") });
36 > export const isPendingRequest = new RawContextKey<boolean>('chatRequestIsPending', false, { type: 'boolean', description: localize('chatRequestIsPending', "True when the chat request item is pending in the queue.") });
37 > export const itemId = new RawContextKey<string>('chatItemId', '', { type: 'string', description: localize('chatItemId', "The id of the chat item.") });
38 > export const lastItemId = new RawContextKey<string[]>('chatLastItemId', [], { type: 'string', description: localize('chatLastItemId', "The id of the last chat item.") });
39 >
40 > export const editApplied = new RawContextKey<boolean>('chatEditApplied', false, { type: 'boolean', description: localize('chatEditApplied', "True when the chat text edits have been applied.") });
41 >
42 > export const inputHasText = new RawContextKey<boolean>('chatInputHasText', false, { type: 'boolean', description: localize('interactiveInputHasText', "True when the chat input has text.") });
43 > export const inputHasSendableContent = new RawContextKey<boolean>('chatInputHasSendableContent', false, { type: 'boolean', description: localize('interactiveInputHasSendableContent', "True when the chat input has text or file attachments that can be sent.") });
44 > export const inputHasFocus = new RawContextKey<boolean>('chatInputHasFocus', false, { type: 'boolean', description: localize('interactiveInputHasFocus', "True when the chat input has focus.") });
45 > export const inChatInput = new RawContextKey<boolean>('inChatInput', false, { type: 'boolean', description: localize('inInteractiveInput', "True when focus is in the chat input, false otherwise.") });
46 > export const inChatSession = new RawContextKey<boolean>('inChat', false, { type: 'boolean', description: localize('inChat', "True when focus is in the chat widget, false otherwise.") });
47 > export const inChatQuestionCarousel = new RawContextKey<boolean>('inChatQuestionCarousel', false, { type: 'boolean', description: localize('inChatQuestionCarousel', "True when focus is in the chat question carousel.") });
48 > export const chatQuestionCarouselHasTerminal = new RawContextKey<boolean>('chatQuestionCarouselHasTerminal', false, { type: 'boolean', description: localize('chatQuestionCarouselHasTerminal', "True when the chat question carousel was triggered by a terminal and has a terminal to focus.") });
49 > export const inChatEditor = new RawContextKey<boolean>('inChatEditor', false, { type: 'boolean', description: localize('inChatEditor', "Whether focus is in a chat editor.") });
50 > export const inChatTodoList = new RawContextKey<boolean>('inChatTodoList', false, { type: 'boolean', description: localize('inChatTodoList', "True when focus is in the chat todo list.") });
51 > export const inChatTip = new RawContextKey<boolean>('inChatTip', false, { type: 'boolean', description: localize('inChatTip', "True when focus is in a chat tip.") });
52 > export const multipleChatTips = new RawContextKey<boolean>('multipleChatTips', false, { type: 'boolean', description: localize('multipleChatTips', "True when there are multiple chat tips available.") });
53 > export const inChatTerminalToolOutput = new RawContextKey<boolean>('inChatTerminalToolOutput', false, { type: 'boolean', description: localize('inChatTerminalToolOutput', "True when focus is in the chat terminal output region.") });
54 > export const chatModeKind = new RawContextKey<ChatModeKind>('chatAgentKind', ChatModeKind.Ask, { type: 'string', description: localize('agentKind', "The 'kind' of the current agent.") });
55 > export const chatPermissionLevel = new RawContextKey<ChatPermissionLevel>('chatPermissionLevel', ChatPermissionLevel.Default, { type: 'string', description: localize('chatPermissionLevel', "The current permission level for tool auto-approval.") });
56 > export const chatModeName = new RawContextKey<string>('chatModeName', '', { type: 'string', description: localize('chatModeName', "The name of the current chat mode (e.g. 'Plan' for custom modes).") });
57 > export const chatModelId = new RawContextKey<string>('chatModelId', '', { type: 'string', description: localize('chatModelId', "The short id of the currently selected chat model (for example 'gpt-4.1').") });
58 > export const speechToTextRecording = new RawContextKey<boolean>('chatSpeechToTextRecording', false, { type: 'boolean', description: localize('chatSpeechToTextRecording', "True while the chat input is recording audio for speech-to-text transcription.") });
59 > export const speechToTextConfigured = new RawContextKey<boolean>('chatSpeechToTextConfigured', false, { type: 'boolean', description: localize('chatSpeechToTextConfigured', "True when on-device speech-to-text is available for dictating into the chat input.") });
60 > export const speechToTextPreparing = new RawContextKey<boolean>('chatSpeechToTextPreparing', false, { type: 'boolean', description: localize('chatSpeechToTextPreparing', "True while the selected speech-to-text backend is preparing.") });
61 >
62 > export const supported = ContextKeyExpr.or(IsWebContext.negate(), RemoteNameContext.notEqualsTo(''), ContextKeyExpr.has('config.chat.experimental.serverlessWebEnabled'));
63 > export const enabled = new RawContextKey<boolean>('chatIsEnabled', false, { type: 'boolean', description: localize('chatIsEnabled', "True when chat is enabled because a default chat participant is activated with an implementation.") });
64 > export const accountPolicyGateActive = ChatAccountPolicyGateActiveContext;
65 >
66 > /**
67 > * True when the chat widget is locked to the coding agent session.
68 > */
69 > export const lockedToCodingAgent = new RawContextKey<boolean>('lockedToCodingAgent', false, { type: 'boolean', description: localize('lockedToCodingAgent', "True when the chat widget is locked to the coding agent session.") });
70 > export const lockedCodingAgentId = new RawContextKey<string>('lockedCodingAgentId', '', { type: 'string', description: localize('lockedCodingAgentId', "The agent ID when the chat widget is locked to a coding agent session.") });
71 > /**
72 > * Widget-scoped: true when the chat shown in this widget is read-only (non-interactive),
73 > * e.g. an observable worker chat. Read-only chats hide the composer and do not offer
74 > * mutating actions such as Start Over or Restore Checkpoint.
75 > */
76 > export const readOnly = new RawContextKey<boolean>('chatIsReadonly', false, { type: 'boolean', description: localize('chatIsReadonly', "True when the chat shown in the widget is read-only (non-interactive).") });
77 > /**
78 > * Widget-scoped: true when this chat widget is locked to an Agent Host-backed chat session.
79 > */
80 > export const chatIsAgentHostSession = new RawContextKey<boolean>('chatIsAgentHostSession', false, { type: 'boolean', description: localize('chatIsAgentHostSession', "True when the chat widget is locked to an Agent Host session.") });
81 > /**
82 > * Widget-scoped: logical Agent Host provider ID for this chat widget, e.g. `copilotcli`, `claude`, or `codex`.
83 > */
84 > export const chatAgentHostProviderId = new RawContextKey<string>('chatAgentHostProviderId', '', { type: 'string', description: localize('chatAgentHostProviderId', "The Agent Host provider ID when the chat widget is locked to an Agent Host session.") });
85 > /**
86 > * True when the chat session has a customAgentTarget defined in its contribution,
87 > * which means the mode picker should be shown with filtered custom agents.
88 > */
89 > export const chatSessionHasCustomAgentTarget = new RawContextKey<boolean>('chatSessionHasCustomAgentTarget', false, { type: 'boolean', description: localize('chatSessionHasCustomAgentTarget', "True when the chat session has a customAgentTarget defined to filter modes.") });
90 > /**
91 > * True when the current chat session has models that specifically target it
92 > * via `targetChatSessionType`, which means the model picker should be shown
93 > * even when the widget is locked to a coding agent.
94 > */
95 > export const chatSessionHasTargetedModels = new RawContextKey<boolean>('chatSessionHasTargetedModels', false, { type: 'boolean', description: localize('chatSessionHasTargetedModels', "True when the chat session has language models that target it via targetChatSessionType.") });
96 > export const agentSupportsAttachments = new RawContextKey<boolean>('agentSupportsAttachments', false, { type: 'boolean', description: localize('agentSupportsAttachments', "True when the chat agent supports attachments.") });
97 > export const withinEditSessionDiff = new RawContextKey<boolean>('withinEditSessionDiff', false, { type: 'boolean', description: localize('withinEditSessionDiff', "True when the chat widget dispatches to the edit session chat.") });
98 > export const filePartOfEditSession = new RawContextKey<boolean>('filePartOfEditSession', false, { type: 'boolean', description: localize('filePartOfEditSession', "True when the chat widget is within a file with an edit session.") });
99 >
100 > export const extensionParticipantRegistered = new RawContextKey<boolean>('chatPanelExtensionParticipantRegistered', false, { type: 'boolean', description: localize('chatPanelExtensionParticipantRegistered', "True when a default chat participant is registered for the panel from an extension.") });
101 > export const panelParticipantRegistered = new RawContextKey<boolean>('chatPanelParticipantRegistered', false, { type: 'boolean', description: localize('chatParticipantRegistered', "True when a default chat participant is registered for the panel.") });
102 > export const chatEditingCanUndo = new RawContextKey<boolean>('chatEditingCanUndo', false, { type: 'boolean', description: localize('chatEditingCanUndo', "True when it is possible to undo an interaction in the editing panel.") });
103 > export const chatEditingCanRedo = new RawContextKey<boolean>('chatEditingCanRedo', false, { type: 'boolean', description: localize('chatEditingCanRedo', "True when it is possible to redo an interaction in the editing panel.") });
104 > export const languageModelsAreUserSelectable = new RawContextKey<boolean>('chatModelsAreUserSelectable', false, { type: 'boolean', description: localize('chatModelsAreUserSelectable', "True when the chat model can be selected manually by the user.") });
105 > export const nonCopilotLanguageModelsAreUserSelectable = new RawContextKey<boolean>('chatNonCopilotModelsAreUserSelectable', false, { type: 'boolean', description: localize('chatNonCopilotModelsAreUserSelectable', "True when a user-selectable chat model from a non-Copilot vendor is available.") });
106 > export const chatSessionHasModels = new RawContextKey<boolean>('chatSessionHasModels', false, { type: 'boolean', description: localize('chatSessionHasModels', "True when the chat is in a contributed chat session that has available 'models' to display.") });
107 > export const chatSessionOptionsValid = new RawContextKey<boolean>('chatSessionOptionsValid', true, { type: 'boolean', description: localize('chatSessionOptionsValid', "True when all selected session options exist in their respective option group items.") });
108 > export const extensionInvalid = new RawContextKey<boolean>('chatExtensionInvalid', false, { type: 'boolean', description: localize('chatExtensionInvalid', "True when the installed chat extension is invalid and needs to be updated.") });
109 > export const inputCursorAtTop = new RawContextKey<boolean>('chatCursorAtTop', false);
110 > export const inputHasAgent = new RawContextKey<boolean>('chatInputHasAgent', false);
111 > export const location = new RawContextKey<ChatAgentLocation>('chatLocation', undefined);
112 > export const inQuickChat = new RawContextKey<boolean>('quickChatHasFocus', false, { type: 'boolean', description: localize('inQuickChat', "True when the quick chat UI has focus, false otherwise.") });
113 > export const inAgentSessionsWelcome = new RawContextKey<boolean>('inAgentSessionsWelcome', false, { type: 'boolean', description: localize('inAgentSessionsWelcome', "True when the chat input is within the agent sessions welcome page.") });
114 > export const inAutomationsDialog = new RawContextKey<boolean>('inAutomationsDialog', false, { type: 'boolean', description: localize('inAutomationsDialog', "True when the chat input is within the automations dialog.") });
115 > export const chatSessionType = new RawContextKey<string>('chatSessionType', '', { type: 'string', description: localize('chatSessionType', "The type of the current chat session.") });
116 > export const hasFileAttachments = new RawContextKey<boolean>('chatHasFileAttachments', false, { type: 'boolean', description: localize('chatHasFileAttachments', "True when the chat has file attachments.") });
117 > export const chatSessionIsEmpty = new RawContextKey<boolean>('chatSessionIsEmpty', true, { type: 'boolean', description: localize('chatSessionIsEmpty', "True when the current chat session has no requests.") });
118 > export const hasPendingRequests = new RawContextKey<boolean>('chatHasPendingRequests', false, { type: 'boolean', description: localize('chatHasPendingRequests', "True when there are pending requests in the queue.") });
119 > export const chatSessionHasDebugData = new RawContextKey<boolean>('chatSessionHasDebugData', false, { type: 'boolean', description: localize('chatSessionHasDebugData', "True when the current chat session has debug log data.") });
120 > export const chatSessionHasDebugTools = new RawContextKey<boolean>('chatSessionHasDebugTools', false, { type: 'boolean', description: localize('chatSessionHasDebugTools', "True when debug tools are enabled in the current chat session.") });
121 >
122 > export const remoteJobCreating = new RawContextKey<boolean>('chatRemoteJobCreating', false, { type: 'boolean', description: localize('chatRemoteJobCreating', "True when a remote coding agent job is being created.") });
123 > export const hasRemoteCodingAgent = new RawContextKey<boolean>('hasRemoteCodingAgent', false, localize('hasRemoteCodingAgent', "Whether any remote coding agent is available"));
124 > export const hasCanDelegateProviders = new RawContextKey<boolean>('chatHasCanDelegateProviders', false, { type: 'boolean', description: localize('chatHasCanDelegateProviders', "True when there are chat session providers with delegation support available.") });
125 > export const enableRemoteCodingAgentPromptFileOverlay = new RawContextKey<boolean>('enableRemoteCodingAgentPromptFileOverlay', false, localize('enableRemoteCodingAgentPromptFileOverlay', "Whether the remote coding agent prompt file overlay feature is enabled"));
126 > /** Used by the extension to skip the quit confirmation when #new wants to open a new folder */
127 > export const skipChatRequestInProgressMessage = new RawContextKey<boolean>('chatSkipRequestInProgressMessage', false, { type: 'boolean', description: localize('chatSkipRequestInProgressMessage', "True when the chat request in progress message should be skipped.") });
128 >
129 > // Re-exported from chat entitlement service
130 > export const Setup = ChatEntitlementContextKeys.Setup;
131 > export const Entitlement = ChatEntitlementContextKeys.Entitlement;
132 > export const chatQuotaExceeded = ChatEntitlementContextKeys.chatQuotaExceeded;
133 > export const completionsQuotaExceeded = ChatEntitlementContextKeys.completionsQuotaExceeded;
134 >
135 > export const Editing = {
136 > hasToolConfirmation: new RawContextKey<boolean>('chatHasToolConfirmation', false, { type: 'boolean', description: localize('chatEditingHasToolConfirmation', "True when a tool confirmation is present.") }),
137 > hasElicitationRequest: new RawContextKey<boolean>('chatHasElicitationRequest', false, { type: 'boolean', description: localize('chatEditingHasElicitationRequest', "True when a chat elicitation request is pending.") }),
138 > hasQuestionCarousel: new RawContextKey<boolean>('chatHasQuestionCarousel', false, { type: 'boolean', description: localize('chatEditingHasQuestionCarousel', "True when a question carousel is rendered in the chat input.") }),
139 > };
140 >
141 > export const Tools = {
142 > toolsCount: new RawContextKey<number>('toolsCount', 0, { type: 'number', description: localize('toolsCount', "The count of tools available in the chat.") })
143 > };
144 >
145 > export const foregroundSessionCount = new RawContextKey<number>('chatForegroundSessionCount', 0, { type: 'number', description: localize('chatForegroundSessionCount', "The number of foreground chat sessions visible across chat surfaces.") });
146 >
147 > export const Modes = {
148 > hasCustomChatModes: new RawContextKey<boolean>('chatHasCustomAgents', false, { type: 'boolean', description: localize('chatHasAgents', "True when the chat has custom agents available.") }),
149 > agentModeDisabledByPolicy: new RawContextKey<boolean>('chatAgentModeDisabledByPolicy', false, { type: 'boolean', description: localize('chatAgentModeDisabledByPolicy', "True when agent mode is disabled by organization policy.") }),
150 > };
151 >
152 > export const panelLocation = new RawContextKey<ViewContainerLocation>('chatPanelLocation', undefined, { type: 'number', description: localize('chatPanelLocation', "The location of the chat panel.") });
153 >
154 > export const agentSessionsViewerFocused = new RawContextKey<boolean>('agentSessionsViewerFocused', true, { type: 'boolean', description: localize('agentSessionsViewerFocused', "If the agent sessions view in the chat view is focused.") });
155 > export const agentSessionsViewerOrientation = new RawContextKey<number>('agentSessionsViewerOrientation', undefined, { type: 'number', description: localize('agentSessionsViewerOrientation', "Orientation of the agent sessions view in the chat view.") });
156 > export const agentSessionsViewerPosition = new RawContextKey<number>('agentSessionsViewerPosition', undefined, { type: 'number', description: localize('agentSessionsViewerPosition', "Position of the agent sessions view in the chat view.") });
157 > export const agentSessionsViewerVisible = new RawContextKey<boolean>('agentSessionsViewerVisible', undefined, { type: 'boolean', description: localize('agentSessionsViewerVisible', "Visibility of the agent sessions view in the chat view.") });
158 > export const agentSessionType = new RawContextKey<string>('chatSessionType', '', { type: 'string', description: localize('agentSessionType', "The type of the current agent session item.") });
159 > export const chatSessionSupportsDelegation = new RawContextKey<boolean>('chatSessionSupportsDelegation', true, { type: 'boolean', description: localize('chatSessionSupportsDelegation', "True when the current session type supports delegation.") });
160 > export const hasPendingDelegationTarget = new RawContextKey<boolean>('chatHasPendingDelegationTarget', false, { type: 'boolean', description: localize('chatHasPendingDelegationTarget', "True when a delegation (continue in) target is selected but the request has not been submitted yet.") });
161 > export const chatSessionSupportsFork = new RawContextKey<boolean>('chatSessionSupportsFork', false, { type: 'boolean', description: localize('chatSessionSupportsFork', "True when the current chat session provider supports forking conversations.") });
162 > export const agentSessionSection = new RawContextKey<string>('agentSessionSection', '', { type: 'string', description: localize('agentSessionSection', "The section of the current agent session section item.") });
163 > export const isArchivedAgentSession = new RawContextKey<boolean>('agentSessionIsArchived', false, { type: 'boolean', description: localize('agentSessionIsArchived', "True when the agent session item is archived.") });
164 > export const isPinnedAgentSession = new RawContextKey<boolean>('agentSessionIsPinned', false, { type: 'boolean', description: localize('agentSessionIsPinned', "True when the agent session item is pinned.") });
165 > export const isReadAgentSession = new RawContextKey<boolean>('agentSessionIsRead', false, { type: 'boolean', description: localize('agentSessionIsRead', "True when the agent session item is read.") });
166 > export const hasMultipleAgentSessionsSelected = new RawContextKey<boolean>('agentSessionHasMultipleSelected', false, { type: 'boolean', description: localize('agentSessionHasMultipleSelected', "True when multiple agent sessions are selected.") });
167 > export const hasAgentSessionChanges = new RawContextKey<boolean>('agentSessionHasChanges', false, { type: 'boolean', description: localize('agentSessionHasChanges', "True when the current agent session item has changes.") });
168 >
169 > export const isKatexMathElement = new RawContextKey<boolean>('chatIsKatexMathElement', false, { type: 'boolean', description: localize('chatIsKatexMathElement', "True when focusing a KaTeX math element.") });
170 >
171 > /**
172 > * True when the user has submitted a chat request using any of the `/create-*` slash commands.
173 > * This is persisted in application storage and used to suppress onboarding tips once discovered.
174 > */
175 > export const hasUsedCreateSlashCommands = new RawContextKey<boolean>('chatHasUsedCreateSlashCommands', false, { type: 'boolean', description: localize('chatHasUsedCreateSlashCommands', "True when the user has used any of the /create-* slash commands.") });
176 >
177 > export const contextUsageHasBeenOpened = new RawContextKey<boolean>('chatContextUsageHasBeenOpened', false, { type: 'boolean', description: localize('chatContextUsageHasBeenOpened', "True when the user has opened the context window usage details.") });
178 >
179 > export const newChatButtonExperimentIcon = new RawContextKey<string>('chatNewChatButtonExperimentIcon', '', { type: 'string', description: localize('chatNewChatButtonExperimentIcon', "The icon variant for the new chat button, controlled by experiment. Values: 'copilot', 'new-session', 'comment', or empty for default.") });
180 > }
181 >
182 > export namespace ChatContextKeyExprs {
183 >
184 > export const inEditingMode = ContextKeyExpr.or(
185 > ChatContextKeys.chatModeKind.isEqualTo(ChatModeKind.Edit),
186 > ChatContextKeys.chatModeKind.isEqualTo(ChatModeKind.Agent),
187 > );
188 >
189 > /**
190 > * True when the locked coding agent is an Agent Host session.
191 > * These sessions use {@link AgentHostSnapshotController} which supports checkpoint-based restore.
192 > */
193 > export const isAgentHostSession = ChatContextKeys.chatIsAgentHostSession.isEqualTo(true);
194 >
195 > /**
196 > * True when an agent session item (e.g. in the sessions viewer) is an agent
197 > * host session (agent-host-* or remote-*). Keyed on {@link ChatContextKeys.agentSessionType}
198 > * rather than the locked coding agent, for use in session item menus and keybindings.
199 > */
200 > export const isAgentHostSessionItem = ContextKeyExpr.or(
201 > ContextKeyExpr.regex(ChatContextKeys.agentSessionType.key, /^agent-host-/),
202 > ContextKeyExpr.regex(ChatContextKeys.agentSessionType.key, /^remote-/),
203 > );
204 > }
src/vs/platform/configuration/common/configuration.ts 203 covered LOC · 12 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
355 .replace(/^\[/, '')
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/workbench/services/mcp/common/mcpWorkbenchManagementService.ts 203 covered LOC · 30 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- mcpWorkbenchManagementService.ts
2 > * Copyright (c) Microsoft 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 { ILocalMcpServer, IMcpManagementService, IGalleryMcpServer, InstallOptions, InstallMcpServerEvent, UninstallMcpServerEvent, DidUninstallMcpServerEvent, InstallMcpServerResult, IInstallableMcpServer, IMcpGalleryService, UninstallOptions, IAllowedMcpServersService, RegistryType } from '../../../../platform/mcp/common/mcpManagement.js';
8 > import { IInstantiationService, refineServiceDecorator } from '../../../../platform/instantiation/common/instantiation.js';
9 > import { IUserDataProfileService } from '../../../services/userDataProfile/common/userDataProfile.js';
10 > import { Emitter, Event } from '../../../../base/common/event.js';
11 > import { IMcpResourceScannerService, McpResourceTarget } from '../../../../platform/mcp/common/mcpResourceScannerService.js';
12 > import { isWorkspaceFolder, IWorkspaceContextService, IWorkspaceFolder, IWorkspaceFoldersChangeEvent } from '../../../../platform/workspace/common/workspace.js';
13 > import { IUriIdentityService } from '../../../../platform/uriIdentity/common/uriIdentity.js';
14 > import { MCP_CONFIGURATION_KEY, WORKSPACE_STANDALONE_CONFIGURATIONS } from '../../configuration/common/configuration.js';
15 > import { ILogService } from '../../../../platform/log/common/log.js';
16 > import { IRemoteAgentService } from '../../remote/common/remoteAgentService.js';
17 > import { URI } from '../../../../base/common/uri.js';
18 > import { ConfigurationTarget } from '../../../../platform/configuration/common/configuration.js';
19 > import { IChannel } from '../../../../base/parts/ipc/common/ipc.js';
20 > import { McpManagementChannelClient } from '../../../../platform/mcp/common/mcpManagementIpc.js';
21 > import { IUserDataProfilesService } from '../../../../platform/userDataProfile/common/userDataProfile.js';
22 > import { IRemoteUserDataProfilesService } from '../../userDataProfile/common/remoteUserDataProfiles.js';
23 > import { AbstractMcpManagementService, AbstractMcpResourceManagementService, ILocalMcpServerInfo } from '../../../../platform/mcp/common/mcpManagementService.js';
24 > import { IFileService } from '../../../../platform/files/common/files.js';
25 > import { ResourceMap } from '../../../../base/common/map.js';
26 > import { IMarkdownString } from '../../../../base/common/htmlContent.js';
27 > import { IMcpServerConfiguration } from '../../../../platform/mcp/common/mcpPlatformTypes.js';
28 >
29 > export const USER_CONFIG_ID = 'usrlocal';
30 > export const REMOTE_USER_CONFIG_ID = 'usrremote';
31 > export const WORKSPACE_CONFIG_ID = 'workspace';
32 > export const WORKSPACE_FOLDER_CONFIG_ID_PREFIX = 'ws';
33 >
34 > export interface IWorkbencMcpServerInstallOptions extends InstallOptions {
35 > target?: ConfigurationTarget | IWorkspaceFolder;
36 > }
37 >
38 > export const enum LocalMcpServerScope {
39 > User = 'user',
40 > RemoteUser = 'remoteUser',
41 > Workspace = 'workspace',
42 > }
43 >
44 > export interface IWorkbenchLocalMcpServer extends ILocalMcpServer {
45 > readonly id: string;
46 > readonly scope: LocalMcpServerScope;
47 > }
48 >
49 > export interface InstallWorkbenchMcpServerEvent extends InstallMcpServerEvent {
50 > readonly scope: LocalMcpServerScope;
51 > }
52 >
53 > export interface IWorkbenchMcpServerInstallResult extends InstallMcpServerResult {
54 > readonly local?: IWorkbenchLocalMcpServer;
55 > }
56 >
57 > export interface UninstallWorkbenchMcpServerEvent extends UninstallMcpServerEvent {
58 > readonly scope: LocalMcpServerScope;
59 > }
60 >
61 > export interface DidUninstallWorkbenchMcpServerEvent extends DidUninstallMcpServerEvent {
62 > readonly scope: LocalMcpServerScope;
63 > }
64 >
65 > export const IWorkbenchMcpManagementService = refineServiceDecorator<IMcpManagementService, IWorkbenchMcpManagementService>(IMcpManagementService);
66 > export interface IWorkbenchMcpManagementService extends IMcpManagementService {
67 > readonly _serviceBrand: undefined;
68 >
69 > readonly onInstallMcpServerInCurrentProfile: Event<InstallWorkbenchMcpServerEvent>;
70 > readonly onDidInstallMcpServersInCurrentProfile: Event<readonly IWorkbenchMcpServerInstallResult[]>;
71 > readonly onDidUpdateMcpServersInCurrentProfile: Event<readonly IWorkbenchMcpServerInstallResult[]>;
72 > readonly onUninstallMcpServerInCurrentProfile: Event<UninstallWorkbenchMcpServerEvent>;
73 > readonly onDidUninstallMcpServerInCurrentProfile: Event<DidUninstallWorkbenchMcpServerEvent>;
74 > readonly onDidChangeProfile: Event<void>;
75 >
76 > getInstalled(): Promise<IWorkbenchLocalMcpServer[]>;
77 > install(server: IInstallableMcpServer | URI, options?: IWorkbencMcpServerInstallOptions): Promise<IWorkbenchLocalMcpServer>;
78 > installFromGallery(server: IGalleryMcpServer, options?: InstallOptions): Promise<IWorkbenchLocalMcpServer>;
79 > updateMetadata(local: ILocalMcpServer, server: IGalleryMcpServer, profileLocation?: URI): Promise<IWorkbenchLocalMcpServer>;
80 > }
81 >
82 > export class WorkbenchMcpManagementService extends AbstractMcpManagementService implements IWorkbenchMcpManagementService {
83 >
84 > private _onInstallMcpServer = this._register(new Emitter<InstallMcpServerEvent>());
85 > readonly onInstallMcpServer = this._onInstallMcpServer.event;
86 >
87 > private _onDidInstallMcpServers = this._register(new Emitter<readonly InstallMcpServerResult[]>());
88 > readonly onDidInstallMcpServers = this._onDidInstallMcpServers.event;
89 >
90 > private _onDidUpdateMcpServers = this._register(new Emitter<readonly InstallMcpServerResult[]>());
91 > readonly onDidUpdateMcpServers = this._onDidUpdateMcpServers.event;
92 >
93 > private _onUninstallMcpServer = this._register(new Emitter<UninstallMcpServerEvent>());
94 > readonly onUninstallMcpServer = this._onUninstallMcpServer.event;
95 >
96 > private _onDidUninstallMcpServer = this._register(new Emitter<DidUninstallMcpServerEvent>());
97 > readonly onDidUninstallMcpServer = this._onDidUninstallMcpServer.event;
98 >
99 > private readonly _onInstallMcpServerInCurrentProfile = this._register(new Emitter<InstallWorkbenchMcpServerEvent>());
100 > readonly onInstallMcpServerInCurrentProfile = this._onInstallMcpServerInCurrentProfile.event;
101 >
102 > private readonly _onDidInstallMcpServersInCurrentProfile = this._register(new Emitter<readonly IWorkbenchMcpServerInstallResult[]>());
103 > readonly onDidInstallMcpServersInCurrentProfile = this._onDidInstallMcpServersInCurrentProfile.event;
104 >
105 > private readonly _onDidUpdateMcpServersInCurrentProfile = this._register(new Emitter<readonly IWorkbenchMcpServerInstallResult[]>());
106 > readonly onDidUpdateMcpServersInCurrentProfile = this._onDidUpdateMcpServersInCurrentProfile.event;
107 >
108 > private readonly _onUninstallMcpServerInCurrentProfile = this._register(new Emitter<UninstallWorkbenchMcpServerEvent>());
109 > readonly onUninstallMcpServerInCurrentProfile = this._onUninstallMcpServerInCurrentProfile.event;
110 >
111 > private readonly _onDidUninstallMcpServerInCurrentProfile = this._register(new Emitter<DidUninstallWorkbenchMcpServerEvent>());
112 > readonly onDidUninstallMcpServerInCurrentProfile = this._onDidUninstallMcpServerInCurrentProfile.event;
113 >
114 > private readonly _onDidChangeProfile = this._register(new Emitter<void>());
115 > readonly onDidChangeProfile = this._onDidChangeProfile.event;
116 >
117 > private readonly workspaceMcpManagementService: IMcpManagementService;
118 > private readonly remoteMcpManagementService: IMcpManagementService | undefined;
119 >
120 > constructor(
121 private readonly mcpManagementService: IMcpManagementService,
122 @IAllowedMcpServersService allowedMcpServersService: IAllowedMcpServersService,
237 }));
238 }
240 > private createInstallMcpServerResultsFromEvent(e: readonly InstallMcpServerResult[], scope: LocalMcpServerScope): { mcpServerInstallResult: IWorkbenchMcpServerInstallResult[]; mcpServerInstallResultInCurrentProfile: IWorkbenchMcpServerInstallResult[] } {
241 const mcpServerInstallResult: IWorkbenchMcpServerInstallResult[] = [];
242 const mcpServerInstallResultInCurrentProfile: IWorkbenchMcpServerInstallResult[] = [];
254 return { mcpServerInstallResult, mcpServerInstallResultInCurrentProfile };
255 }
257 > private async handleRemoteInstallMcpServerResultsFromEvent(e: readonly InstallMcpServerResult[], emitter: Emitter<readonly InstallMcpServerResult[]>, currentProfileEmitter: Emitter<readonly IWorkbenchMcpServerInstallResult[]>): Promise<void> {
258 const mcpServerInstallResult: IWorkbenchMcpServerInstallResult[] = [];
259 const mcpServerInstallResultInCurrentProfile: IWorkbenchMcpServerInstallResult[] = [];
275 }
276 }
278 > async getInstalled(): Promise<IWorkbenchLocalMcpServer[]> {
279 const installed: IWorkbenchLocalMcpServer[] = [];
280 const [userServers, remoteServers, workspaceServers] = await Promise.all([
296 return installed;
297 }
299 > private toWorkspaceMcpServer(server: ILocalMcpServer, scope: LocalMcpServerScope): IWorkbenchLocalMcpServer {
300 return { ...server, id: `mcp.config.${this.getConfigId(server, scope)}.${server.name}`, scope };
301 }
303 > private getConfigId(server: ILocalMcpServer, scope: LocalMcpServerScope): string {
304 if (scope === LocalMcpServerScope.User) {
305 return USER_CONFIG_ID;
326 return 'unknown';
327 }
329 > async install(server: IInstallableMcpServer, options?: IWorkbencMcpServerInstallOptions): Promise<IWorkbenchLocalMcpServer> {
330 options = options ?? {};
331
357 return this.toWorkspaceMcpServer(result, LocalMcpServerScope.User);
358 }
360 > async installFromGallery(server: IGalleryMcpServer, options?: IWorkbencMcpServerInstallOptions): Promise<IWorkbenchLocalMcpServer> {
361 options = options ?? {};
362
390 return this.toWorkspaceMcpServer(result, LocalMcpServerScope.User);
391 }
393 > async updateMetadata(local: IWorkbenchLocalMcpServer, server: IGalleryMcpServer, profileLocation: URI): Promise<IWorkbenchLocalMcpServer> {
394 if (local.scope === LocalMcpServerScope.Workspace) {
395 const result = await this.workspaceMcpManagementService.updateMetadata(local, server, profileLocation);
408 return this.toWorkspaceMcpServer(result, LocalMcpServerScope.User);
409 }
411 > async uninstall(server: IWorkbenchLocalMcpServer): Promise<void> {
412 if (server.scope === LocalMcpServerScope.Workspace) {
413 return this.workspaceMcpManagementService.uninstall(server);
423 return this.mcpManagementService.uninstall(server, { mcpResource: this.userDataProfileService.currentProfile.mcpResource });
424 }
426 > private async getRemoteMcpResource(mcpResource?: URI): Promise<URI | undefined> {
427 if (!mcpResource && this.userDataProfileService.currentProfile.isDefault) {
428 return undefined;
437 return profile?.mcpResource;
438 }
440 >
441 > class WorkspaceMcpResourceManagementService extends AbstractMcpResourceManagementService {
442 >
443 > constructor(
444 mcpResource: URI,
445 target: McpResourceTarget,
453 super(mcpResource, target, mcpGalleryService, fileService, uriIdentityService, logService, mcpResourceScannerService, allowedMcpServersService);
454 }
456 > override async installFromGallery(server: IGalleryMcpServer, options?: InstallOptions): Promise<ILocalMcpServer> {
457 this.logService.trace('MCP Management Service: installGallery', server.name, server.galleryUrl);
458
493 }
494 }
496 > override updateMetadata(): Promise<ILocalMcpServer> {
497 throw new Error('Not supported');
498 }
500 > protected override installFromUri(): Promise<ILocalMcpServer> {
501 throw new Error('Not supported');
502 }
504 > protected override async getLocalServerInfo(name: string, mcpServerConfig: IMcpServerConfiguration): Promise<ILocalMcpServerInfo | undefined> {
505 if (!mcpServerConfig.gallery) {
506 return undefined;
525 };
526 }
528 > override canInstall(server: IGalleryMcpServer | IInstallableMcpServer): true | IMarkdownString {
529 throw new Error('Not supported');
530 }
532 >
533 > class WorkspaceMcpManagementService extends AbstractMcpManagementService implements IMcpManagementService {
534 >
535 > private readonly _onInstallMcpServer = this._register(new Emitter<InstallMcpServerEvent>());
536 > readonly onInstallMcpServer = this._onInstallMcpServer.event;
537 >
538 > private readonly _onDidInstallMcpServers = this._register(new Emitter<readonly InstallMcpServerResult[]>());
539 > readonly onDidInstallMcpServers = this._onDidInstallMcpServers.event;
540 >
541 > private readonly _onDidUpdateMcpServers = this._register(new Emitter<readonly InstallMcpServerResult[]>());
542 > readonly onDidUpdateMcpServers = this._onDidUpdateMcpServers.event;
543 >
544 > private readonly _onUninstallMcpServer = this._register(new Emitter<UninstallMcpServerEvent>());
545 > readonly onUninstallMcpServer = this._onUninstallMcpServer.event;
546 >
547 > private readonly _onDidUninstallMcpServer = this._register(new Emitter<DidUninstallMcpServerEvent>());
548 > readonly onDidUninstallMcpServer = this._onDidUninstallMcpServer.event;
549 >
550 > private allMcpServers: ILocalMcpServer[] = [];
551 >
552 > private workspaceConfiguration?: URI | null;
553 > private readonly workspaceMcpManagementServices = new ResourceMap<{ service: WorkspaceMcpResourceManagementService } & IDisposable>();
554 >
555 > constructor(
556 @IAllowedMcpServersService allowedMcpServersService: IAllowedMcpServersService,
557 @IUriIdentityService private readonly uriIdentityService: IUriIdentityService,
563 this.initialize();
564 }
566 > private async initialize(): Promise<void> {
567 try {
568 await this.onDidChangeWorkbenchState();
574 }
575 }
577 > private async onDidChangeWorkbenchState(): Promise<void> {
578 if (this.workspaceConfiguration) {
579 await this.removeWorkspaceService(this.workspaceConfiguration);
584 }
585 }
587 > private async onDidChangeWorkspaceFolders(e: IWorkspaceFoldersChangeEvent): Promise<void> {
588 try {
589 await Promise.allSettled(e.removed.map(folder => this.removeWorkspaceService(folder.toResource(WORKSPACE_STANDALONE_CONFIGURATIONS[MCP_CONFIGURATION_KEY]))));
597 }
598 }
600 > private async addWorkspaceService(mcpResource: URI, target: McpResourceTarget): Promise<void> {
601 if (this.workspaceMcpManagementServices.has(mcpResource)) {
602 return;
651 this.workspaceMcpManagementServices.set(mcpResource, { service, dispose: () => disposables.dispose() });
652 }
654 > private async removeWorkspaceService(mcpResource: URI): Promise<void> {
655 const serviceItem = this.workspaceMcpManagementServices.get(mcpResource);
656 if (serviceItem) {
671 }
672 }
674 > async getInstalled(): Promise<ILocalMcpServer[]> {
675 return this.allMcpServers;
676 }
678 > async install(server: IInstallableMcpServer, options?: InstallOptions): Promise<ILocalMcpServer> {
679 if (!options?.mcpResource) {
680 throw new Error('MCP resource is required');
688 return mcpManagementServiceItem.service.install(server, options);
689 }
691 > async uninstall(server: ILocalMcpServer, options?: UninstallOptions): Promise<void> {
692 const mcpResource = server.mcpResource;
693
699 return mcpManagementServiceItem.service.uninstall(server, options);
700 }
702 > installFromGallery(gallery: IGalleryMcpServer, options?: InstallOptions): Promise<ILocalMcpServer> {
703 if (!options?.mcpResource) {
704 throw new Error('MCP resource is required');
712 return mcpManagementServiceItem.service.installFromGallery(gallery, options);
713 }
715 > updateMetadata(): Promise<ILocalMcpServer> {
716 throw new Error('Not supported');
717 }
719 > override dispose(): void {
720 this.workspaceMcpManagementServices.forEach(service => service.dispose());
721 this.workspaceMcpManagementServices.clear();
722 super.dispose();
723 }
src/vs/platform/telemetry/common/telemetryUtils.ts 199 covered LOC · 15 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- telemetryUtils.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { cloneAndChange, safeStringify } from '../../../base/common/objects.js';
7 > import { isObject } from '../../../base/common/types.js';
8 > import { URI } from '../../../base/common/uri.js';
9 > import { localize } from '../../../nls.js';
10 > import { IConfigurationService } from '../../configuration/common/configuration.js';
11 > import { IEnvironmentService } from '../../environment/common/environment.js';
12 > import { LoggerGroup } from '../../log/common/log.js';
13 > import { IProductService } from '../../product/common/productService.js';
14 > import { getRemoteName } from '../../remote/common/remoteHosts.js';
15 > import { verifyMicrosoftInternalDomain } from './commonProperties.js';
16 > import { ICustomEndpointTelemetryService, ITelemetryData, ITelemetryEndpoint, ITelemetryService, TelemetryConfiguration, TelemetryLevel, TELEMETRY_CRASH_REPORTER_SETTING_ID, TELEMETRY_OLD_SETTING_ID, TELEMETRY_SETTING_ID } from './telemetry.js';
17 >
18 > /**
19 > * A special class used to denoting a telemetry value which should not be clean.
20 > * This is because that value is "Trusted" not to contain identifiable information such as paths.
21 > * NOTE: This is used as an API type as well, and should not be changed.
22 > */
23 > export class TelemetryTrustedValue<T> {
24 > // This is merely used as an identifier as the instance will be lost during serialization over the exthost
25 > public readonly isTrustedTelemetryValue = true;
26 > constructor(public readonly value: T) { }
27 > }
28 >
29 > export class NullTelemetryServiceShape implements ITelemetryService {
30 > declare readonly _serviceBrand: undefined;
31 > readonly telemetryLevel = TelemetryLevel.NONE;
32 > readonly sessionId = 'someValue.sessionId';
33 > readonly machineId = 'someValue.machineId';
34 > readonly sqmId = 'someValue.sqmId';
35 > readonly devDeviceId = 'someValue.devDeviceId';
36 > readonly firstSessionDate = 'someValue.firstSessionDate';
37 > readonly sendErrorTelemetry = false;
38 > publicLog() { }
39 > publicLog2() { }
40 > publicLogError() { }
41 > publicLogError2() { }
42 > setExperimentProperty() { }
43 > setCommonProperty() { }
44 > }
45 >
46 > export const NullTelemetryService = new NullTelemetryServiceShape();
47 >
48 > export class NullEndpointTelemetryService implements ICustomEndpointTelemetryService {
49 > _serviceBrand: undefined;
50 >
51 > async publicLog(_endpoint: ITelemetryEndpoint, _eventName: string, _data?: ITelemetryData): Promise<void> {
52 // noop
53 }
55 > async publicLogError(_endpoint: ITelemetryEndpoint, _errorEventName: string, _data?: ITelemetryData): Promise<void> {
56 // noop
57 }
59 >
60 > export const telemetryLogId = 'telemetry';
61 > export const TelemetryLogGroup: LoggerGroup = { id: telemetryLogId, name: localize('telemetryLogName', "Telemetry") };
62 >
63 > export interface ITelemetryAppender {
64 > log(eventName: string, data: ITelemetryData): void;
65 > flush(): Promise<void>;
66 > }
67 >
68 > export const NullAppender: ITelemetryAppender = { log: () => null, flush: () => Promise.resolve(undefined) };
69 >
70 >
71 > /* __GDPR__FRAGMENT__
72 > "URIDescriptor" : {
73 > "mimeType" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
74 > "scheme": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
75 > "ext": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
76 > "path": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
77 > }
78 > */
79 > export interface URIDescriptor {
80 > mimeType?: string;
81 > scheme?: string;
82 > ext?: string;
83 > path?: string;
84 > }
85 >
86 > /**
87 > * Determines whether or not we support logging telemetry.
88 > * This checks if the product is capable of collecting telemetry but not whether or not it can send it
89 > * For checking the user setting and what telemetry you can send please check `getTelemetryLevel`.
90 > * This returns true if `--disable-telemetry` wasn't used, the product.json allows for telemetry, and we're not testing an extension
91 > * If false telemetry is disabled throughout the product
92 > * @param productService
93 > * @param environmentService
94 > * @returns false - telemetry is completely disabled, true - telemetry is logged locally, but may not be sent
95 > */
96 > export function supportsTelemetry(productService: IProductService, environmentService: IEnvironmentService): boolean {
97 // If it's OSS and telemetry isn't disabled via the CLI we will allow it for logging only purposes
98 if (!environmentService.isBuilt && !environmentService.disableTelemetry) {
101 return !(environmentService.disableTelemetry || !productService.enableTelemetry);
102 }
104 > /**
105 > * Checks to see if we're in logging only mode to debug telemetry.
106 > * This is if telemetry is enabled and we're in OSS, but no telemetry key is provided so it's not being sent just logged.
107 > * @param productService
108 > * @param environmentService
109 > * @returns True if telemetry is actually disabled and we're only logging for debug purposes
110 > */
111 > export function isLoggingOnly(productService: IProductService, environmentService: IEnvironmentService): boolean {
112 // If we're testing an extension, log telemetry for debug purposes
113 if (environmentService.extensionTestsLocationURI) {
129 return true;
130 }
132 > /**
133 > * Determines how telemetry is handled based on the user's configuration.
134 > *
135 > * @param configurationService
136 > * @returns OFF, ERROR, ON
137 > */
138 > export function getTelemetryLevel(configurationService: IConfigurationService): TelemetryLevel {
139 const newConfig = configurationService.getValue<TelemetryConfiguration>(TELEMETRY_SETTING_ID);
140 const crashReporterConfig = configurationService.getValue<boolean | undefined>(TELEMETRY_CRASH_REPORTER_SETTING_ID);
158 }
159 }
161 > export interface Properties {
162 > [key: string]: string;
163 > }
164 >
165 > export interface Measurements {
166 > [key: string]: number;
167 > }
168 >
169 > export function validateTelemetryData(data?: unknown): { properties: Properties; measurements: Measurements } {
170
171 const properties: Properties = {};
204 };
205 }
207 > interface IRemoteAuthoringConfig {
208 > remoteExtensionTips?: { readonly [remoteName: string]: unknown };
209 > virtualWorkspaceExtensionTips?: { readonly [remoteName: string]: unknown };
210 > }
211 >
212 > export function cleanRemoteAuthority(remoteAuthority: string | undefined, config: IRemoteAuthoringConfig): string {
213 if (!remoteAuthority) {
214 return 'none';
229 return 'other';
230 }
232 function flatten(obj: unknown, result: Record<string, unknown>, order: number = 0, prefix?: string): void {
233 if (!obj || (typeof obj !== 'object' && typeof obj !== 'function')) {
258 }
259 }
261 > /**
262 > * Whether or not this is an internal user
263 > * @param productService The product service
264 > * @param configService The config servivce
265 > * @returns true if internal, false otherwise
266 > */
267 > export function isInternalTelemetry(productService: IProductService, configService: IConfigurationService) {
268 const msftInternalDomains = productService.msftInternalDomains || [];
269 const internalTesting = configService.getValue<boolean>('telemetry.internalTesting');
270 return verifyMicrosoftInternalDomain(msftInternalDomains) || internalTesting;
271 }
273 > interface IPathEnvironment {
274 > appRoot: string;
275 > extensionsPath: string;
276 > userDataPath: string;
277 > userHome: URI;
278 > tmpDir: URI;
279 > }
280 >
281 > export function getPiiPathsFromEnvironment(paths: IPathEnvironment): string[] {
282 return [paths.appRoot, paths.extensionsPath, paths.userHome.fsPath, paths.tmpDir.fsPath, paths.userDataPath];
283 }
285 > //#region Telemetry Cleaning
286 >
287 > /**
288 > * Cleans a given stack of possible paths
289 > * @param stack The stack to sanitize
290 > * @param cleanupPatterns Cleanup patterns to remove from the stack
291 > * @returns The cleaned stack
292 > */
293 function anonymizeFilePaths(stack: string, cleanupPatterns: RegExp[]): string {
294
356 return updatedStack;
357 }
359 > const userDataRegexes = [
360 > { label: 'URL', regex: /[a-zA-Z][a-zA-Z0-9+.-]*:\/\/[^\s]*/ },
361 > { label: 'Google API Key', regex: /AIza[A-Za-z0-9_\\\-]{35}/ },
362 > { label: 'JWT', regex: /eyJ[0eXAiOiJKV1Qi|hbGci|a-zA-Z0-9\-_]+\.[a-zA-Z0-9\-_]+\.[a-zA-Z0-9\-_]+/ },
363 > { label: 'Slack Token', regex: /xox[pbar]\-[A-Za-z0-9]/ },
364 > { label: 'GitHub Token', regex: /(gh[psuro]_[a-zA-Z0-9]{36}|github_pat_[a-zA-Z0-9]{22}_[a-zA-Z0-9]{59})/ },
365 > { label: 'Generic Secret', regex: /(key|token|sig|secret|signature|password|passwd|pwd|android:value)[^a-zA-Z0-9]/i },
366 > { label: 'CLI Credentials', regex: /((login|psexec|(certutil|psexec)\.exe).{1,50}(\s-u(ser(name)?)?\s+.{3,100})?\s-(admin|user|vm|root)?p(ass(word)?)?\s+["']?[^$\-\/\s]|(^|[\s\r\n\\])net(\.exe)?.{1,5}(user\s+|share\s+\/user:| user -? secrets ? set) \s + [^ $\s \/])/ },
367 > { label: 'Microsoft Entra ID', regex: /eyJ(?:0eXAiOiJKV1Qi|hbGci|[a-zA-Z0-9\-_]+\.[a-zA-Z0-9\-_]+\.)/ },
368 > { label: 'Email', regex: /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/ }
369 > ];
370 >
371 > /**
372 > * Redacts a value if it contains commonly leaked PII.
373 > * @param value The value returned (as-is) when no PII is detected
374 > * @param probe The string actually matched against the PII heuristics. Defaults
375 > * to `value`; callers may pass a value that includes a trailing delimiter (e.g. a
376 > * newline) so that heuristics relying on a non-alphanumeric boundary match the
377 > * same way they would against the original whole string.
378 > * @returns A `<REDACTED: ...>` marker if the probe matched, otherwise `value`
379 > */
380 function redactIfPossibleUserInfo(value: string, probe: string = value): string {
381 for (const secretRegex of userDataRegexes) {
386 return value;
387 }
389 > /**
390 > * Attempts to remove commonly leaked PII.
391 > *
392 > * When a match is found the check is applied per line so that a single suspicious
393 > * frame (e.g. a stack frame containing a function name such as `getStorageKey`
394 > * which matches the broad `Generic Secret` heuristic) only redacts that line —
395 > * replacing it with a `<REDACTED: ...>` marker — instead of wiping the entire
396 > * multi-line value such as a whole callstack.
397 > * @param property The property whose offending lines will be replaced with a redaction marker if they contain user data
398 > * @returns The new value for the property
399 > */
400 function removePropertiesWithPossibleUserInfo(property: string): string {
401 // If for some reason it is undefined we skip it (this shouldn't be possible);
436 return lines.join('\n');
437 }
439 >
440 > /**
441 > * Does a best possible effort to clean a data object from any possible PII.
442 > * @param data The data object to clean
443 > * @param paths Any additional patterns that should be removed from the data set
444 > * @returns A new object with the PII removed
445 > */
446 > export function cleanData(data: ITelemetryData | undefined, cleanUpPatterns: RegExp[]): Record<string, unknown> {
447 if (!data) {
448 return {};
src/vs/platform/mcp/common/mcpManagementService.ts 198 covered LOC · 36 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- mcpManagementService.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { RunOnceScheduler } from '../../../base/common/async.js';
7 > import { VSBuffer } from '../../../base/common/buffer.js';
8 > import { CancellationToken } from '../../../base/common/cancellation.js';
9 > import { Emitter, Event } from '../../../base/common/event.js';
10 > import { IMarkdownString, MarkdownString } from '../../../base/common/htmlContent.js';
11 > import { Disposable, DisposableStore, IDisposable } from '../../../base/common/lifecycle.js';
12 > import { ResourceMap } from '../../../base/common/map.js';
13 > import { equals } from '../../../base/common/objects.js';
14 > import { isString } from '../../../base/common/types.js';
15 > import { URI } from '../../../base/common/uri.js';
16 > import { localize } from '../../../nls.js';
17 > import { ConfigurationTarget } from '../../configuration/common/configuration.js';
18 > import { IEnvironmentService } from '../../environment/common/environment.js';
19 > import { IFileService } from '../../files/common/files.js';
20 > import { IInstantiationService } from '../../instantiation/common/instantiation.js';
21 > import { ILogService } from '../../log/common/log.js';
22 > import { IUriIdentityService } from '../../uriIdentity/common/uriIdentity.js';
23 > import { IUserDataProfilesService } from '../../userDataProfile/common/userDataProfile.js';
24 > import { DidUninstallMcpServerEvent, IGalleryMcpServer, ILocalMcpServer, IMcpGalleryService, IMcpManagementService, IMcpServerInput, IGalleryMcpServerConfiguration, InstallMcpServerEvent, InstallMcpServerResult, RegistryType, UninstallMcpServerEvent, InstallOptions, UninstallOptions, IInstallableMcpServer, IAllowedMcpServersService, IMcpServerArgument, IMcpServerKeyValueInput, McpServerConfigurationParseResult } from './mcpManagement.js';
25 > import { IMcpSandboxConfiguration, IMcpServerVariable, McpServerVariableType, IMcpServerConfiguration, McpServerType } from './mcpPlatformTypes.js';
26 > import { IMcpResourceScannerService, McpResourceTarget } from './mcpResourceScannerService.js';
27 >
28 > export interface ILocalMcpServerInfo {
29 > name: string;
30 > version?: string;
31 > displayName?: string;
32 > galleryId?: string;
33 > galleryUrl?: string;
34 > description?: string;
35 > repositoryUrl?: string;
36 > publisher?: string;
37 > publisherDisplayName?: string;
38 > icon?: {
39 > dark: string;
40 > light: string;
41 > };
42 > codicon?: string;
43 > manifest?: IGalleryMcpServerConfiguration;
44 > readmeUrl?: URI;
45 > location?: URI;
46 > licenseUrl?: string;
47 > }
48 >
49 > export abstract class AbstractCommonMcpManagementService extends Disposable implements IMcpManagementService {
50 >
51 > _serviceBrand: undefined;
52 >
53 > abstract onInstallMcpServer: Event<InstallMcpServerEvent>;
54 > abstract onDidInstallMcpServers: Event<readonly InstallMcpServerResult[]>;
55 > abstract onDidUpdateMcpServers: Event<readonly InstallMcpServerResult[]>;
56 > abstract onUninstallMcpServer: Event<UninstallMcpServerEvent>;
57 > abstract onDidUninstallMcpServer: Event<DidUninstallMcpServerEvent>;
58 >
59 > abstract getInstalled(mcpResource?: URI): Promise<ILocalMcpServer[]>;
60 > abstract install(server: IInstallableMcpServer, options?: InstallOptions): Promise<ILocalMcpServer>;
61 > abstract installFromGallery(server: IGalleryMcpServer, options?: InstallOptions): Promise<ILocalMcpServer>;
62 > abstract updateMetadata(local: ILocalMcpServer, server: IGalleryMcpServer, profileLocation?: URI): Promise<ILocalMcpServer>;
63 > abstract uninstall(server: ILocalMcpServer, options?: UninstallOptions): Promise<void>;
64 > abstract canInstall(server: IGalleryMcpServer | IInstallableMcpServer): true | IMarkdownString;
65 >
66 > constructor(
67 @ILogService protected readonly logService: ILogService
68 ) {
69 super();
70 }
72 > getMcpServerConfigurationFromManifest(manifest: IGalleryMcpServerConfiguration, packageType: RegistryType): McpServerConfigurationParseResult {
73
74 // remote
180 };
181 }
183 > protected getCommandName(packageType: RegistryType): string {
184 switch (packageType) {
185 case RegistryType.NODE: return 'npx';
190 return packageType;
191 }
193 > protected getVariables(variableInputs: Record<string, IMcpServerInput>): IMcpServerVariable[] {
194 const variables: IMcpServerVariable[] = [];
195 for (const [key, value] of Object.entries(variableInputs)) {
205 return variables;
206 }
208 > private processKeyValueInputs(keyValueInputs: ReadonlyArray<IMcpServerKeyValueInput>): { inputs: Record<string, string>; variables: IMcpServerVariable[]; notices: string[] } {
209 const notices: string[] = [];
210 const inputs: Record<string, string> = {};
239 return { inputs, variables, notices };
240 }
242 > private processArguments(argumentsList: readonly IMcpServerArgument[]): { args: string[]; variables: IMcpServerVariable[]; notices: string[] } {
243 const args: string[] = [];
244 const variables: IMcpServerVariable[] = [];
302 return { args, variables, notices };
303 }
305 > }
306 >
307 > export abstract class AbstractMcpResourceManagementService extends AbstractCommonMcpManagementService {
308 >
309 > private initializePromise: Promise<void> | undefined;
310 > private readonly reloadConfigurationScheduler: RunOnceScheduler;
311 > private local = new Map<string, ILocalMcpServer>();
312 >
313 > protected readonly _onInstallMcpServer = this._register(new Emitter<InstallMcpServerEvent>());
314 > readonly onInstallMcpServer = this._onInstallMcpServer.event;
315 >
316 > protected readonly _onDidInstallMcpServers = this._register(new Emitter<InstallMcpServerResult[]>());
317 > get onDidInstallMcpServers() { return this._onDidInstallMcpServers.event; }
318 >
319 > protected readonly _onDidUpdateMcpServers = this._register(new Emitter<InstallMcpServerResult[]>());
320 > get onDidUpdateMcpServers() { return this._onDidUpdateMcpServers.event; }
321 >
322 > protected readonly _onUninstallMcpServer = this._register(new Emitter<UninstallMcpServerEvent>());
323 > get onUninstallMcpServer() { return this._onUninstallMcpServer.event; }
324 >
325 > protected _onDidUninstallMcpServer = this._register(new Emitter<DidUninstallMcpServerEvent>());
326 > get onDidUninstallMcpServer() { return this._onDidUninstallMcpServer.event; }
327 >
328 > constructor(
329 protected readonly mcpResource: URI,
330 protected readonly target: McpResourceTarget,
339 this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this.updateLocal(), 50));
340 }
342 > /**
343 > * Enforces the enterprise allow/deny policy at the point of persistence. Called by every
344 > * install path (installable and each gallery override) against the fully resolved server
345 > * configuration, so a caller that goes straight to the management API cannot bypass the
346 > * `canInstall` UI check, and a gallery entry cannot slip through if its resolved command/URL
347 > * differs from the pre-resolution metadata.
348 > */
349 > protected ensureServerAllowed(server: IGalleryMcpServer | IInstallableMcpServer): void {
350 const result = this.allowedMcpServersService.isAllowed(server);
351 if (result !== true) {
353 }
354 }
356 > private initialize(): Promise<void> {
357 if (!this.initializePromise) {
358 this.initializePromise = (async () => {
366 return this.initializePromise;
367 }
369 > private async populateLocalServers(): Promise<Map<string, ILocalMcpServer>> {
370 this.logService.trace('AbstractMcpResourceManagementService#populateLocalServers', this.mcpResource.toString());
371 const local = new Map<string, ILocalMcpServer>();
384 return local;
385 }
387 > private startWatching(): void {
388 this._register(this.fileService.watch(this.mcpResource));
389 this._register(this.fileService.onDidFilesChange(e => {
393 }));
394 }
396 > protected async updateLocal(): Promise<void> {
397 try {
398 const current = await this.populateLocalServers();
436 }
437 }
439 > async getInstalled(): Promise<ILocalMcpServer[]> {
440 await this.initialize();
441 return Array.from(this.local.values());
442 }
444 > protected async scanLocalServer(name: string, config: IMcpServerConfiguration, rootSandbox?: IMcpSandboxConfiguration): Promise<ILocalMcpServer> {
445 let mcpServerInfo = await this.getLocalServerInfo(name, config);
446 if (!mcpServerInfo) {
469 };
470 }
472 > async install(server: IInstallableMcpServer, options?: Omit<InstallOptions, 'mcpResource'>): Promise<ILocalMcpServer> {
473 this.logService.trace('MCP Management Service: install', server.name);
474 this.ensureServerAllowed(server);
488 }
489 }
491 > async uninstall(server: ILocalMcpServer, options?: Omit<UninstallOptions, 'mcpResource'>): Promise<void> {
492 this.logService.trace('MCP Management Service: uninstall', server.name);
493 this._onUninstallMcpServer.fire({ name: server.name, mcpResource: this.mcpResource });
508 }
509 }
511 > protected abstract getLocalServerInfo(name: string, mcpServerConfig: IMcpServerConfiguration): Promise<ILocalMcpServerInfo | undefined>;
512 > protected abstract installFromUri(uri: URI, options?: Omit<InstallOptions, 'mcpResource'>): Promise<ILocalMcpServer>;
513 > }
514 >
515 > export class McpUserResourceManagementService extends AbstractMcpResourceManagementService {
516 >
517 > protected readonly mcpLocation: URI;
518 >
519 > constructor(
520 mcpResource: URI,
521 @IMcpGalleryService mcpGalleryService: IMcpGalleryService,
530 this.mcpLocation = uriIdentityService.extUri.joinPath(environmentService.userRoamingDataHome, 'mcp');
531 }
533 > async installFromGallery(server: IGalleryMcpServer, options?: InstallOptions): Promise<ILocalMcpServer> {
534 throw new Error('Not supported');
535 }
537 > async updateMetadata(local: ILocalMcpServer, gallery: IGalleryMcpServer): Promise<ILocalMcpServer> {
538 await this.updateMetadataFromGallery(gallery);
539 await this.updateLocal();
544 return updatedLocal;
545 }
547 > protected async updateMetadataFromGallery(gallery: IGalleryMcpServer): Promise<IGalleryMcpServerConfiguration> {
548 const manifest = gallery.configuration;
549 const location = this.getLocation(gallery.name, gallery.version);
573 return manifest;
574 }
576 > protected async getLocalServerInfo(name: string, mcpServerConfig: IMcpServerConfiguration): Promise<ILocalMcpServerInfo | undefined> {
577 let storedMcpServerInfo: ILocalMcpServerInfo | undefined;
578 let location: URI | undefined;
603 return storedMcpServerInfo;
604 }
606 > protected getLocation(name: string, version?: string): URI {
607 name = name.replace('/', '.');
608 return this.uriIdentityService.extUri.joinPath(this.mcpLocation, version ? `${name}-${version}` : name);
609 }
611 > protected override installFromUri(uri: URI, options?: Omit<InstallOptions, 'mcpResource'>): Promise<ILocalMcpServer> {
612 throw new Error('Method not supported.');
613 }
615 > override canInstall(): true | IMarkdownString {
616 throw new Error('Not supported');
617 }
619 > }
620 >
621 > export abstract class AbstractMcpManagementService extends AbstractCommonMcpManagementService implements IMcpManagementService {
622 >
623 > constructor(
624 @IAllowedMcpServersService protected readonly allowedMcpServersService: IAllowedMcpServersService,
625 @ILogService logService: ILogService,
627 super(logService);
628 }
630 > canInstall(server: IGalleryMcpServer | IInstallableMcpServer): true | IMarkdownString {
631 const allowedToInstall = this.allowedMcpServersService.isAllowed(server);
632 if (allowedToInstall !== true) {
635 return true;
636 }
638 >
639 > export class McpManagementService extends AbstractMcpManagementService implements IMcpManagementService {
640 >
641 > private readonly _onInstallMcpServer = this._register(new Emitter<InstallMcpServerEvent>());
642 > readonly onInstallMcpServer = this._onInstallMcpServer.event;
643 >
644 > private readonly _onDidInstallMcpServers = this._register(new Emitter<readonly InstallMcpServerResult[]>());
645 > readonly onDidInstallMcpServers = this._onDidInstallMcpServers.event;
646 >
647 > private readonly _onDidUpdateMcpServers = this._register(new Emitter<readonly InstallMcpServerResult[]>());
648 > readonly onDidUpdateMcpServers = this._onDidUpdateMcpServers.event;
649 >
650 > private readonly _onUninstallMcpServer = this._register(new Emitter<UninstallMcpServerEvent>());
651 > readonly onUninstallMcpServer = this._onUninstallMcpServer.event;
652 >
653 > private readonly _onDidUninstallMcpServer = this._register(new Emitter<DidUninstallMcpServerEvent>());
654 > readonly onDidUninstallMcpServer = this._onDidUninstallMcpServer.event;
655 >
656 > private readonly mcpResourceManagementServices = new ResourceMap<{ service: McpUserResourceManagementService } & IDisposable>();
657 >
658 > constructor(
659 @IAllowedMcpServersService allowedMcpServersService: IAllowedMcpServersService,
660 @ILogService logService: ILogService,
664 super(allowedMcpServersService, logService);
665 }
667 > private getMcpResourceManagementService(mcpResource: URI): McpUserResourceManagementService {
668 let mcpResourceManagementService = this.mcpResourceManagementServices.get(mcpResource);
669 if (!mcpResourceManagementService) {
679 return mcpResourceManagementService.service;
680 }
682 > async getInstalled(mcpResource?: URI): Promise<ILocalMcpServer[]> {
683 const mcpResourceUri = mcpResource || this.userDataProfilesService.defaultProfile.mcpResource;
684 return this.getMcpResourceManagementService(mcpResourceUri).getInstalled();
685 }
687 > async install(server: IInstallableMcpServer, options?: InstallOptions): Promise<ILocalMcpServer> {
688 const mcpResourceUri = options?.mcpResource || this.userDataProfilesService.defaultProfile.mcpResource;
689 return this.getMcpResourceManagementService(mcpResourceUri).install(server, options);
690 }
692 > async uninstall(server: ILocalMcpServer, options?: UninstallOptions): Promise<void> {
693 const mcpResourceUri = options?.mcpResource || this.userDataProfilesService.defaultProfile.mcpResource;
694 return this.getMcpResourceManagementService(mcpResourceUri).uninstall(server, options);
695 }
697 > async installFromGallery(server: IGalleryMcpServer, options?: InstallOptions): Promise<ILocalMcpServer> {
698 const mcpResourceUri = options?.mcpResource || this.userDataProfilesService.defaultProfile.mcpResource;
699 return this.getMcpResourceManagementService(mcpResourceUri).installFromGallery(server, options);
700 }
702 > async updateMetadata(local: ILocalMcpServer, gallery: IGalleryMcpServer, mcpResource?: URI): Promise<ILocalMcpServer> {
703 return this.getMcpResourceManagementService(mcpResource || this.userDataProfilesService.defaultProfile.mcpResource).updateMetadata(local, gallery);
704 }
706 > override dispose(): void {
707 this.mcpResourceManagementServices.forEach(service => service.dispose());
708 this.mcpResourceManagementServices.clear();
709 super.dispose();
710 }
712 > protected createMcpResourceManagementService(mcpResource: URI): McpUserResourceManagementService {
713 return this.instantiationService.createInstance(McpUserResourceManagementService, mcpResource);
714 }
716 > }
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/validation.ts 190 covered LOC · 48 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- validation.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { mapFilter } from './arrays.js';
7 > import { IJSONSchema } from './jsonSchema.js';
8 >
9 > export interface IValidator<T> {
10 > validate(content: unknown): { content: T; error: undefined } | { content: undefined; error: ValidationError };
11 >
12 > getJSONSchema(): IJSONSchema;
13 > }
14 >
15 > export abstract class ValidatorBase<T> implements IValidator<T> {
16 > abstract validate(content: unknown): { content: T; error: undefined } | { content: undefined; error: ValidationError };
17 >
18 > abstract getJSONSchema(): IJSONSchema;
19 >
20 > validateOrThrow(content: unknown): T {
21 const result = this.validate(content);
22 if (result.error) {
25 return result.content;
26 }
27 > } validation.ts
28 >
29 > export type ValidatorType<T> = T extends IValidator<infer U> ? U : never;
30 >
31 > export interface ValidationError {
32 > message: string;
33 > }
34 >
35 > type TypeOfMap = {
36 > string: string;
37 > number: number;
38 > boolean: boolean;
39 > object: object;
40 > null: null;
41 > };
42 >
43 > class TypeofValidator<TKey extends keyof TypeOfMap> extends ValidatorBase<TypeOfMap[TKey]> {
44 > constructor(private readonly type: TKey) {
45 > super();
46 > }
47 >
48 > validate(content: unknown): { content: TypeOfMap[TKey]; error: undefined } | { content: undefined; error: ValidationError } {
49 if (typeof content !== this.type) {
50 return { content: undefined, error: { message: `Expected ${this.type}, but got ${typeof content}` } };
53 return { content: content as TypeOfMap[TKey], error: undefined };
54 }
56 > getJSONSchema(): IJSONSchema {
57 return { type: this.type };
58 }
59 > } validation.ts
60 >
61 > const vStringValidator = new TypeofValidator('string');
62 > export function vString(): ValidatorBase<string> { return vStringValidator; }
63 >
64 > const vNumberValidator = new TypeofValidator('number');
65 > export function vNumber(): ValidatorBase<number> { return vNumberValidator; }
66 >
67 > const vBooleanValidator = new TypeofValidator('boolean');
68 > export function vBoolean(): ValidatorBase<boolean> { return vBooleanValidator; }
69 >
70 > const vObjAnyValidator = new TypeofValidator('object');
71 > export function vObjAny(): ValidatorBase<object> { return vObjAnyValidator; }
72 >
73 >
74 > class UncheckedValidator<T> extends ValidatorBase<T> {
75 > validate(content: unknown): { content: T; error: undefined } {
76 return { content: content as T, error: undefined };
77 }
79 > getJSONSchema(): IJSONSchema {
80 return {};
81 }
82 > } validation.ts
83 >
84 > export function vUnchecked<T>(): ValidatorBase<T> {
85 return new UncheckedValidator<T>();
86 }
88 > class UndefinedValidator extends ValidatorBase<undefined> {
89 > validate(content: unknown): { content: undefined; error: undefined } | { content: undefined; error: ValidationError } {
90 if (content !== undefined) {
91 return { content: undefined, error: { message: `Expected undefined, but got ${typeof content}` } };
94 return { content: undefined, error: undefined };
95 }
97 > getJSONSchema(): IJSONSchema {
98 return {};
99 }
100 > } validation.ts
101 >
102 > export function vUndefined(): ValidatorBase<undefined> {
103 return new UndefinedValidator();
104 }
106 > export function vUnknown(): ValidatorBase<unknown> {
107 return vUnchecked();
108 }
110 > export type ObjectProperties = Record<string, unknown>;
111 >
112 > export class Optional<T extends IValidator<unknown>> {
113 > constructor(public readonly validator: T) { }
114 > }
115 >
116 > export function vOptionalProp<T>(validator: IValidator<T>): Optional<IValidator<T>> {
117 > return new Optional(validator); validation.ts
118 > }
120 > type ExtractOptionalKeys<T> = {
121 > [K in keyof T]: T[K] extends Optional<IValidator<unknown>> ? K : never;
122 > }[keyof T];
123 >
124 > type ExtractRequiredKeys<T> = {
125 > [K in keyof T]: T[K] extends Optional<IValidator<unknown>> ? never : K;
126 > }[keyof T];
127 >
128 > export type vObjType<T extends Record<string, IValidator<unknown> | Optional<IValidator<unknown>>>> = {
129 > [K in ExtractRequiredKeys<T>]: T[K] extends IValidator<infer U> ? U : never;
130 > } & {
131 > [K in ExtractOptionalKeys<T>]?: T[K] extends Optional<IValidator<infer U>> ? U : never;
132 > };
133 >
134 > class ObjValidator<T extends Record<string, IValidator<unknown> | Optional<IValidator<unknown>>>> extends ValidatorBase<vObjType<T>> {
135 > constructor(private readonly properties: T) {
136 > super(); validation.ts
137 > }
139 > validate(content: unknown): { content: vObjType<T>; error: undefined } | { content: undefined; error: ValidationError } {
140 if (typeof content !== 'object' || content === null) {
141 return { content: undefined, error: { message: 'Expected object' } };
169 return { content: result, error: undefined };
170 }
172 > getJSONSchema(): IJSONSchema {
173 const requiredFields: string[] = [];
174 const schemaProperties: Record<string, IJSONSchema> = {};
191 return schema;
192 }
193 > } validation.ts
194 >
195 > export function vObj<T extends Record<string, IValidator<unknown> | Optional<IValidator<unknown>>>>(properties: T): ValidatorBase<vObjType<T>> {
196 > return new ObjValidator(properties); validation.ts
197 > }
199 > class ArrayValidator<T> extends ValidatorBase<T[]> {
200 > constructor(private readonly validator: IValidator<T>) {
201 > super(); validation.ts
202 > }
204 > validate(content: unknown): { content: T[]; error: undefined } | { content: undefined; error: ValidationError } {
205 if (!Array.isArray(content)) {
206 return { content: undefined, error: { message: 'Expected array' } };
219 return { content: result, error: undefined };
220 }
222 > getJSONSchema(): IJSONSchema {
223 return {
224 type: 'array',
226 };
227 }
228 > } validation.ts
229 >
230 > export function vArray<T>(validator: IValidator<T>): ValidatorBase<T[]> {
231 > return new ArrayValidator(validator); validation.ts
232 > }
234 > type vTupleType<T extends IValidator<unknown>[]> = { [K in keyof T]: ValidatorType<T[K]> };
235 >
236 > class TupleValidator<T extends IValidator<unknown>[]> extends ValidatorBase<vTupleType<T>> {
237 > constructor(private readonly validators: T) {
238 super();
239 }
241 > validate(content: unknown): { content: vTupleType<T>; error: undefined } | { content: undefined; error: ValidationError } {
242 if (!Array.isArray(content)) {
243 return { content: undefined, error: { message: 'Expected array' } };
260 return { content: result, error: undefined };
261 }
263 > getJSONSchema(): IJSONSchema {
264 return {
265 type: 'array',
267 };
268 }
269 > } validation.ts
270 >
271 > export function vTuple<T extends IValidator<unknown>[]>(...validators: T): ValidatorBase<vTupleType<T>> {
272 return new TupleValidator(validators);
273 }
275 > class UnionValidator<T extends IValidator<unknown>[]> extends ValidatorBase<ValidatorType<T[number]>> {
276 > constructor(private readonly validators: T) {
277 super();
278 }
280 > validate(content: unknown): { content: ValidatorType<T[number]>; error: undefined } | { content: undefined; error: ValidationError } {
281 let lastError: ValidationError | undefined;
282 for (const validator of this.validators) {
292 return { content: undefined, error: lastError! };
293 }
295 > getJSONSchema(): IJSONSchema {
296 return {
297 oneOf: mapFilter(this.validators, validator => {
303 };
304 }
305 > } validation.ts
306 >
307 > export function vUnion<T extends IValidator<unknown>[]>(...validators: T): ValidatorBase<ValidatorType<T[number]>> {
308 return new UnionValidator(validators);
309 }
311 > class EnumValidator<T extends string[]> extends ValidatorBase<T[number]> {
312 > constructor(private readonly values: T) {
313 super();
314 }
316 > validate(content: unknown): { content: T[number]; error: undefined } | { content: undefined; error: ValidationError } {
317 if (this.values.indexOf(content as string) === -1) {
318 return { content: undefined, error: { message: `Expected one of: ${this.values.join(', ')}` } };
321 return { content: content as T[number], error: undefined };
322 }
324 > getJSONSchema(): IJSONSchema {
325 return {
326 enum: this.values,
327 };
328 }
329 > } validation.ts
330 >
331 > export function vEnum<T extends string[]>(...values: T): ValidatorBase<T[number]> {
332 return new EnumValidator(values);
333 }
335 > class LiteralValidator<T extends string> extends ValidatorBase<T> {
336 > constructor(private readonly value: T) {
337 super();
338 }
340 > validate(content: unknown): { content: T; error: undefined } | { content: undefined; error: ValidationError } {
341 if (content !== this.value) {
342 return { content: undefined, error: { message: `Expected: ${this.value}` } };
345 return { content: content as T, error: undefined };
346 }
348 > getJSONSchema(): IJSONSchema {
349 return {
350 const: this.value,
351 };
352 }
353 > } validation.ts
354 >
355 > export function vLiteral<T extends string>(value: T): ValidatorBase<T> {
356 return new LiteralValidator(value);
357 }
359 > class LazyValidator<T> extends ValidatorBase<T> {
360 > constructor(private readonly fn: () => IValidator<T>) {
361 super();
362 }
364 > validate(content: unknown): { content: T; error: undefined } | { content: undefined; error: ValidationError } {
365 return this.fn().validate(content);
366 }
368 > getJSONSchema(): IJSONSchema {
369 return this.fn().getJSONSchema();
370 }
371 > } validation.ts
372 >
373 > export function vLazy<T>(fn: () => IValidator<T>): ValidatorBase<T> {
374 return new LazyValidator(fn);
375 }
377 > class UseRefSchemaValidator<T> extends ValidatorBase<T> {
378 > constructor(
379 private readonly _ref: string,
380 private readonly _validator: IValidator<T>
382 super();
383 }
385 > validate(content: unknown): { content: T; error: undefined } | { content: undefined; error: ValidationError } {
386 return this._validator.validate(content);
387 }
389 > getJSONSchema(): IJSONSchema {
390 return { $ref: this._ref };
391 }
392 > } validation.ts
393 >
394 > export function vWithJsonSchemaRef<T>(ref: string, validator: IValidator<T>): ValidatorBase<T> {
395 return new UseRefSchemaValidator(ref, validator);
396 }
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/workbench/services/search/common/queryBuilder.ts 187 covered LOC · 27 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- queryBuilder.ts
2 > * Copyright (c) Microsoft 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 * as collections from '../../../../base/common/collections.js';
8 > import * as glob from '../../../../base/common/glob.js';
9 > import { untildify } from '../../../../base/common/labels.js';
10 > import { ResourceMap } from '../../../../base/common/map.js';
11 > import { Schemas } from '../../../../base/common/network.js';
12 > import * as path from '../../../../base/common/path.js';
13 > import { isEqual, basename, relativePath, isAbsolutePath } from '../../../../base/common/resources.js';
14 > import * as strings from '../../../../base/common/strings.js';
15 > import { assertReturnsDefined, isDefined } from '../../../../base/common/types.js';
16 > import { URI, URI as uri, UriComponents } from '../../../../base/common/uri.js';
17 > import { isMultilineRegexSource } from '../../../../editor/common/model/textModelSearch.js';
18 > import * as nls from '../../../../nls.js';
19 > import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
20 > import { ILogService } from '../../../../platform/log/common/log.js';
21 > import { IUriIdentityService } from '../../../../platform/uriIdentity/common/uriIdentity.js';
22 > import { IWorkspaceContextService, IWorkspaceFolderData, toWorkspaceFolder, WorkbenchState } from '../../../../platform/workspace/common/workspace.js';
23 > import { IEditorGroupsService } from '../../editor/common/editorGroupsService.js';
24 > import { IPathService } from '../../path/common/pathService.js';
25 > import { ExcludeGlobPattern, getExcludes, IAITextQuery, ICommonQueryProps, IFileQuery, IFolderQuery, IPatternInfo, ISearchConfiguration, ITextQuery, ITextSearchPreviewOptions, pathIncludedInQuery, QueryType } from './search.js';
26 > import { GlobPattern } from './searchExtTypes.js';
27 >
28 > /**
29 > * One folder to search and a glob expression that should be applied.
30 > */
31 > interface IOneSearchPathPattern {
32 > searchPath: uri;
33 > pattern?: string;
34 > }
35 >
36 > /**
37 > * One folder to search and a set of glob expressions that should be applied.
38 > */
39 > export interface ISearchPathPattern {
40 > searchPath: uri;
41 > pattern?: glob.IExpression;
42 > }
43 >
44 > type ISearchPathPatternBuilder = string | string[];
45 >
46 > export interface ISearchPatternBuilder<U extends UriComponents> {
47 > uri?: U;
48 > pattern: ISearchPathPatternBuilder;
49 > }
50 >
51 > export function isISearchPatternBuilder<U extends UriComponents>(object: ISearchPatternBuilder<U> | ISearchPathPatternBuilder): object is ISearchPatternBuilder<U> {
52 return (typeof object === 'object' && 'uri' in object && 'pattern' in object);
53 }
55 > export function globPatternToISearchPatternBuilder(globPattern: GlobPattern): ISearchPatternBuilder<URI> {
56
57 if (typeof globPattern === 'string') {
66 };
67 }
69 > /**
70 > * A set of search paths and a set of glob expressions that should be applied.
71 > */
72 > export interface ISearchPathsInfo {
73 > searchPaths?: ISearchPathPattern[];
74 > pattern?: glob.IExpression;
75 > }
76 >
77 > interface ICommonQueryBuilderOptions<U extends UriComponents = URI> {
78 > _reason?: string;
79 > excludePattern?: ISearchPatternBuilder<U>[];
80 > includePattern?: ISearchPathPatternBuilder;
81 > extraFileResources?: U[];
82 >
83 > /** Parse the special ./ syntax supported by the searchview, and expand foo to ** /foo */
84 > expandPatterns?: boolean;
85 >
86 > maxResults?: number;
87 > maxFileSize?: number;
88 > disregardIgnoreFiles?: boolean;
89 > disregardGlobalIgnoreFiles?: boolean;
90 > disregardParentIgnoreFiles?: boolean;
91 > disregardExcludeSettings?: boolean;
92 > disregardSearchExcludeSettings?: boolean;
93 > ignoreSymlinks?: boolean;
94 > ignoreGlobCase?: boolean;
95 > onlyOpenEditors?: boolean;
96 > changedFileUris?: URI[];
97 > onlyFileScheme?: boolean;
98 > }
99 >
100 > export interface IFileQueryBuilderOptions<U extends UriComponents = URI> extends ICommonQueryBuilderOptions<U> {
101 > filePattern?: string;
102 > exists?: boolean;
103 > sortByScore?: boolean;
104 > cacheKey?: string;
105 > shouldGlobSearch?: boolean;
106 > }
107 >
108 > export interface ITextQueryBuilderOptions<U extends UriComponents = URI> extends ICommonQueryBuilderOptions<U> {
109 > previewOptions?: ITextSearchPreviewOptions;
110 > fileEncoding?: string;
111 > surroundingContext?: number;
112 > isSmartCase?: boolean;
113 > notebookSearchConfig?: {
114 > includeMarkupInput: boolean;
115 > includeMarkupPreview: boolean;
116 > includeCodeInput: boolean;
117 > includeOutput: boolean;
118 > };
119 > }
120 >
121 > export class QueryBuilder {
122 >
123 > constructor(
124 @IConfigurationService private readonly configurationService: IConfigurationService,
125 @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
130 ) {
131 }
133 > aiText(contentPattern: string, folderResources?: uri[], options: ITextQueryBuilderOptions = {}): IAITextQuery {
134 const commonQuery = this.commonQuery(folderResources?.map(toWorkspaceFolder), options);
135 return {
139 };
140 }
142 > text(contentPattern: IPatternInfo, folderResources?: uri[], options: ITextQueryBuilderOptions = {}): ITextQuery {
143 contentPattern = this.getContentPattern(contentPattern, options);
144
155 };
156 }
158 > /**
159 > * Adjusts input pattern for config
160 > */
161 > private getContentPattern(inputPattern: IPatternInfo, options: ITextQueryBuilderOptions): IPatternInfo {
162 const searchConfig = this.configurationService.getValue<ISearchConfiguration>();
163
209 return newPattern;
210 }
212 > file(folders: (IWorkspaceFolderData | URI)[], options: IFileQueryBuilderOptions = {}): IFileQuery {
213 const commonQuery = this.commonQuery(folders, options);
214 return {
224 };
225 }
227 > private handleIncludeExclude(pattern: string | string[] | undefined, expandPatterns: boolean | undefined): ISearchPathsInfo {
228 if (!pattern) {
229 return {};
242 : { pattern: patternListToIExpression(...(Array.isArray(pattern) ? pattern : [pattern])) };
243 }
245 > private commonQuery(folderResources: (IWorkspaceFolderData | URI)[] = [], options: ICommonQueryBuilderOptions = {}): ICommonQueryProps<uri> {
246
247 let excludePatterns: string | string[] | undefined = Array.isArray(options.excludePattern) ? options.excludePattern.map(p => p.pattern).flat() : options.excludePattern;
293 return queryProps;
294 }
296 > private commonQueryFromFileList(files: URI[]): ICommonQueryProps<URI> {
297 const folderQueries: IFolderQuery[] = [];
298 const foldersToSearch: ResourceMap<IFolderQuery> = new ResourceMap();
333 };
334 }
336 > /**
337 > * Resolve isCaseSensitive flag based on the query and the isSmartCase flag, for search providers that don't support smart case natively.
338 > */
339 > private isCaseSensitive(contentPattern: IPatternInfo, options: ITextQueryBuilderOptions): boolean {
340 if (options.isSmartCase) {
341 if (contentPattern.isRegExp) {
351 return !!contentPattern.isCaseSensitive;
352 }
354 > private isMultiline(contentPattern: IPatternInfo): boolean {
355 if (contentPattern.isMultiline) {
356 return true;
367 return !!contentPattern.isMultiline;
368 }
370 > /**
371 > * Take the includePattern as seen in the search viewlet, and split into components that look like searchPaths, and
372 > * glob patterns. Glob patterns are expanded from 'foo/bar' to '{foo/bar/**, **\/foo/bar}.
373 > *
374 > * Public for test.
375 > */
376 > parseSearchPaths(pattern: string | string[]): ISearchPathsInfo {
377 const isSearchPath = (segment: string) => {
378 // A segment is a search path if it is an absolute path or starts with ./, ../, .\, or ..\
418 return result;
419 }
421 > private getExcludesForFolder(folderConfig: ISearchConfiguration, options: ICommonQueryBuilderOptions): glob.IExpression | undefined {
422 return options.disregardExcludeSettings ?
423 undefined :
424 getExcludes(folderConfig, !options.disregardSearchExcludeSettings);
425 }
427 > /**
428 > * Split search paths (./ or ../ or absolute paths in the includePatterns) into absolute paths and globs applied to those paths
429 > */
430 > private expandSearchPathPatterns(searchPaths: string[]): ISearchPathPattern[] {
431 if (!searchPaths || !searchPaths.length) {
432 // No workspace => ignore search paths
468 return Array.from(searchPathPatternMap.values());
469 }
471 > /**
472 > * Takes a searchPath like `./a/foo` or `../a/foo` and expands it to absolute paths for all the workspaces it matches.
473 > */
474 > private expandOneSearchPath(searchPath: string): IOneSearchPathPattern[] {
475 if (path.isAbsolute(searchPath)) {
476 const workspaceFolders = this.workspaceContextService.getWorkspace().folders;
535 }
536 }
538 > private resolveOneSearchPathPattern(oneExpandedResult: IOneSearchPathPattern, globPortion?: string): IOneSearchPathPattern[] {
539 const pattern = oneExpandedResult.pattern && globPortion ?
540 `${oneExpandedResult.pattern}/${globPortion}` :
556 return results;
557 }
559 > private getFolderQueryForSearchPath(searchPath: ISearchPathPattern, options: ICommonQueryBuilderOptions, searchPathExcludes: ISearchPathsInfo): IFolderQuery | null {
560 const rootConfig = this.getFolderQueryForRoot(toWorkspaceFolder(searchPath.searchPath), options, searchPathExcludes, false);
561 if (!rootConfig) {
570 };
571 }
573 > private getFolderQueryForRoot(folder: (IWorkspaceFolderData | URI), options: ICommonQueryBuilderOptions, searchPathExcludes: ISearchPathsInfo, includeFolderName: boolean): IFolderQuery | null {
574 let thisFolderExcludeSearchPathPattern: glob.IExpression | undefined;
575 const folderUri = URI.isUri(folder) ? folder : folder.uri;
624 };
625 }
626 > } queryBuilder.ts
627 >
628 function splitGlobFromPath(searchPath: string): { pathPortion: string; globPortion?: string } {
629 const globCharMatch = searchPath.match(/[\*\{\}\(\)\[\]\?]/);
650 };
651 }
653 function patternListToIExpression(...patterns: string[]): glob.IExpression | undefined {
654 return patterns.length ?
656 undefined;
657 }
659 function splitGlobPattern(pattern: string): string[] {
660 return glob.splitGlobAware(pattern, ',')
662 .filter(s => !!s.length);
663 }
665 > /**
666 > * Note - we used {} here previously but ripgrep can't handle nested {} patterns. See https://github.com/microsoft/vscode/issues/32761
667 > */
668 function expandGlobalGlob(pattern: string): string[] {
669 const patterns = [
674 return patterns.map(p => p.replace(/\*\*\/\*\*/g, '**'));
675 }
677 function normalizeSlashes(pattern: string): string {
678 return pattern.replace(/\\/g, '/');
679 }
681 > /**
682 > * Normalize slashes, remove `./` and trailing slashes
683 > */
684 function normalizeGlobPattern(pattern: string): string {
685 return normalizeSlashes(pattern)
687 .replace(/\/+$/g, '');
688 }
690 > /**
691 > * Escapes a path for use as a glob pattern that would match the input precisely.
692 > * Characters '?', '*', '[', and ']' are escaped into character range glob syntax
693 > * (for example, '?' becomes '[?]').
694 > * NOTE: This implementation makes no special cases for UNC paths. For example,
695 > * given the input "//?/C:/A?.txt", this would produce output '//[?]/C:/A[?].txt',
696 > * which may not be desirable in some cases. Use with caution if UNC paths could be expected.
697 > */
698 > export function escapeGlobPattern(path: string): string {
699 return path.replace(/([?*[\]])/g, '[$1]');
700 }
702 > /**
703 > * Construct an include pattern from a list of folders uris to search in.
704 > */
705 > export function resolveResourcesForSearchIncludes(resources: URI[], contextService: IWorkspaceContextService): string[] {
706 resources = arrays.distinct(resources, resource => resource.toString());
707
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/workbench/api/common/extHostAuthentication.ts 180 covered LOC · 39 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostAuthentication.ts
2 > * Copyright (c) Microsoft 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 * as vscode from 'vscode';
7 > import * as nls from '../../../nls.js';
8 > import { Emitter, Event } from '../../../base/common/event.js';
9 > import { MainContext, MainThreadAuthenticationShape, ExtHostAuthenticationShape } from './extHost.protocol.js';
10 > import { Disposable, ProgressLocation } from './extHostTypes.js';
11 > import { IExtensionDescription, ExtensionIdentifier } from '../../../platform/extensions/common/extensions.js';
12 > import { IAuthenticationGetSessionsOptions, IAuthenticationProviderSessionOptions, INTERNAL_AUTH_PROVIDER_PREFIX, isAuthenticationWwwAuthenticateRequest } from '../../services/authentication/common/authentication.js';
13 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
14 > import { IExtHostRpcService } from './extHostRpcService.js';
15 > import { URI, UriComponents } from '../../../base/common/uri.js';
16 > import { AuthorizationErrorType, fetchDynamicRegistration, getClaimsFromJWT, IAuthorizationJWTClaims, IAuthorizationProtectedResourceMetadata, IAuthorizationServerMetadata, IAuthorizationTokenResponse, isAuthorizationErrorResponse, isAuthorizationTokenResponse } from '../../../base/common/oauth.js';
17 > import { IExtHostWindow } from './extHostWindow.js';
18 > import { IExtHostInitDataService } from './extHostInitDataService.js';
19 > import { ILogger, ILoggerService, ILogService } from '../../../platform/log/common/log.js';
20 > import { autorun, derivedOpts, IObservable, ISettableObservable, observableValue } from '../../../base/common/observable.js';
21 > import { stringHash } from '../../../base/common/hash.js';
22 > import { DisposableStore, IDisposable } from '../../../base/common/lifecycle.js';
23 > import { IExtHostUrlsService } from './extHostUrls.js';
24 > import { encodeBase64, VSBuffer } from '../../../base/common/buffer.js';
25 > import { equals as arraysEqual } from '../../../base/common/arrays.js';
26 > import { IExtHostProgress } from './extHostProgress.js';
27 > import { IProgressStep } from '../../../platform/progress/common/progress.js';
28 > import { CancellationError, isCancellationError } from '../../../base/common/errors.js';
29 > import { raceCancellationError, SequencerByKey } from '../../../base/common/async.js';
30 > import { XaaifyAuthProvider } from './extHostXaaAuthProvider.js';
31 >
32 > export interface IExtHostAuthentication extends ExtHostAuthentication { }
33 > export const IExtHostAuthentication = createDecorator<IExtHostAuthentication>('IExtHostAuthentication');
34 >
35 > interface ProviderWithMetadata {
36 > label: string;
37 > provider: vscode.AuthenticationProvider;
38 > disposable?: vscode.Disposable;
39 > options: vscode.AuthenticationProviderOptions;
40 > }
41 >
42 > export class ExtHostAuthentication implements ExtHostAuthenticationShape {
43 >
44 > declare _serviceBrand: undefined;
45 >
46 > protected readonly _dynamicAuthProviderCtor = DynamicAuthProvider;
47 > protected readonly _xaaAuthProviderCtor = XaaifyAuthProvider(DynamicAuthProvider);
48 >
49 > private _proxy: MainThreadAuthenticationShape;
50 > private _authenticationProviders: Map<string, ProviderWithMetadata> = new Map<string, ProviderWithMetadata>();
51 > private _providerOperations = new SequencerByKey<string>();
52 >
53 > private _onDidChangeSessions = new Emitter<vscode.AuthenticationSessionsChangeEvent & { extensionIdFilter?: string[] }>();
54 > private _getSessionTaskSingler = new TaskSingler<vscode.AuthenticationSession | undefined>();
55 >
56 > private _onDidDynamicAuthProviderTokensChange = new Emitter<{ authProviderId: string; clientId: string; tokens: IAuthorizationToken[] }>();
57 >
58 > constructor(
59 @IExtHostRpcService extHostRpc: IExtHostRpcService,
60 @IExtHostInitDataService private readonly _initData: IExtHostInitDataService,
67 this._proxy = extHostRpc.getProxy(MainContext.MainThreadAuthentication);
68 }
70 > /**
71 > * This sets up an event that will fire when the auth sessions change with a built-in filter for the extensionId
72 > * if a session change only affects a specific extension.
73 > * @param extensionId The extension that is interested in the event.
74 > * @returns An event with a built-in filter for the extensionId
75 > */
76 > getExtensionScopedSessionsEvent(extensionId: string): Event<vscode.AuthenticationSessionsChangeEvent> {
77 const normalizedExtensionId = extensionId.toLowerCase();
78 return Event.chain(this._onDidChangeSessions.event, ($) => $
81 );
82 }
84 > async getSession(requestingExtension: IExtensionDescription, providerId: string, scopesOrRequest: readonly string[] | vscode.AuthenticationWwwAuthenticateRequest, options: vscode.AuthenticationGetSessionOptions & ({ createIfNone: true } | { forceNewSession: true } | { forceNewSession: vscode.AuthenticationForceNewSessionOptions })): Promise<vscode.AuthenticationSession>;
85 > async getSession(requestingExtension: IExtensionDescription, providerId: string, scopesOrRequest: readonly string[] | vscode.AuthenticationWwwAuthenticateRequest, options: vscode.AuthenticationGetSessionOptions & { forceNewSession: true }): Promise<vscode.AuthenticationSession>;
86 > async getSession(requestingExtension: IExtensionDescription, providerId: string, scopesOrRequest: readonly string[] | vscode.AuthenticationWwwAuthenticateRequest, options: vscode.AuthenticationGetSessionOptions & { forceNewSession: vscode.AuthenticationForceNewSessionOptions }): Promise<vscode.AuthenticationSession>;
87 > async getSession(requestingExtension: IExtensionDescription, providerId: string, scopesOrRequest: readonly string[] | vscode.AuthenticationWwwAuthenticateRequest, options: vscode.AuthenticationGetSessionOptions): Promise<vscode.AuthenticationSession | undefined>;
88 > async getSession(requestingExtension: IExtensionDescription, providerId: string, scopesOrRequest: readonly string[] | vscode.AuthenticationWwwAuthenticateRequest, options: vscode.AuthenticationGetSessionOptions = {}): Promise<vscode.AuthenticationSession | undefined> {
89 const extensionId = ExtensionIdentifier.toKey(requestingExtension.identifier);
90 const keys: (keyof vscode.AuthenticationGetSessionOptions)[] = Object.keys(options) as (keyof vscode.AuthenticationGetSessionOptions)[];
128 });
129 }
131 > async getAccounts(providerId: string) {
132 await this._proxy.$ensureProvider(providerId);
133 return await this._proxy.$getAccounts(providerId);
134 }
136 > registerAuthenticationProvider(id: string, label: string, provider: vscode.AuthenticationProvider, options?: vscode.AuthenticationProviderOptions): vscode.Disposable {
137 // register
138 void this._providerOperations.queue(id, async () => {
167 });
168 }
170 > $createSession(providerId: string, scopes: string[], options: vscode.AuthenticationProviderSessionOptions): Promise<vscode.AuthenticationSession> {
171 return this._providerOperations.queue(providerId, async () => {
172 const providerData = this._authenticationProviders.get(providerId);
179 });
180 }
182 > $removeSession(providerId: string, sessionId: string): Promise<void> {
183 return this._providerOperations.queue(providerId, async () => {
184 const providerData = this._authenticationProviders.get(providerId);
190 });
191 }
193 > $getSessions(providerId: string, scopes: ReadonlyArray<string> | undefined, options: IAuthenticationGetSessionsOptions): Promise<ReadonlyArray<vscode.AuthenticationSession>> {
194 return this._providerOperations.queue(providerId, async () => {
195 const providerData = this._authenticationProviders.get(providerId);
202 });
203 }
205 > $getSessionsFromChallenges(providerId: string, constraint: vscode.AuthenticationConstraint, options: vscode.AuthenticationProviderSessionOptions): Promise<ReadonlyArray<vscode.AuthenticationSession>> {
206 return this._providerOperations.queue(providerId, async () => {
207 const providerData = this._authenticationProviders.get(providerId);
219 });
220 }
222 > $createSessionFromChallenges(providerId: string, constraint: vscode.AuthenticationConstraint, options: vscode.AuthenticationProviderSessionOptions): Promise<vscode.AuthenticationSession> {
223 return this._providerOperations.queue(providerId, async () => {
224 const providerData = this._authenticationProviders.get(providerId);
236 });
237 }
239 > $onDidChangeAuthenticationSessions(id: string, label: string, extensionIdFilter?: string[]) {
240 // Don't fire events for the internal auth providers
241 if (!id.startsWith(INTERNAL_AUTH_PROVIDER_PREFIX)) {
244 return Promise.resolve();
245 }
247 > $onDidUnregisterAuthenticationProvider(id: string): Promise<void> {
248 return this._providerOperations.queue(id, async () => {
249 const providerData = this._authenticationProviders.get(id);
254 });
255 }
257 > async $registerDynamicAuthProvider(
258 authorizationServerComponents: UriComponents,
259 serverMetadata: IAuthorizationServerMetadata,
343 return provider.id;
344 }
346 > async $registerXaaAuthProvider(
347 issuerComponents: UriComponents,
348 serverMetadata: IAuthorizationServerMetadata,
412 return provider.id;
413 }
415 > async $onDidChangeDynamicAuthProviderTokens(authProviderId: string, clientId: string, tokens: IAuthorizationToken[]): Promise<void> {
416 this._onDidDynamicAuthProviderTokensChange.fire({ authProviderId, clientId, tokens });
417 }
419 >
420 class TaskSingler<T> {
421 private _inFlightPromises = new Map<string, Promise<T>>();
422 > getOrCreate(key: string, promiseFactory: () => Promise<T>) { extHostAuthentication.ts
423 const inFlight = this._inFlightPromises.get(key);
424 if (inFlight) {
431 return promise;
432 }
434 >
435 > export class DynamicAuthProvider implements vscode.AuthenticationProvider {
436 > id: string;
437 > readonly label: string;
438 >
439 > private _onDidChangeSessions = new Emitter<vscode.AuthenticationProviderAuthenticationSessionsChangeEvent>();
440 > readonly onDidChangeSessions = this._onDidChangeSessions.event;
441 >
442 > private readonly _onDidChangeClientId = new Emitter<void>();
443 > readonly onDidChangeClientId = this._onDidChangeClientId.event;
444 >
445 > private readonly _tokenStore: TokenStore;
446 >
447 > protected readonly _createFlows: Array<{
448 > label: string;
449 > handler: (scopes: string[], progress: vscode.Progress<{ message: string }>, token: vscode.CancellationToken) => Promise<IAuthorizationTokenResponse>;
450 > }>;
451 >
452 > protected readonly _logger: ILogger;
453 > private readonly _disposable: DisposableStore;
454 >
455 > constructor(
456 @IExtHostWindow protected readonly _extHostWindow: IExtHostWindow,
457 @IExtHostUrlsService protected readonly _extHostUrls: IExtHostUrlsService,
503 }
504 }
506 > get clientId(): string {
507 return this._clientId;
508 }
510 > get clientSecret(): string | undefined {
511 return this._clientSecret;
512 }
514 > async getSessions(scopes: readonly string[] | undefined, options: IAuthenticationProviderSessionOptions): Promise<vscode.AuthenticationSession[]> {
515 this._logger.info(`Getting sessions for scopes: ${scopes?.join(' ') ?? 'all'}`);
516 if (!scopes) {
570 return [];
571 }
573 > async createSession(scopes: string[], _options: vscode.AuthenticationProviderSessionOptions): Promise<vscode.AuthenticationSession> {
574 this._logger.info(`Creating session for scopes: ${scopes.join(' ')}`);
575 let token: IAuthorizationTokenResponse | undefined;
618 return session;
619 }
621 > async removeSession(sessionId: string): Promise<void> {
622 this._logger.info(`Removing session with id: ${sessionId}`);
623 const session = this._tokenStore.sessions.find(session => session.id === sessionId);
634 this._logger.info(`Removed token for session: ${session.id} with scopes: ${session.scopes.join(' ')}`);
635 }
637 > dispose(): void {
638 this._disposable.dispose();
639 }
641 > private async _createWithUrlHandler(scopes: string[], progress: vscode.Progress<IProgressStep>, token: vscode.CancellationToken): Promise<IAuthorizationTokenResponse> {
642 if (!this._serverMetadata.authorization_endpoint) {
643 throw new Error('Authorization Endpoint required');
714 return tokenResponse;
715 }
717 > protected generateRandomString(length: number): string {
718 const array = new Uint8Array(length);
719 crypto.getRandomValues(array);
723 .substring(0, length);
724 }
726 > protected async generateCodeChallenge(codeVerifier: string): Promise<string> {
727 const encoder = new TextEncoder();
728 const data = encoder.encode(codeVerifier);
735 .replace(/=+$/, '');
736 }
738 > private async waitForAuthorizationCode(expectedState: URI): Promise<{ code: string }> {
739 const result = await this._proxy.$waitForUriHandler(expectedState);
740 // Extract the code parameter directly from the query string. NOTE, URLSearchParams does not work here because
747 return { code: codeMatch[1] };
748 }
750 > protected async exchangeCodeForToken(code: string, codeVerifier: string, redirectUri: string): Promise<IAuthorizationTokenResponse> {
751 if (!this._serverMetadata.token_endpoint) {
752 throw new Error('Token endpoint not available in server metadata');
804 throw new Error(`Invalid authorization token response: ${JSON.stringify(result)}`);
805 }
807 > protected async exchangeRefreshTokenForToken(refreshToken: string, allowClientRegistration: boolean): Promise<IAuthorizationToken> {
808 if (!this._serverMetadata.token_endpoint) {
809 throw new Error('Token endpoint not available in server metadata');
851 throw new Error(`Invalid authorization token response: ${JSON.stringify(result)}`);
852 }
854 > protected async _generateNewClientId(): Promise<void> {
855 try {
856 const registration = await fetchDynamicRegistration(this._serverMetadata, this._initData.environment.appName, this._resourceMetadata?.scopes_supported);
883 }
884 }
886 >
887 > export type IAuthorizationToken = IAuthorizationTokenResponse & {
888 > /**
889 > * The time when the token was created, in milliseconds since the epoch.
890 > */
891 > created_at: number;
892 > };
893 >
894 > export class TokenStore implements Disposable {
895 > private readonly _tokensObservable: ISettableObservable<IAuthorizationToken[]>;
896 > private readonly _sessionsObservable: IObservable<vscode.AuthenticationSession[]>;
897 >
898 > private readonly _onDidChangeSessions = new Emitter<vscode.AuthenticationProviderAuthenticationSessionsChangeEvent>();
899 > readonly onDidChangeSessions = this._onDidChangeSessions.event;
900 >
901 > private readonly _disposable: DisposableStore;
902 >
903 > constructor(
904 private readonly _persistence: { onDidChange: Event<IAuthorizationToken[]>; set: (tokens: IAuthorizationToken[]) => void },
905 initialTokens: IAuthorizationToken[],
915 this._disposable.add(this._persistence.onDidChange((tokens) => this._tokensObservable.set(tokens, undefined)));
916 }
918 > get tokens(): IAuthorizationToken[] {
919 return this._tokensObservable.get();
920 }
922 > get sessions(): vscode.AuthenticationSession[] {
923 return this._sessionsObservable.get();
924 }
926 > dispose() {
927 this._disposable.dispose();
928 }
930 > update({ added, removed }: { added: IAuthorizationToken[]; removed: IAuthorizationToken[] }): void {
931 this._logger.trace(`Updating tokens: added ${added.length}, removed ${removed.length}`);
932 const currentTokens = [...this._tokensObservable.get()];
951 this._logger.trace(`Tokens updated: ${currentTokens.length} tokens stored.`);
952 }
954 > private _registerChangeEventAutorun(): IDisposable {
955 let previousSessions: vscode.AuthenticationSession[] = [];
956 return autorun((reader) => {
1005 });
1006 }
1008 > private _getSessionFromToken(token: IAuthorizationTokenResponse): vscode.AuthenticationSession {
1009 let claims: IAuthorizationJWTClaims | undefined;
1010 if (token.id_token) {
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/workbench/api/common/extHostExtensionActivator.ts 176 covered LOC · 33 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostExtensionActivator.ts
2 > * Copyright (c) Microsoft 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 * as vscode from 'vscode';
7 > import * as errors from '../../../base/common/errors.js';
8 > import { Disposable, IDisposable } from '../../../base/common/lifecycle.js';
9 > import { ExtensionDescriptionRegistry } from '../../services/extensions/common/extensionDescriptionRegistry.js';
10 > import { ExtensionIdentifier, ExtensionIdentifierMap } from '../../../platform/extensions/common/extensions.js';
11 > import { ExtensionActivationReason, MissingExtensionDependency } from '../../services/extensions/common/extensions.js';
12 > import { ILogService } from '../../../platform/log/common/log.js';
13 > import { Barrier } from '../../../base/common/async.js';
14 >
15 > /**
16 > * Represents the source code (module) of an extension.
17 > */
18 > export interface IExtensionModule {
19 > activate?(ctx: vscode.ExtensionContext): Promise<IExtensionAPI>;
20 > deactivate?(): void;
21 > }
22 >
23 > /**
24 > * Represents the API of an extension (return value of `activate`).
25 > */
26 > export interface IExtensionAPI {
27 > // _extensionAPIBrand: any;
28 > }
29 >
30 > export type ExtensionActivationTimesFragment = {
31 > startup?: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Activation occurred during startup' };
32 > codeLoadingTime?: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Time it took to load the extension\'s code' };
33 > activateCallTime?: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Time it took to call activate' };
34 > activateResolvedTime?: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Time it took for async-activation to finish' };
35 > };
36 >
37 > export class ExtensionActivationTimes {
38 >
39 > public static readonly NONE = new ExtensionActivationTimes(false, -1, -1, -1);
40 >
41 > public readonly startup: boolean;
42 > public readonly codeLoadingTime: number;
43 > public readonly activateCallTime: number;
44 > public readonly activateResolvedTime: number;
45 >
46 > constructor(startup: boolean, codeLoadingTime: number, activateCallTime: number, activateResolvedTime: number) {
47 > this.startup = startup;
48 > this.codeLoadingTime = codeLoadingTime;
49 > this.activateCallTime = activateCallTime;
50 > this.activateResolvedTime = activateResolvedTime;
51 > }
52 > }
53 >
54 > export class ExtensionActivationTimesBuilder {
55 >
56 > private readonly _startup: boolean;
57 > private _codeLoadingStart: number;
58 > private _codeLoadingStop: number;
59 > private _activateCallStart: number;
60 > private _activateCallStop: number;
61 > private _activateResolveStart: number;
62 > private _activateResolveStop: number;
63 >
64 > constructor(startup: boolean) {
65 this._startup = startup;
66 this._codeLoadingStart = -1;
71 this._activateResolveStop = -1;
72 }
74 > private _delta(start: number, stop: number): number {
75 if (start === -1 || stop === -1) {
76 return -1;
78 return stop - start;
79 }
81 > public build(): ExtensionActivationTimes {
82 return new ExtensionActivationTimes(
83 this._startup,
87 );
88 }
90 > public codeLoadingStart(): void {
91 this._codeLoadingStart = Date.now();
92 }
94 > public codeLoadingStop(): void {
95 this._codeLoadingStop = Date.now();
96 }
98 > public activateCallStart(): void {
99 this._activateCallStart = Date.now();
100 }
102 > public activateCallStop(): void {
103 this._activateCallStop = Date.now();
104 }
106 > public activateResolveStart(): void {
107 this._activateResolveStart = Date.now();
108 }
110 > public activateResolveStop(): void {
111 this._activateResolveStop = Date.now();
112 }
114 >
115 > export class ActivatedExtension {
116 >
117 > public readonly activationFailed: boolean;
118 > public readonly activationFailedError: Error | null;
119 > public readonly activationTimes: ExtensionActivationTimes;
120 > public readonly module: IExtensionModule;
121 > public readonly exports: IExtensionAPI | undefined;
122 > public readonly disposable: IDisposable;
123 >
124 > constructor(
125 activationFailed: boolean,
126 activationFailedError: Error | null,
137 this.disposable = disposable;
138 }
140 >
141 > export class EmptyExtension extends ActivatedExtension {
142 > constructor(activationTimes: ExtensionActivationTimes) {
143 super(false, null, activationTimes, { activate: undefined, deactivate: undefined }, undefined, Disposable.None);
144 }
146 >
147 > export class HostExtension extends ActivatedExtension {
148 > constructor() {
149 super(false, null, ExtensionActivationTimes.NONE, { activate: undefined, deactivate: undefined }, undefined, Disposable.None);
150 }
152 >
153 > class FailedExtension extends ActivatedExtension {
154 > constructor(activationError: Error) {
155 super(true, activationError, ExtensionActivationTimes.NONE, { activate: undefined, deactivate: undefined }, undefined, Disposable.None);
156 }
158 >
159 > export interface IExtensionsActivatorHost {
160 > onExtensionActivationError(extensionId: ExtensionIdentifier, error: Error | null, missingExtensionDependency: MissingExtensionDependency | null): void;
161 > actualActivateExtension(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<ActivatedExtension>;
162 > }
163 >
164 > type ActivationIdAndReason = { id: ExtensionIdentifier; reason: ExtensionActivationReason };
165 >
166 > export class ExtensionsActivator implements IDisposable {
167 >
168 > private readonly _registry: ExtensionDescriptionRegistry;
169 > private readonly _globalRegistry: ExtensionDescriptionRegistry;
170 > private readonly _host: IExtensionsActivatorHost;
171 > private readonly _operations: ExtensionIdentifierMap<ActivationOperation>;
172 > /**
173 > * A map of already activated events to speed things up if the same activation event is triggered multiple times.
174 > */
175 > private readonly _alreadyActivatedEvents: { [activationEvent: string]: boolean };
176 >
177 > constructor(
178 registry: ExtensionDescriptionRegistry,
179 globalRegistry: ExtensionDescriptionRegistry,
187 this._alreadyActivatedEvents = Object.create(null);
188 }
190 > public dispose(): void {
191 for (const [_, op] of this._operations) {
192 op.dispose();
193 }
194 }
196 > public async waitForActivatingExtensions(): Promise<void> {
197 const res: Promise<boolean>[] = [];
198 for (const [_, op] of this._operations) {
201 await Promise.all(res);
202 }
204 > public isActivated(extensionId: ExtensionIdentifier): boolean {
205 const op = this._operations.get(extensionId);
206 return Boolean(op && op.value);
207 }
209 > public getActivatedExtension(extensionId: ExtensionIdentifier): ActivatedExtension {
210 const op = this._operations.get(extensionId);
211 if (!op || !op.value) {
214 return op.value;
215 }
217 > public async activateByEvent(activationEvent: string, startup: boolean): Promise<void> {
218 if (this._alreadyActivatedEvents[activationEvent]) {
219 return;
228 this._alreadyActivatedEvents[activationEvent] = true;
229 }
231 > public activateById(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<void> {
232 const desc = this._registry.getExtensionDescription(extensionId);
233 if (!desc) {
236 return this._activateExtensions([{ id: desc.identifier, reason }]);
237 }
239 > private async _activateExtensions(extensions: ActivationIdAndReason[]): Promise<void> {
240 const operations = extensions
241 .filter((p) => !this.isActivated(p.id))
243 await Promise.all(operations.map(op => op.wait()));
244 }
246 > /**
247 > * Handle semantics related to dependencies for `currentExtension`.
248 > * We don't need to worry about dependency loops because they are handled by the registry.
249 > */
250 > private _handleActivationRequest(currentActivation: ActivationIdAndReason): ActivationOperation {
251 if (this._operations.has(currentActivation.id)) {
252 return this._operations.get(currentActivation.id)!;
323 return this._createAndSaveOperation(currentActivation, currentExtension.displayName, deps, null);
324 }
326 > private _createAndSaveOperation(activation: ActivationIdAndReason, displayName: string | null | undefined, deps: ActivationOperation[], value: ActivatedExtension | null): ActivationOperation {
327 const operation = new ActivationOperation(activation.id, displayName, activation.reason, deps, value, this._host, this._logService);
328 this._operations.set(activation.id, operation);
329 return operation;
330 }
332 > private _isHostExtension(extensionId: ExtensionIdentifier | string): boolean {
333 return ExtensionDescriptionRegistry.isHostExtension(extensionId, this._registry, this._globalRegistry);
334 }
336 > private _isResolvedExtension(extensionId: ExtensionIdentifier | string): boolean {
337 const extensionDescription = this._globalRegistry.getExtensionDescription(extensionId);
338 if (!extensionDescription) {
342 return (!extensionDescription.main && !extensionDescription.browser);
343 }
345 >
346 > class ActivationOperation {
347 >
348 > private readonly _barrier = new Barrier();
349 > private _isDisposed = false;
350 >
351 > public get value(): ActivatedExtension | null {
352 > return this._value;
353 > }
354 >
355 > public get friendlyName(): string {
356 return this._displayName || this._id.value;
357 }
359 > constructor(
360 private readonly _id: ExtensionIdentifier,
361 private readonly _displayName: string | null | undefined,
368 this._initialize();
369 }
371 > public dispose(): void {
372 this._isDisposed = true;
373 }
375 > public wait() {
376 return this._barrier.wait();
377 }
379 > private async _initialize(): Promise<void> {
380 await this._waitForDepsThenActivate();
381 this._barrier.open();
382 }
384 > private async _waitForDepsThenActivate(): Promise<void> {
385 if (this._value) {
386 // this operation is already finished
419 await this._activate();
420 }
422 > private async _activate(): Promise<void> {
423 try {
424 this._value = await this._host.actualActivateExtension(this._id, this._reason);
src/vs/platform/agentHost/common/state/protocol/channels-terminal/state.ts 173 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- state.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > // allow-any-unicode-comment-file
7 > // DO NOT EDIT -- auto-generated by scripts/sync-agent-host-protocol.ts
8 >
9 > import type { URI } from '../common/state.js';
10 >
11 > // ─── Terminal Types ──────────────────────────────────────────────────────────
12 >
13 > /**
14 > * Lightweight terminal metadata exposed on the root state.
15 > *
16 > * @category Terminal Types
17 > */
18 > export interface TerminalInfo {
19 > /** Terminal URI (subscribable for full terminal state) */
20 > resource: URI;
21 > /** Human-readable terminal title */
22 > title: string;
23 > /** Who currently holds this terminal */
24 > claim: TerminalClaim;
25 > /** Process exit code, if the terminal process has exited */
26 > exitCode?: number;
27 > }
28 >
29 > /**
30 > * Discriminant for terminal claim kinds.
31 > *
32 > * @category Terminal Types
33 > */
34 > export const enum TerminalClaimKind {
35 > Client = 'client',
36 > Session = 'session',
37 > }
38 >
39 > /**
40 > * A terminal claimed by a connected client.
41 > *
42 > * @category Terminal Types
43 > */
44 > export interface TerminalClientClaim {
45 > /** Discriminant */
46 > kind: TerminalClaimKind.Client;
47 > /** The `clientId` of the claiming client */
48 > clientId: string;
49 > }
50 >
51 > /**
52 > * A terminal claimed by a session, optionally scoped to a specific turn or tool call.
53 > *
54 > * @category Terminal Types
55 > */
56 > export interface TerminalSessionClaim {
57 > /** Discriminant */
58 > kind: TerminalClaimKind.Session;
59 > /** Session URI that claimed the terminal */
60 > session: URI;
61 > /** Optional turn identifier within the session */
62 > turnId?: string;
63 > /** Optional tool call identifier within the turn */
64 > toolCallId?: string;
65 > }
66 >
67 > /**
68 > * Describes who currently holds a terminal. A terminal may be claimed by
69 > * either a connected client or a session (e.g. during a tool call).
70 > *
71 > * @category Terminal Types
72 > */
73 > export type TerminalClaim = TerminalClientClaim | TerminalSessionClaim;
74 >
75 > /**
76 > * Full state for a single terminal, loaded when a client subscribes to the terminal's URI.
77 > *
78 > * @category Terminal Types
79 > */
80 > export interface TerminalState {
81 > /** Human-readable terminal title */
82 > title: string;
83 > /** Current working directory of the terminal process */
84 > cwd?: URI;
85 > /** Terminal width in columns */
86 > cols?: number;
87 > /** Terminal height in rows */
88 > rows?: number;
89 > /**
90 > * Typed content parts, replacing the flat `content: string`.
91 > *
92 > * Naive consumers that only need the raw VT stream can reconstruct it with:
93 > * `content.map(p => p.type === 'command' ? p.output : p.value).join('')`
94 > *
95 > * Consumers that need command boundaries can filter by part type.
96 > */
97 > content: TerminalContentPart[];
98 > /** Process exit code, set when the terminal process exits */
99 > exitCode?: number;
100 > /** Who currently holds this terminal */
101 > claim: TerminalClaim;
102 > /**
103 > * Whether this terminal emits `terminal/commandExecuted` and
104 > * `terminal/commandFinished` actions and populates `command`-typed parts.
105 > *
106 > * Clients MUST check this flag before relying on command detection.
107 > * Do NOT use the presence of a `command` part as a feature flag — parts
108 > * are absent in the normal idle state.
109 > */
110 > supportsCommandDetection?: boolean;
111 > /**
112 > * Whether this terminal-style resource is backed by a pseudoterminal.
113 > * When `false`, output is plain text and clients do not need to parse
114 > * VT sequences.
115 > */
116 > isPty?: boolean;
117 > }
118 >
119 > // ─── Terminal Content Parts ──────────────────────────────────────────────────
120 >
121 > /**
122 > * A content part within terminal output.
123 > *
124 > * @category Terminal Types
125 > */
126 > export type TerminalContentPart =
127 > | TerminalUnclassifiedPart
128 > | TerminalCommandPart;
129 >
130 > /**
131 > * Unstructured terminal output — content before, between, or after commands,
132 > * or from terminals that do not support command detection.
133 > *
134 > * @category Terminal Types
135 > */
136 > export interface TerminalUnclassifiedPart {
137 > type: 'unclassified';
138 > /** Accumulated VT output. Appended to by `terminal/data` when no command is executing. */
139 > value: string;
140 > }
141 >
142 > /**
143 > * A single command: its command line and the output it produced.
144 > *
145 > * While `isComplete` is false the command is still executing; `output` grows
146 > * as `terminal/data` actions arrive. At `terminal/commandFinished` the part
147 > * is mutated in-place with `isComplete: true` and the completion metadata.
148 > *
149 > * @category Terminal Types
150 > */
151 > export interface TerminalCommandPart {
152 > type: 'command';
153 > /**
154 > * Stable id matching the `commandId` on the corresponding
155 > * `terminal/commandExecuted` and `terminal/commandFinished` actions.
156 > */
157 > commandId: string;
158 > /** The command line submitted to the shell. */
159 > commandLine: string;
160 > /**
161 > * Accumulated VT output. Appended to by `terminal/data` while `isComplete`
162 > * is false. Shell integration escape sequences are stripped by the server.
163 > */
164 > output: string;
165 > /** Unix timestamp (ms) when execution started, as reported by the server. */
166 > timestamp: number;
167 > /** Whether the command has finished. */
168 > isComplete: boolean;
169 > /** Shell exit code. Set at completion. `undefined` if unknown. */
170 > exitCode?: number;
171 > /** Wall-clock duration in milliseconds. Set at completion. */
172 > durationMs?: number;
173 > }
src/vs/platform/progress/common/progress.ts 170 covered LOC · 9 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- progress.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IAction } from '../../../base/common/actions.js';
7 > import { DeferredPromise } from '../../../base/common/async.js';
8 > import { CancellationToken, CancellationTokenSource } from '../../../base/common/cancellation.js';
9 > import { Disposable, DisposableStore, toDisposable } from '../../../base/common/lifecycle.js';
10 > import { createDecorator } from '../../instantiation/common/instantiation.js';
11 > import { INotificationSource, NotificationPriority } from '../../notification/common/notification.js';
12 >
13 > export const IProgressService = createDecorator<IProgressService>('progressService');
14 >
15 > /**
16 > * A progress service that can be used to report progress to various locations of the UI.
17 > */
18 > export interface IProgressService {
19 >
20 > readonly _serviceBrand: undefined;
21 >
22 > withProgress<R>(
23 > options: IProgressOptions | IProgressDialogOptions | IProgressNotificationOptions | IProgressWindowOptions | IProgressCompositeOptions,
24 > task: (progress: IProgress<IProgressStep>) => Promise<R>,
25 > onDidCancel?: (choice?: number) => void
26 > ): Promise<R>;
27 > }
28 >
29 > export interface IProgressIndicator {
30 >
31 > /**
32 > * Show progress customized with the provided flags.
33 > */
34 > show(infinite: true, delay?: number): IProgressRunner;
35 > show(total: number, delay?: number): IProgressRunner;
36 >
37 > /**
38 > * Indicate progress for the duration of the provided promise. Progress will stop in
39 > * any case of promise completion, error or cancellation.
40 > */
41 > showWhile(promise: Promise<unknown>, delay?: number): Promise<void>;
42 > }
43 >
44 > export const enum ProgressLocation {
45 > Explorer = 1,
46 > Scm = 3,
47 > Extensions = 5,
48 > Window = 10,
49 > Notification = 15,
50 > Dialog = 20
51 > }
52 >
53 > export interface IProgressOptions {
54 > readonly location: ProgressLocation | string;
55 > readonly title?: string;
56 > readonly source?: string | INotificationSource;
57 > readonly total?: number;
58 > readonly cancellable?: boolean | string;
59 > readonly buttons?: string[];
60 > }
61 >
62 > export interface IProgressNotificationOptions extends IProgressOptions {
63 > readonly location: ProgressLocation.Notification;
64 > readonly primaryActions?: readonly IAction[];
65 > readonly secondaryActions?: readonly IAction[];
66 > readonly delay?: number;
67 > readonly priority?: NotificationPriority;
68 > readonly type?: 'loading' | 'syncing';
69 > }
70 >
71 > export interface IProgressDialogOptions extends IProgressOptions {
72 > readonly delay?: number;
73 > readonly detail?: string;
74 > readonly sticky?: boolean;
75 > }
76 >
77 > export interface IProgressWindowOptions extends IProgressOptions {
78 > readonly location: ProgressLocation.Window;
79 > readonly command?: string;
80 > readonly type?: 'loading' | 'syncing';
81 > }
82 >
83 > export interface IProgressCompositeOptions extends IProgressOptions {
84 > readonly location: ProgressLocation.Explorer | ProgressLocation.Extensions | ProgressLocation.Scm | string;
85 > readonly delay?: number;
86 > }
87 >
88 > export interface IProgressStep {
89 > message?: string;
90 > increment?: number;
91 > total?: number;
92 > }
93 >
94 > export interface IProgressRunner {
95 > total(value: number): void;
96 > worked(value: number): void;
97 > done(): void;
98 > }
99 >
100 > export const emptyProgressRunner = Object.freeze<IProgressRunner>({
101 > total() { },
102 > worked() { },
103 > done() { }
104 > });
105 >
106 > export interface IProgress<T> {
107 > report(item: T): void;
108 > }
109 >
110 > export class Progress<T> implements IProgress<T> {
111 >
112 > static readonly None = Object.freeze<IProgress<unknown>>({ report() { } });
113 >
114 > private _value?: T;
115 > get value(): T | undefined { return this._value; }
116 >
117 > constructor(private callback: (data: T) => unknown) {
118 }
119 > progress.ts
120 > report(item: T) {
121 this._value = item;
122 this.callback(this._value);
123 }
124 > } progress.ts
125 >
126 > /**
127 > * A helper to show progress during a long running operation. If the operation
128 > * is started multiple times, only the last invocation will drive the progress.
129 > */
130 > export interface IOperation {
131 > id: number;
132 > isCurrent: () => boolean;
133 > token: CancellationToken;
134 > stop(): void;
135 > }
136 >
137 > /**
138 > * RAII-style progress instance that allows imperative reporting and hides
139 > * once `dispose()` is called.
140 > */
141 > export class UnmanagedProgress extends Disposable {
142 > private readonly deferred = new DeferredPromise<void>();
143 > private reporter?: IProgress<IProgressStep>;
144 > private lastStep?: IProgressStep;
145 >
146 > constructor(
147 options: IProgressOptions | IProgressDialogOptions | IProgressNotificationOptions | IProgressWindowOptions | IProgressCompositeOptions,
148 @IProgressService progressService: IProgressService,
160 this._register(toDisposable(() => this.deferred.complete()));
161 }
162 > progress.ts
163 > report(step: IProgressStep) {
164 if (this.reporter) {
165 this.reporter.report(step);
168 }
169 }
170 > } progress.ts
171 >
172 > export class LongRunningOperation extends Disposable {
173 > private currentOperationId = 0;
174 > private readonly currentOperationDisposables = this._register(new DisposableStore());
175 > private currentProgressRunner: IProgressRunner | undefined;
176 > private currentProgressTimeout: Timeout | undefined = undefined;
177 >
178 > constructor(
179 private progressIndicator: IProgressIndicator
180 ) {
181 super();
182 }
183 > progress.ts
184 > start(progressDelay: number): IOperation {
185
186 // Stop any previous operation
207 };
208 }
209 > progress.ts
210 > stop(): void {
211 this.doStop(this.currentOperationId);
212 }
213 > progress.ts
214 > private doStop(operationId: number): void {
215 if (this.currentOperationId === operationId) {
216 this.currentOperationDisposables.clear();
217 }
218 }
219 > } progress.ts
220 >
221 > export const IEditorProgressService = createDecorator<IEditorProgressService>('editorProgressService');
222 >
223 > /**
224 > * A progress service that will report progress local to the editor triggered from.
225 > */
226 > export interface IEditorProgressService extends IProgressIndicator {
227 >
228 > readonly _serviceBrand: undefined;
229 > }
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/base/common/policy.ts 161 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- policy.ts
2 > * Copyright (c) Microsoft 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 { IPolicyData } from './defaultAccount.js';
8 >
9 > /**
10 > * System-wide policy file path for Linux systems.
11 > */
12 > export const LINUX_SYSTEM_POLICY_FILE_PATH = '/etc/vscode/policy.json';
13 >
14 > export type PolicyName = string;
15 > export type LocalizedValue = {
16 > key: string;
17 > value: string;
18 > };
19 >
20 > export type PolicyValue = string | number | boolean;
21 > export type ManagedSettingValue = PolicyValue;
22 > export type ManagedSettingsData = Readonly<Record<string, ManagedSettingValue>>;
23 >
24 > export interface IManagedSettingPolicyDefinition {
25 > readonly type: 'string' | 'number' | 'boolean';
26 > }
27 >
28 > export type IManagedSettingsPolicyDefinitions = Readonly<Record<string, IManagedSettingPolicyDefinition>>;
29 >
30 > export enum PolicyCategory {
31 > Extensions = 'Extensions',
32 > IntegratedTerminal = 'IntegratedTerminal',
33 > InteractiveSession = 'InteractiveSession',
34 > Telemetry = 'Telemetry',
35 > Update = 'Update',
36 > }
37 >
38 > export const PolicyCategoryData: {
39 > [key in PolicyCategory]: { name: LocalizedValue }
40 > } = {
41 > [PolicyCategory.Extensions]: {
42 > name: {
43 > key: 'extensionsConfigurationTitle', value: localize('extensionsConfigurationTitle', "Extensions"),
44 > }
45 > },
46 > [PolicyCategory.IntegratedTerminal]: {
47 > name: {
48 > key: 'terminalIntegratedConfigurationTitle', value: localize('terminalIntegratedConfigurationTitle', "Integrated Terminal"),
49 > }
50 > },
51 > [PolicyCategory.InteractiveSession]: {
52 > name: {
53 > key: 'interactiveSessionConfigurationTitle', value: localize('interactiveSessionConfigurationTitle', "Chat"),
54 > }
55 > },
56 > [PolicyCategory.Telemetry]: {
57 > name: {
58 > key: 'telemetryConfigurationTitle', value: localize('telemetryConfigurationTitle', "Telemetry"),
59 > }
60 > },
61 > [PolicyCategory.Update]: {
62 > name: {
63 > key: 'updateConfigurationTitle', value: localize('updateConfigurationTitle', "Update"),
64 > }
65 > }
66 > };
67 >
68 > export interface IPolicy {
69 >
70 > /**
71 > * The policy name.
72 > */
73 > readonly name: PolicyName;
74 >
75 > /**
76 > * The policy category.
77 > */
78 > readonly category: PolicyCategory;
79 >
80 > /**
81 > * The Code version in which this policy was introduced.
82 > */
83 > readonly minimumVersion: `${number}.${number}`;
84 >
85 > /**
86 > * Localization info for the policy.
87 > *
88 > * IMPORTANT: the key values for these must be unique to avoid collisions, as during the export time the module information is not available.
89 > */
90 > readonly localization: {
91 > /** The localization key or key value pair. If only a key is provided, the default value will fallback to the parent configuration's description property. */
92 > description: LocalizedValue;
93 > /** List of localization key or key value pair. If only a key is provided, the default value will fallback to the parent configuration's enumDescriptions property. */
94 > enumDescriptions?: LocalizedValue[];
95 > };
96 >
97 > /**
98 > * The value that an ACCOUNT-based feature will use when its corresponding policy is active.
99 > *
100 > * Only applicable when policy is tagged with ACCOUNT. When an account-based feature's policy is enabled,
101 > * this value determines what value the feature receives.
102 > *
103 > * For example:
104 > * - If evaluated value is `true`, the feature's setting is locked to `true` WHEN the policy is in effect.
105 > * - If evaluated value is `foo`, the feature's setting is locked to 'foo' WHEN the policy is in effect.
106 > *
107 > * If `undefined`, the feature's setting is not locked and can be overridden by other means.
108 > */
109 > readonly value?: (policyData: IPolicyData) => string | number | boolean | undefined;
110 >
111 > /**
112 > * Declares Copilot managed-settings keys this policy's value callback reads.
113 > * Keys are dot-separated managed-settings paths, for example
114 > * `permissions.disableBypassPermissionsMode`.
115 > */
116 > readonly managedSettings?: IManagedSettingsPolicyDefinitions;
117 >
118 > /**
119 > * The most-restrictive value that should be applied when the user is subject to the
120 > * "Require Approved Account" gate but the gate is not yet satisfied (i.e. no approved
121 > * GitHub account is signed in or the account-side policy data has not yet resolved).
122 > *
123 > * If omitted, the gate falls back to a type-driven safe default
124 > * (`false` for boolean, `0` for number, `''` for string).
125 > *
126 > * Only consulted while the gate is active and unsatisfied; ignored otherwise.
127 > */
128 > readonly restrictedValue?: string | number | boolean;
129 > }
130 >
131 > /**
132 > * A subordinate attachment to an existing {@link IPolicy} (the "owner"). A setting may declare a
133 > * `policyReference` instead of a full `policy` to be governed by a policy owned by another setting,
134 > * letting a single enterprise policy lock more than one setting (e.g. gating an agent in both the
135 > * editor window and the Agents window).
136 > *
137 > * A reference is a pure pointer: it carries no policy semantics of its own. The owner is the single
138 > * source of truth for the policy's catalog metadata *and* its runtime behaviour (type, value
139 > * callback, etc.); a reference only contributes the policy name so the setting is gated and the OS
140 > * policy watcher observes the name in processes where the owner is not loaded.
141 > */
142 > export interface IPolicyReference {
143 >
144 > /** The name of the owning {@link IPolicy} this setting attaches to. */
145 > readonly name: PolicyName;
146 > }
147 >
148 > /**
149 > * A `product.json` `extensionConfigurationPolicy` entry that attaches its setting to a policy
150 > * *owned* by an in-code setting, instead of declaring a full owner {@link IPolicy}. This mirrors the
151 > * in-code `policyReference` configuration field, so the same indirection can be expressed from
152 > * `product.json` — where the owner's runtime behaviour (notably its `value` callback) cannot live.
153 > *
154 > * An `extensionConfigurationPolicy` entry is therefore either a full {@link IPolicy} (the setting
155 > * "parents"/owns the policy, the current syntax) or this reference wrapper.
156 > */
157 > export interface IExtensionConfigurationPolicyReference {
158 >
159 > /** Pointer to the owning {@link IPolicy} declared by an in-code setting. */
160 > readonly policyReference: IPolicyReference;
161 > }
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/workbench/contrib/testing/common/testId.ts 158 covered LOC · 23 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- testId.ts
2 > * Copyright (c) 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 TestIdPathParts {
7 > /** Delimiter for path parts in test IDs */
8 > Delimiter = '\0',
9 > }
10 >
11 > /**
12 > * Enum for describing relative positions of tests. Similar to
13 > * `node.compareDocumentPosition` in the DOM.
14 > */
15 > export const enum TestPosition {
16 > /** a === b */
17 > IsSame,
18 > /** Neither a nor b are a child of one another. They may share a common parent, though. */
19 > Disconnected,
20 > /** b is a child of a */
21 > IsChild,
22 > /** b is a parent of a */
23 > IsParent,
24 > }
25 >
26 > type TestItemLike = { id: string; parent?: TestItemLike; _isRoot?: boolean };
27 >
28 > /**
29 > * The test ID is a stringifiable client that
30 > */
31 > export class TestId {
32 > private stringifed?: string;
33 >
34 > /**
35 > * Creates a test ID from an ext host test item.
36 > */
37 > public static fromExtHostTestItem(item: TestItemLike, rootId: string, parent = item.parent) {
38 > if (item._isRoot) {
39 > return new TestId([rootId]);
40 > }
41 >
42 > const path = [item.id];
43 > for (let i = parent; i && i.id !== rootId; i = i.parent) {
44 > path.push(i.id);
45 > }
46 > path.push(rootId);
47 >
48 > return new TestId(path.reverse());
49 > }
50 >
51 > /**
52 > * Cheaply ets whether the ID refers to the root .
53 > */
54 > public static isRoot(idString: string) {
55 return !idString.includes(TestIdPathParts.Delimiter);
56 }
57 > testId.ts
58 > /**
59 > * Cheaply gets whether the ID refers to the root .
60 > */
61 > public static root(idString: string) {
62 const idx = idString.indexOf(TestIdPathParts.Delimiter);
63 return idx === -1 ? idString : idString.slice(0, idx);
64 }
65 > testId.ts
66 > /**
67 > * Creates a test ID from a serialized TestId instance.
68 > */
69 > public static fromString(idString: string) {
70 return new TestId(idString.split(TestIdPathParts.Delimiter));
71 }
72 > testId.ts
73 > /**
74 > * Gets the ID resulting from adding b to the base ID.
75 > */
76 > public static join(base: TestId, b: string) {
77 return new TestId([...base.path, b]);
78 }
79 > testId.ts
80 > /**
81 > * Splits a test ID into its parts.
82 > */
83 > public static split(idString: string) {
84 return idString.split(TestIdPathParts.Delimiter);
85 }
86 > testId.ts
87 > /**
88 > * Gets the string ID resulting from adding b to the base ID.
89 > */
90 > public static joinToString(base: string | TestId, b: string) {
91 return base.toString() + TestIdPathParts.Delimiter + b;
92 }
93 > testId.ts
94 > /**
95 > * Cheaply gets the parent ID of a test identified with the string.
96 > */
97 > public static parentId(idString: string) {
98 const idx = idString.lastIndexOf(TestIdPathParts.Delimiter);
99 return idx === -1 ? undefined : idString.slice(0, idx);
100 }
101 > testId.ts
102 > /**
103 > * Cheaply gets the local ID of a test identified with the string.
104 > */
105 > public static localId(idString: string) {
106 const idx = idString.lastIndexOf(TestIdPathParts.Delimiter);
107 return idx === -1 ? idString : idString.slice(idx + TestIdPathParts.Delimiter.length);
108 }
109 > testId.ts
110 > /**
111 > * Gets whether maybeChild is a child of maybeParent.
112 > * todo@connor4312: review usages of this to see if using the WellDefinedPrefixTree is better
113 > */
114 > public static isChild(maybeParent: string, maybeChild: string) {
115 return maybeChild[maybeParent.length] === TestIdPathParts.Delimiter && maybeChild.startsWith(maybeParent);
116 }
117 > testId.ts
118 > /**
119 > * Compares the position of the two ID strings.
120 > * todo@connor4312: review usages of this to see if using the WellDefinedPrefixTree is better
121 > */
122 > public static compare(a: string, b: string) {
123 if (a === b) {
124 return TestPosition.IsSame;
135 return TestPosition.Disconnected;
136 }
137 > testId.ts
138 > public static getLengthOfCommonPrefix(length: number, getId: (i: number) => TestId): number {
139 if (length === 0) {
140 return 0;
156 return commonPrefix;
157 }
158 > testId.ts
159 > constructor(
160 public readonly path: readonly string[],
161 private readonly viewEnd = path.length,
165 }
166 }
167 > testId.ts
168 > /**
169 > * Gets the ID of the parent test.
170 > */
171 > public get rootId(): TestId {
172 return new TestId(this.path, 1);
173 }
174 > testId.ts
175 > /**
176 > * Gets the ID of the parent test.
177 > */
178 > public get parentId(): TestId | undefined {
179 return this.viewEnd > 1 ? new TestId(this.path, this.viewEnd - 1) : undefined;
180 }
181 > testId.ts
182 > /**
183 > * Gets the local ID of the current full test ID.
184 > */
185 > public get localId() {
186 return this.path[this.viewEnd - 1];
187 }
188 > testId.ts
189 > /**
190 > * Gets whether this ID refers to the root.
191 > */
192 > public get controllerId() {
193 return this.path[0];
194 }
195 > testId.ts
196 > /**
197 > * Gets whether this ID refers to the root.
198 > */
199 > public get isRoot() {
200 return this.viewEnd === 1;
201 }
202 > testId.ts
203 > /**
204 > * Returns an iterable that yields IDs of all parent items down to and
205 > * including the current item.
206 > */
207 > public *idsFromRoot() {
208 for (let i = 1; i <= this.viewEnd; i++) {
209 yield new TestId(this.path, i);
210 }
211 }
212 > testId.ts
213 > /**
214 > * Returns an iterable that yields IDs of the current item up to the root
215 > * item.
216 > */
217 > public *idsToRoot() {
218 for (let i = this.viewEnd; i > 0; i--) {
219 yield new TestId(this.path, i);
220 }
221 }
222 > testId.ts
223 > /**
224 > * Compares the other test ID with this one.
225 > */
226 > public compare(other: TestId | string) {
227 if (typeof other === 'string') {
228 return TestId.compare(this.toString(), other);
245 return TestPosition.IsSame;
246 }
247 > testId.ts
248 > /**
249 > * Serializes the ID.
250 > */
251 > public toJSON() {
252 return this.toString();
253 }
254 > testId.ts
255 > /**
256 > * Serializes the ID to a string.
257 > */
258 > public toString() {
259 if (!this.stringifed) {
260 this.stringifed = this.path[0];
267 return this.stringifed;
268 }
269 > } testId.ts
src/vs/workbench/api/common/extHostTextEditor.ts 153 covered LOC · 32 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostTextEditor.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { ok } from '../../../base/common/assert.js';
7 > import { ReadonlyError, illegalArgument } from '../../../base/common/errors.js';
8 > import { IdGenerator } from '../../../base/common/idGenerator.js';
9 > import { TextEditorCursorStyle } from '../../../editor/common/config/editorOptions.js';
10 > import { IRange } from '../../../editor/common/core/range.js';
11 > import { ISingleEditOperation } from '../../../editor/common/core/editOperation.js';
12 > import { IResolvedTextEditorConfiguration, ITextEditorConfigurationUpdate, MainThreadTextEditorsShape } from './extHost.protocol.js';
13 > import * as TypeConverters from './extHostTypeConverters.js';
14 > import { EndOfLine, Position, Range, Selection, SnippetString, TextEditorLineNumbersStyle, TextEditorRevealType } from './extHostTypes.js';
15 > import type * as vscode from 'vscode';
16 > import { ILogService } from '../../../platform/log/common/log.js';
17 > import { Lazy } from '../../../base/common/lazy.js';
18 > import { IExtensionDescription } from '../../../platform/extensions/common/extensions.js';
19 >
20 > export class TextEditorDecorationType {
21 >
22 > private static readonly _Keys = new IdGenerator('TextEditorDecorationType');
23 >
24 > readonly value: vscode.TextEditorDecorationType;
25 >
26 > constructor(proxy: MainThreadTextEditorsShape, extension: IExtensionDescription, options: vscode.DecorationRenderOptions) {
27 const key = TextEditorDecorationType._Keys.nextId();
28 proxy.$registerTextEditorDecorationType(extension.identifier, key, TypeConverters.DecorationRenderOptions.from(options));
34 });
35 }
37 > }
38 >
39 > export interface ITextEditOperation {
40 > range: vscode.Range;
41 > text: string | null;
42 > forceMoveMarkers: boolean;
43 > }
44 >
45 > export interface IEditData {
46 > documentVersionId: number;
47 > edits: ITextEditOperation[];
48 > setEndOfLine: EndOfLine | undefined;
49 > undoStopBefore: boolean;
50 > undoStopAfter: boolean;
51 > }
52 >
53 > class TextEditorEdit {
54 >
55 > private readonly _document: vscode.TextDocument;
56 > private readonly _documentVersionId: number;
57 > private readonly _undoStopBefore: boolean;
58 > private readonly _undoStopAfter: boolean;
59 > private _collectedEdits: ITextEditOperation[] = [];
60 > private _setEndOfLine: EndOfLine | undefined = undefined;
61 > private _finalized: boolean = false;
62 >
63 > constructor(document: vscode.TextDocument, options: { undoStopBefore: boolean; undoStopAfter: boolean }) {
64 this._document = document;
65 this._documentVersionId = document.version;
67 this._undoStopAfter = options.undoStopAfter;
68 }
70 > finalize(): IEditData {
71 this._finalized = true;
72 return {
78 };
79 }
81 > private _throwIfFinalized() {
82 if (this._finalized) {
83 throw new Error('Edit is only valid while callback runs');
84 }
85 }
87 > replace(location: Position | Range | Selection, value: string): void {
88 this._throwIfFinalized();
89 let range: Range | null = null;
99 this._pushEdit(range, value, false);
100 }
102 > insert(location: Position, value: string): void {
103 this._throwIfFinalized();
104 this._pushEdit(new Range(location, location), value, true);
105 }
107 > delete(location: Range | Selection): void {
108 this._throwIfFinalized();
109 let range: Range | null = null;
117 this._pushEdit(range, null, true);
118 }
120 > private _pushEdit(range: Range, text: string | null, forceMoveMarkers: boolean): void {
121 const validRange = this._document.validateRange(range);
122 this._collectedEdits.push({
126 });
127 }
129 > setEndOfLine(endOfLine: EndOfLine): void {
130 this._throwIfFinalized();
131 if (endOfLine !== EndOfLine.LF && endOfLine !== EndOfLine.CRLF) {
135 this._setEndOfLine = endOfLine;
136 }
138 >
139 > export class ExtHostTextEditorOptions {
140 >
141 > private _proxy: MainThreadTextEditorsShape;
142 > private _id: string;
143 > private _logService: ILogService;
144 >
145 > private _tabSize!: number;
146 > private _indentSize!: number;
147 > private _originalIndentSize!: number | 'tabSize';
148 > private _insertSpaces!: boolean;
149 > private _cursorStyle!: TextEditorCursorStyle;
150 > private _lineNumbers!: TextEditorLineNumbersStyle;
151 >
152 > readonly value: vscode.TextEditorOptions;
153 >
154 > constructor(proxy: MainThreadTextEditorsShape, id: string, source: IResolvedTextEditorConfiguration, logService: ILogService) {
155 this._proxy = proxy;
156 this._id = id;
193 };
194 }
196 > public _accept(source: IResolvedTextEditorConfiguration): void {
197 this._tabSize = source.tabSize;
198 this._indentSize = source.indentSize;
202 this._lineNumbers = TypeConverters.TextEditorLineNumbersStyle.to(source.lineNumbers);
203 }
205 > // --- internal: tabSize
206 >
207 > private _validateTabSize(value: number | string): number | 'auto' | null {
208 if (value === 'auto') {
209 return 'auto';
222 return null;
223 }
225 > private _setTabSize(value: number | string) {
226 const tabSize = this._validateTabSize(value);
227 if (tabSize === null) {
241 }));
242 }
244 > // --- internal: indentSize
245 >
246 > private _validateIndentSize(value: number | string): number | 'tabSize' | null {
247 if (value === 'tabSize') {
248 return 'tabSize';
261 return null;
262 }
264 > private _setIndentSize(value: number | string) {
265 const indentSize = this._validateIndentSize(value);
266 if (indentSize === null) {
281 }));
282 }
284 > // --- internal: insert spaces
285 >
286 > private _validateInsertSpaces(value: boolean | string): boolean | 'auto' {
287 if (value === 'auto') {
288 return 'auto';
290 return (value === 'false' ? false : Boolean(value));
291 }
293 > private _setInsertSpaces(value: boolean | string) {
294 const insertSpaces = this._validateInsertSpaces(value);
295 if (typeof insertSpaces === 'boolean') {
305 }));
306 }
308 > // --- internal: cursor style
309 >
310 > private _setCursorStyle(value: TextEditorCursorStyle) {
311 if (this._cursorStyle === value) {
312 // nothing to do
318 }));
319 }
321 > // --- internal: line number
322 >
323 > private _setLineNumbers(value: TextEditorLineNumbersStyle) {
324 if (this._lineNumbers === value) {
325 // nothing to do
331 }));
332 }
334 > public assign(newOptions: vscode.TextEditorOptions) {
335 const bulkConfigurationUpdate: ITextEditorConfigurationUpdate = {};
336 let hasUpdate = false;
396 }
397 }
399 > private _warnOnError(action: string, promise: Promise<any>): void {
400 promise.catch(err => {
401 this._logService.warn(`ExtHostTextEditorOptions '${action}' failed:'`);
403 });
404 }
406 >
407 > export class ExtHostTextEditor {
408 >
409 > private _selections: Selection[];
410 > private _options: ExtHostTextEditorOptions;
411 > private _visibleRanges: Range[];
412 > private _viewColumn: vscode.ViewColumn | undefined;
413 > private _disposed: boolean = false;
414 > private _hasDecorationsForKey = new Set<string>();
415 > private _diffInformation: vscode.TextEditorDiffInformation[] | undefined;
416 >
417 > readonly value: vscode.TextEditor;
418 >
419 > constructor(
420 readonly id: string,
421 private readonly _proxy: MainThreadTextEditorsShape,
583 });
584 }
586 > dispose() {
587 ok(!this._disposed);
588 this._disposed = true;
589 }
591 > // --- incoming: extension host MUST accept what the renderer says
592 >
593 > _acceptOptions(options: IResolvedTextEditorConfiguration): void {
594 ok(!this._disposed);
595 this._options._accept(options);
596 }
598 > _acceptVisibleRanges(value: Range[]): void {
599 ok(!this._disposed);
600 this._visibleRanges = value;
601 }
603 > _acceptViewColumn(value: vscode.ViewColumn) {
604 ok(!this._disposed);
605 this._viewColumn = value;
606 }
608 > _acceptSelections(selections: Selection[]): void {
609 ok(!this._disposed);
610 this._selections = selections;
611 }
613 > _acceptDiffInformation(diffInformation: vscode.TextEditorDiffInformation[] | undefined): void {
614 ok(!this._disposed);
615 this._diffInformation = diffInformation;
616 }
618 > private async _trySetSelection(): Promise<vscode.TextEditor | null | undefined> {
619 const selection = this._selections.map(TypeConverters.Selection.from);
620 await this._runOnProxy(() => this._proxy.$trySetSelections(this.id, selection));
621 return this.value;
622 }
624 > private _applyEdit(editBuilder: TextEditorEdit): Promise<boolean> {
625 const editData = editBuilder.finalize();
626
675 });
676 }
677 > private _runOnProxy(callback: () => Promise<any>): Promise<ExtHostTextEditor | undefined | null> { extHostTextEditor.ts
678 if (this._disposed) {
679 this._logService.warn('TextEditor is closed/disposed');
src/vs/workbench/api/common/extHostCommands.ts 152 covered LOC · 21 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostCommands.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { validateConstraint } from '../../../base/common/types.js';
7 > import { ICommandMetadata } from '../../../platform/commands/common/commands.js';
8 > import * as extHostTypes from './extHostTypes.js';
9 > import * as extHostTypeConverter from './extHostTypeConverters.js';
10 > import { cloneAndChange } from '../../../base/common/objects.js';
11 > import { MainContext, MainThreadCommandsShape, ExtHostCommandsShape, ICommandDto, ICommandMetadataDto, MainThreadTelemetryShape } from './extHost.protocol.js';
12 > import { isNonEmptyArray } from '../../../base/common/arrays.js';
13 > import * as languages from '../../../editor/common/languages.js';
14 > import type * as vscode from 'vscode';
15 > import { ILogService } from '../../../platform/log/common/log.js';
16 > import { revive } from '../../../base/common/marshalling.js';
17 > import { IRange, Range } from '../../../editor/common/core/range.js';
18 > import { IPosition, Position } from '../../../editor/common/core/position.js';
19 > import { URI } from '../../../base/common/uri.js';
20 > import { DisposableStore, toDisposable } from '../../../base/common/lifecycle.js';
21 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
22 > import { IExtHostRpcService } from './extHostRpcService.js';
23 > import { ISelection } from '../../../editor/common/core/selection.js';
24 > import { TestItemImpl } from './extHostTestItem.js';
25 > import { VSBuffer } from '../../../base/common/buffer.js';
26 > import { SerializableObjectWithBuffers } from '../../services/extensions/common/proxyIdentifier.js';
27 > import { toErrorMessage } from '../../../base/common/errorMessage.js';
28 > import { StopWatch } from '../../../base/common/stopwatch.js';
29 > import { IExtensionDescription } from '../../../platform/extensions/common/extensions.js';
30 > import { TelemetryTrustedValue } from '../../../platform/telemetry/common/telemetryUtils.js';
31 > import { IExtHostTelemetry } from './extHostTelemetry.js';
32 > import { generateUuid } from '../../../base/common/uuid.js';
33 > import { isCancellationError } from '../../../base/common/errors.js';
34 >
35 > interface CommandHandler {
36 > callback: Function;
37 > thisArg: any;
38 > metadata?: ICommandMetadata;
39 > extension?: IExtensionDescription;
40 > }
41 >
42 > export interface ArgumentProcessor {
43 > processArgument(arg: any, extension: IExtensionDescription | undefined): any;
44 > }
45 >
46 > export class ExtHostCommands implements ExtHostCommandsShape {
47 >
48 > readonly _serviceBrand: undefined;
49 >
50 > #proxy: MainThreadCommandsShape;
51 >
52 > private readonly _commands = new Map<string, CommandHandler>();
53 > private readonly _apiCommands = new Map<string, ApiCommand>();
54 > #telemetry: MainThreadTelemetryShape;
55 >
56 > private readonly _logService: ILogService;
57 > readonly #extHostTelemetry: IExtHostTelemetry;
58 > private readonly _argumentProcessors: ArgumentProcessor[];
59 >
60 > readonly converter: CommandsConverter;
61 >
62 > constructor(
63 @IExtHostRpcService extHostRpc: IExtHostRpcService,
64 @ILogService logService: ILogService,
112 ];
113 }
115 > registerArgumentProcessor(processor: ArgumentProcessor): void {
116 this._argumentProcessors.push(processor);
117 }
119 > registerApiCommand(apiCommand: ApiCommand): extHostTypes.Disposable {
120
121
144 });
145 }
147 > registerCommand(global: boolean, id: string, callback: <T>(...args: any[]) => T | Thenable<T>, thisArg?: any, metadata?: ICommandMetadata, extension?: IExtensionDescription): extHostTypes.Disposable {
148 this._logService.trace('ExtHostCommands#registerCommand', id);
149
169 });
170 }
172 > executeCommand<T>(id: string, ...args: unknown[]): Promise<T> {
173 this._logService.trace('ExtHostCommands#executeCommand', id);
174 return this._doExecuteCommand(id, args, true);
175 }
177 > private async _doExecuteCommand<T>(id: string, args: unknown[], retry: boolean): Promise<T> {
178
179 if (this._commands.has(id)) {
227 }
228 }
230 > private async _executeContributedCommand<T = unknown>(id: string, args: unknown[], annotateError: boolean): Promise<T> {
231 const command = this._commands.get(id);
232 if (!command) {
281 }
282 }
284 > private _reportTelemetry(command: CommandHandler, id: string, duration: number) {
285 if (!command.extension) {
286 return;
308 });
309 }
311 > $executeContributedCommand(id: string, ...args: unknown[]): Promise<unknown> {
312 this._logService.trace('ExtHostCommands#$executeContributedCommand', id);
313
320 }
321 }
323 > getCommands(filterUnderscoreCommands: boolean = false): Promise<string[]> {
324 this._logService.trace('ExtHostCommands#getCommands', filterUnderscoreCommands);
325
331 });
332 }
334 > $getContributedCommandMetadata(): Promise<{ [id: string]: string | ICommandMetadataDto }> {
335 const result: { [id: string]: string | ICommandMetadata } = Object.create(null);
336 for (const [id, command] of this._commands) {
342 return Promise.resolve(result);
343 }
345 >
346 > export interface IExtHostCommands extends ExtHostCommands { }
347 > export const IExtHostCommands = createDecorator<IExtHostCommands>('IExtHostCommands');
348 >
349 > export class CommandsConverter implements extHostTypeConverter.Command.ICommandsConverter {
350 >
351 > readonly delegatingCommandId: string = `__vsc${generateUuid()}`;
352 > private readonly _cache = new Map<string, vscode.Command>();
353 > private _cachIdPool = 0;
354 >
355 > // --- conversion between internal and api commands
356 > constructor(
357 private readonly _commands: ExtHostCommands,
358 private readonly _lookupApiCommand: (id: string) => ApiCommand | undefined,
361 this._commands.registerCommand(true, this.delegatingCommandId, this._executeConvertedCommand, this);
362 }
364 > toInternal(command: vscode.Command, disposables: DisposableStore): ICommandDto;
365 > toInternal(command: vscode.Command | undefined, disposables: DisposableStore): ICommandDto | undefined;
366 > toInternal(command: vscode.Command | undefined, disposables: DisposableStore): ICommandDto | undefined {
367
368 if (!command) {
410 return result;
411 }
413 > fromInternal(command: ICommandDto): vscode.Command | undefined {
414
415 if (typeof command.$ident === 'string') {
424 }
425 }
427 >
428 > getActualCommand(...args: unknown[]): vscode.Command | undefined {
429 return this._cache.get(args[0] as string);
430 }
432 > private _executeConvertedCommand<R>(...args: unknown[]): Promise<R> {
433 const actualCmd = this.getActualCommand(...args);
434 this._logService.trace('CommandsConverter#EXECUTE', args[0], actualCmd ? actualCmd.command : 'MISSING');
439 return this._commands.executeCommand(actualCmd.command, ...(actualCmd.arguments || []));
440 }
442 > }
443 >
444 >
445 > export class ApiCommandArgument<V, O = V> {
446 >
447 > static readonly Uri = new ApiCommandArgument<URI>('uri', 'Uri of a text document', v => URI.isUri(v), v => v);
448 > static readonly Position = new ApiCommandArgument<extHostTypes.Position, IPosition>('position', 'A position in a text document', v => extHostTypes.Position.isPosition(v), extHostTypeConverter.Position.from);
449 > static readonly Range = new ApiCommandArgument<extHostTypes.Range, IRange>('range', 'A range in a text document', v => extHostTypes.Range.isRange(v), extHostTypeConverter.Range.from);
450 > static readonly Selection = new ApiCommandArgument<extHostTypes.Selection, ISelection>('selection', 'A selection in a text document', v => extHostTypes.Selection.isSelection(v), extHostTypeConverter.Selection.from);
451 > static readonly Number = new ApiCommandArgument<number>('number', '', v => typeof v === 'number', v => v);
452 > static readonly String = new ApiCommandArgument<string>('string', '', v => typeof v === 'string', v => v);
453 >
454 > static Arr<T, K = T>(element: ApiCommandArgument<T, K>) {
455 return new ApiCommandArgument(
456 `${element.name}_array`,
460 );
461 }
463 > static readonly CallHierarchyItem = new ApiCommandArgument('item', 'A call hierarchy item', v => v instanceof extHostTypes.CallHierarchyItem, extHostTypeConverter.CallHierarchyItem.from);
464 > static readonly TypeHierarchyItem = new ApiCommandArgument('item', 'A type hierarchy item', v => v instanceof extHostTypes.TypeHierarchyItem, extHostTypeConverter.TypeHierarchyItem.from);
465 > static readonly TestItem = new ApiCommandArgument('testItem', 'A VS Code TestItem', v => v instanceof TestItemImpl, extHostTypeConverter.TestItem.from);
466 > static readonly TestProfile = new ApiCommandArgument('testProfile', 'A VS Code test profile', v => v instanceof extHostTypes.TestRunProfileBase, extHostTypeConverter.TestRunProfile.from);
467 >
468 > constructor(
469 > readonly name: string,
470 > readonly description: string,
471 > readonly validate: (v: V) => boolean,
472 > readonly convert: (v: V) => O
473 > ) { }
474 >
475 > optional(): ApiCommandArgument<V | undefined | null, O | undefined | null> {
476 return new ApiCommandArgument(
477 this.name, `(optional) ${this.description}`,
480 );
481 }
483 > with(name: string | undefined, description: string | undefined): ApiCommandArgument<V, O> {
484 return new ApiCommandArgument(name ?? this.name, description ?? this.description, this.validate, this.convert);
485 }
487 >
488 > export class ApiCommandResult<V, O = V> {
489 >
490 > static readonly Void = new ApiCommandResult<void, void>('no result', v => v);
491 >
492 > constructor(
493 > readonly description: string,
494 > readonly convert: (v: V, apiArgs: any[], cmdConverter: CommandsConverter) => O
495 > ) { }
496 > }
497 >
498 > export class ApiCommand {
499 >
500 > constructor(
501 readonly id: string,
502 readonly internalId: string,
src/vs/base/common/actions.ts 151 covered LOC · 25 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- actions.ts
2 > * Copyright (c) Microsoft 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 > import * as nls from '../../nls.js';
9 >
10 > export interface ITelemetryData {
11 > readonly from?: string;
12 > readonly target?: string;
13 > [key: string]: unknown;
14 > }
15 >
16 > export type WorkbenchActionExecutedClassification = {
17 > id: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The identifier of the action that was run.' };
18 > from: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The name of the component the action was run from.' };
19 > detail?: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Optional details about how the action was run, e.g which keybinding was used.' };
20 > owner: 'isidorn';
21 > comment: 'Provides insight into actions that are executed within the workbench.';
22 > };
23 >
24 > export type WorkbenchActionExecutedEvent = {
25 > id: string;
26 > from: string;
27 > detail?: string;
28 > };
29 >
30 > export interface IAction {
31 > readonly id: string;
32 > label: string;
33 > tooltip: string;
34 > class: string | undefined;
35 > enabled: boolean;
36 > checked?: boolean;
37 > run(...args: unknown[]): unknown;
38 > }
39 >
40 > export interface IActionRunner extends IDisposable {
41 > readonly onDidRun: Event<IRunEvent>;
42 > readonly onWillRun: Event<IRunEvent>;
43 >
44 > run(action: IAction, context?: unknown): unknown;
45 > }
46 >
47 > export interface IActionChangeEvent {
48 > readonly label?: string;
49 > readonly tooltip?: string;
50 > readonly class?: string;
51 > readonly enabled?: boolean;
52 > readonly checked?: boolean;
53 > }
54 >
55 > /**
56 > * A concrete implementation of {@link IAction}.
57 > *
58 > * Note that in most cases you should use the lighter-weight {@linkcode toAction} function instead.
59 > */
60 > export class Action extends Disposable implements IAction {
61 >
62 > protected _onDidChange = this._register(new Emitter<IActionChangeEvent>());
63 > get onDidChange() { return this._onDidChange.event; }
64 >
65 > protected readonly _id: string;
66 > protected _label: string;
67 > protected _tooltip: string | undefined;
68 > protected _cssClass: string | undefined;
69 > protected _enabled: boolean = true;
70 > protected _checked?: boolean;
71 > protected readonly _actionCallback?: (event?: unknown) => unknown;
72 >
73 > constructor(id: string, label: string = '', cssClass: string = '', enabled: boolean = true, actionCallback?: (event?: unknown) => unknown) {
74 super();
75 this._id = id;
79 this._actionCallback = actionCallback;
80 }
81 > actions.ts
82 > get id(): string {
83 return this._id;
84 }
85 > actions.ts
86 > get label(): string {
87 return this._label;
88 }
89 > actions.ts
90 > set label(value: string) {
91 this._setLabel(value);
92 }
93 > actions.ts
94 > private _setLabel(value: string): void {
95 if (this._label !== value) {
96 this._label = value;
98 }
99 }
100 > actions.ts
101 > get tooltip(): string {
102 return this._tooltip || '';
103 }
104 > actions.ts
105 > set tooltip(value: string) {
106 this._setTooltip(value);
107 }
108 > actions.ts
109 > protected _setTooltip(value: string): void {
110 if (this._tooltip !== value) {
111 this._tooltip = value;
113 }
114 }
115 > actions.ts
116 > get class(): string | undefined {
117 return this._cssClass;
118 }
119 > actions.ts
120 > set class(value: string | undefined) {
121 this._setClass(value);
122 }
123 > actions.ts
124 > protected _setClass(value: string | undefined): void {
125 if (this._cssClass !== value) {
126 this._cssClass = value;
128 }
129 }
130 > actions.ts
131 > get enabled(): boolean {
132 return this._enabled;
133 }
134 > actions.ts
135 > set enabled(value: boolean) {
136 this._setEnabled(value);
137 }
138 > actions.ts
139 > protected _setEnabled(value: boolean): void {
140 if (this._enabled !== value) {
141 this._enabled = value;
143 }
144 }
145 > actions.ts
146 > get checked(): boolean | undefined {
147 return this._checked;
148 }
149 > actions.ts
150 > set checked(value: boolean | undefined) {
151 this._setChecked(value);
152 }
153 > actions.ts
154 > protected _setChecked(value: boolean | undefined): void {
155 if (this._checked !== value) {
156 this._checked = value;
158 }
159 }
160 > actions.ts
161 > async run(event?: unknown, data?: ITelemetryData): Promise<void> {
162 if (this._actionCallback) {
163 await this._actionCallback(event);
164 }
165 }
166 > } actions.ts
167 >
168 > export interface IRunEvent {
169 > readonly action: IAction;
170 > readonly error?: Error;
171 > }
172 >
173 > export class ActionRunner extends Disposable implements IActionRunner {
174
175 private readonly _onWillRun = this._register(new Emitter<IRunEvent>());
177
178 private readonly _onDidRun = this._register(new Emitter<IRunEvent>());
179 > get onDidRun() { return this._onDidRun.event; } actions.ts
180 >
181 > async run(action: IAction, context?: unknown): Promise<void> {
182 if (!action.enabled) {
183 return;
195 this._onDidRun.fire({ action, error });
196 }
197 > actions.ts
198 > protected async runAction(action: IAction, context?: unknown): Promise<void> {
199 await action.run(context);
200 }
201 > } actions.ts
202 >
203 > export class Separator implements IAction {
204
205 /**
248 readonly enabled: boolean = false;
249 readonly checked: undefined = undefined;
250 > async run() { } actions.ts
251 > }
252 >
253 > export class SubmenuAction implements IAction {
254 >
255 > readonly id: string;
256 > readonly label: string;
257 > readonly class: string | undefined;
258 > readonly tooltip: string = '';
259 > readonly enabled: boolean = true;
260 > readonly checked: undefined = undefined;
261 >
262 > private readonly _actions: readonly IAction[];
263 > get actions(): readonly IAction[] { return this._actions; }
264 >
265 > constructor(id: string, label: string, actions: readonly IAction[], cssClass?: string) {
266 this.id = id;
267 this.label = label;
269 this._actions = actions;
270 }
271 > actions.ts
272 > async run(): Promise<void> { }
273 > }
274 >
275 > export class EmptySubmenuAction extends Action {
276 >
277 > static readonly ID = 'vs.actions.empty';
278 >
279 > constructor() {
280 super(EmptySubmenuAction.ID, nls.localize('submenu.empty', '(empty)'), undefined, false);
281 }
282 > } actions.ts
283 >
284 > export function toAction(props: { id: string; label: string; tooltip?: string; enabled?: boolean; checked?: boolean; class?: string; run: Function }): IAction {
285 return {
286 id: props.id,
src/vs/workbench/api/common/extHostLanguageModels.ts 149 covered LOC · 35 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostLanguageModels.ts
2 > * Copyright (c) Microsoft 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 * as vscode from 'vscode';
7 > import { AsyncIterableProducer, AsyncIterableSource, RunOnceScheduler } from '../../../base/common/async.js';
8 > import { VSBuffer } from '../../../base/common/buffer.js';
9 > import { CancellationToken, CancellationTokenSource } from '../../../base/common/cancellation.js';
10 > import { SerializedError, transformErrorForSerialization, transformErrorFromSerialization } from '../../../base/common/errors.js';
11 > import { Emitter, Event } from '../../../base/common/event.js';
12 > import { Iterable } from '../../../base/common/iterator.js';
13 > import { DisposableMap, IDisposable, toDisposable } from '../../../base/common/lifecycle.js';
14 > import { IJSONSchema } from '../../../base/common/jsonSchema.js';
15 > import { URI, UriComponents } from '../../../base/common/uri.js';
16 > import { localize } from '../../../nls.js';
17 > import { ExtensionIdentifier, ExtensionIdentifierMap, ExtensionIdentifierSet, IExtensionDescription } from '../../../platform/extensions/common/extensions.js';
18 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
19 > import { ILogService } from '../../../platform/log/common/log.js';
20 > import { Progress } from '../../../platform/progress/common/progress.js';
21 > import { COPILOT_VENDOR_ID, IChatMessage, IChatResponsePart, ILanguageModelChatInfoOptions, ILanguageModelChatMetadata, ILanguageModelChatMetadataAndIdentifier, ILanguageModelChatRequestOptions } from '../../contrib/chat/common/languageModels.js';
22 > import { INTERNAL_AUTH_PROVIDER_PREFIX } from '../../services/authentication/common/authentication.js';
23 > import { checkProposedApiEnabled, isProposedApiEnabled } from '../../services/extensions/common/extensions.js';
24 > import { SerializableObjectWithBuffers } from '../../services/extensions/common/proxyIdentifier.js';
25 > import { ExtHostLanguageModelsShape, MainContext, MainThreadLanguageModelsShape } from './extHost.protocol.js';
26 > import { IExtHostAuthentication } from './extHostAuthentication.js';
27 > import { IExtHostRpcService } from './extHostRpcService.js';
28 > import * as typeConvert from './extHostTypeConverters.js';
29 > import * as extHostTypes from './extHostTypes.js';
30 > import { ChatAgentLocation } from '../../contrib/chat/common/constants.js';
31 >
32 > export interface IExtHostLanguageModels extends ExtHostLanguageModels { }
33 >
34 > export const IExtHostLanguageModels = createDecorator<IExtHostLanguageModels>('IExtHostLanguageModels');
35 >
36 > type LanguageModelProviderData = {
37 > readonly extension: IExtensionDescription;
38 > readonly provider: vscode.LanguageModelChatProvider;
39 > };
40 >
41 > type LMResponsePart = vscode.LanguageModelTextPart | vscode.LanguageModelToolCallPart | vscode.LanguageModelDataPart | vscode.LanguageModelThinkingPart;
42 >
43 >
44 > class LanguageModelResponse {
45 >
46 > readonly apiObject: vscode.LanguageModelChatResponse;
47 >
48 > private readonly _defaultStream = new AsyncIterableSource<LMResponsePart>();
49 > private _isDone: boolean = false;
50 >
51 > constructor() {
52
53 const that = this;
71 };
72 }
74 > handleResponsePart(parts: IChatResponsePart | IChatResponsePart[]): void {
75 if (this._isDone) {
76 return;
97 this._defaultStream.emitMany(lmResponseParts);
98 }
100 > reject(err: Error): void {
101 this._isDone = true;
102 this._defaultStream.reject(err);
103 }
105 > resolve(): void {
106 this._isDone = true;
107 this._defaultStream.resolve();
108 }
110 >
111 > export class ExtHostLanguageModels implements ExtHostLanguageModelsShape {
112 >
113 > declare _serviceBrand: undefined;
114 >
115 > private static _idPool = 1;
116 >
117 > private readonly _proxy: MainThreadLanguageModelsShape;
118 > private readonly _onDidChangeModelAccess = new Emitter<{ from: ExtensionIdentifier; to: ExtensionIdentifier }>();
119 > private readonly _onDidChangeProviders = new Emitter<void>();
120 > readonly onDidChangeProviders = this._onDidChangeProviders.event;
121 > private readonly _onDidChangeModelProxyAvailability = new Emitter<void>();
122 > readonly onDidChangeModelProxyAvailability = this._onDidChangeModelProxyAvailability.event;
123 >
124 > private readonly _languageModelProviders = new Map<string, LanguageModelProviderData>();
125 > // TODO @lramos15 - Remove the need for both info and metadata as it's a lot of redundancy. Should just need one
126 > private readonly _localModels = new Map<string, { group: string | undefined; metadata: ILanguageModelChatMetadata; info: vscode.LanguageModelChatInformation }>();
127 > private readonly _modelAccessList = new ExtensionIdentifierMap<ExtensionIdentifierSet>();
128 > private readonly _pendingRequest = new Map<number, { languageModelId: string; res: LanguageModelResponse }>();
129 > private readonly _pendingCancelCTS = new DisposableMap<number, CancellationTokenSource>();
130 > private readonly _ignoredFileProviders = new Map<number, vscode.LanguageModelIgnoredFileProvider>();
131 > private _languageModelProxyProvider: vscode.LanguageModelProxyProvider | undefined;
132 >
133 > constructor(
134 @IExtHostRpcService extHostRpc: IExtHostRpcService,
135 @ILogService private readonly _logService: ILogService,
138 this._proxy = extHostRpc.getProxy(MainContext.MainThreadLanguageModels);
139 }
141 > dispose(): void {
142 this._onDidChangeModelAccess.dispose();
143 this._onDidChangeProviders.dispose();
146 this._pendingCancelCTS.dispose();
147 }
149 > registerLanguageModelChatProvider(extension: IExtensionDescription, vendor: string, provider: vscode.LanguageModelChatProvider): IDisposable {
150
151 this._languageModelProviders.set(vendor, { extension: extension, provider });
170 });
171 }
173 > private toModelIdentifier(vendor: string, group: string | undefined, modelId: string): string {
174 return group ? `${vendor}/${group}/${modelId}` : `${vendor}/${modelId}`;
175 }
177 > private getVendorFromModelIdentifier(modelIdentifier: string): string | undefined {
178 const firstSlash = modelIdentifier.indexOf('/');
179 return firstSlash === -1 ? undefined : modelIdentifier.substring(0, firstSlash);
180 }
182 > async $provideLanguageModelChatInfo(vendor: string, options: ILanguageModelChatInfoOptions, token: CancellationToken): Promise<ILanguageModelChatMetadataAndIdentifier[]> {
183 const data = this._languageModelProviders.get(vendor);
184 if (!data) {
274 return modelMetadataAndIdentifier;
275 }
277 > async $startChatRequest(modelId: string, requestId: number, from: ExtensionIdentifier | undefined, messages: SerializableObjectWithBuffers<IChatMessage[]>, options: ILanguageModelChatRequestOptions, token: CancellationToken): Promise<void> {
278 const knownModel = this._localModels.get(modelId);
279 if (!knownModel) {
366 });
367 }
369 > //#region --- token counting
370 >
371 > $cancelLanguageModelChatRequest(requestId: number): void {
372 this._pendingCancelCTS.get(requestId)?.cancel();
373 }
375 > $provideTokenLength(modelId: string, value: string, token: CancellationToken): Promise<number> {
376 const knownModel = this._localModels.get(modelId);
377 if (!knownModel) {
384 return Promise.resolve(data.provider.provideTokenCount(knownModel.info, value, token));
385 }
387 >
388 > //#region --- making request
389 >
390 > async getDefaultLanguageModel(extension: IExtensionDescription, forceResolveModels?: boolean): Promise<vscode.LanguageModelChat | undefined> {
391 let defaultModelId: string | undefined;
392
407 return this.getLanguageModelByIdentifier(extension, defaultModelId);
408 }
410 > async getLanguageModelByIdentifier(extension: IExtensionDescription, modelId: string | undefined): Promise<vscode.LanguageModelChat | undefined> {
411 if (!modelId) {
412 return undefined;
431 return this._createLanguageModelChatApi(extension, modelId);
432 }
434 > private async _createLanguageModelChatApi(extension: IExtensionDescription, modelId: string): Promise<vscode.LanguageModelChat | undefined> {
435 const model = this._localModels.get(modelId);
436 if (!model) {
484 return apiObject;
485 }
487 > async selectLanguageModels(extension: IExtensionDescription, selector: vscode.LanguageModelChatSelector) {
488
489 // this triggers extension activation
494 return modelResults.filter((m): m is vscode.LanguageModelChat => !!m);
495 }
497 > private async _sendChatRequest(extension: IExtensionDescription, languageModelId: string, messages: vscode.LanguageModelChatMessage2[], options: vscode.LanguageModelChatRequestOptions, token: CancellationToken) {
498
499 const internalMessages: IChatMessage[] = this._convertMessages(extension, messages);
537 return res.apiObject;
538 }
540 > private _convertMessages(extension: IExtensionDescription, messages: vscode.LanguageModelChatMessage2[]) {
541 const internalMessages: IChatMessage[] = [];
542 for (const message of messages) {
548 return internalMessages;
549 }
551 > async $acceptResponsePart(requestId: number, chunk: SerializableObjectWithBuffers<IChatResponsePart | IChatResponsePart[]>): Promise<void> {
552 const data = this._pendingRequest.get(requestId);
553 if (data) {
555 }
556 }
558 > $onChatModelsChange(): void {
559 this._onDidChangeProviders.fire();
560 }
562 > async $acceptResponseDone(requestId: number, error: SerializedError | undefined): Promise<void> {
563 const data = this._pendingRequest.get(requestId);
564 if (!data) {
575 }
576 }
578 > // BIG HACK: Using AuthenticationProviders to check access to Language Models
579 > private async _getAuthAccess(from: IExtensionDescription, to: { identifier: ExtensionIdentifier; displayName: string }, justification: string | undefined, silent: boolean | undefined): Promise<boolean> {
580 // This needs to be done in both MainThread & ExtHost ChatProvider
581 const providerId = INTERNAL_AUTH_PROVIDER_PREFIX + to.identifier.value;
604 }
605 }
607 > private _isUsingAuth(from: ExtensionIdentifier, toMetadata: ILanguageModelChatMetadata): toMetadata is ILanguageModelChatMetadata & { auth: NonNullable<ILanguageModelChatMetadata['auth']> } {
608 // If the 'to' extension uses an auth check
609 return !!toMetadata.auth
611 && !ExtensionIdentifier.equals(toMetadata.extension, from);
612 }
614 > private async _fakeAuthPopulate(metadata: ILanguageModelChatMetadata): Promise<void> {
615
616 if (!metadata.auth) {
627 }
628 }
630 > private async _computeTokenLength(modelId: string, value: string | vscode.LanguageModelChatMessage2, token: vscode.CancellationToken): Promise<number> {
631
632 const data = this._localModels.get(modelId);
637 // return this._proxy.$countTokens(languageModelId, (typeof value === 'string' ? value : typeConvert.LanguageModelChatMessage2.from(value)), token);
638 }
640 > $updateModelAccesslist(data: { from: ExtensionIdentifier; to: ExtensionIdentifier; enabled: boolean }[]): void {
641 const updated = new Array<{ from: ExtensionIdentifier; to: ExtensionIdentifier }>();
642 for (const { from, to, enabled } of data) {
656 }
657 }
659 > private readonly _languageAccessInformationExtensions = new Set<Readonly<IExtensionDescription>>();
660 >
661 > createLanguageModelAccessInformation(from: Readonly<IExtensionDescription>): vscode.LanguageModelAccessInformation {
662
663 this._languageAccessInformationExtensions.add(from);
700 };
701 }
703 > fileIsIgnored(extension: IExtensionDescription, uri: vscode.Uri, token: vscode.CancellationToken = CancellationToken.None): Promise<boolean> {
704 checkProposedApiEnabled(extension, 'chatParticipantAdditions');
705
706 return this._proxy.$fileIsIgnored(uri, token);
707 }
709 > get isModelProxyAvailable(): boolean {
710 return !!this._languageModelProxyProvider;
711 }
713 > async getModelProxy(extension: IExtensionDescription): Promise<vscode.LanguageModelProxy> {
714 checkProposedApiEnabled(extension, 'languageModelProxy');
715
732 }
733 }
735 > async $isFileIgnored(handle: number, uri: UriComponents, token: CancellationToken): Promise<boolean> {
736 const provider = this._ignoredFileProviders.get(handle);
737 if (!provider) {
741 return (await provider.provideFileIgnored(URI.revive(uri), token)) ?? false;
742 }
744 > registerIgnoredFileProvider(extension: IExtensionDescription, provider: vscode.LanguageModelIgnoredFileProvider): vscode.Disposable {
745 checkProposedApiEnabled(extension, 'chatParticipantPrivate');
746
753 });
754 }
756 > registerLanguageModelProxyProvider(extension: IExtensionDescription, provider: vscode.LanguageModelProxyProvider): vscode.Disposable {
757 checkProposedApiEnabled(extension, 'chatParticipantPrivate');
758
src/vs/platform/agentHost/common/state/protocol/channels-chat/commands.ts 147 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- commands.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > // allow-any-unicode-comment-file
7 > // DO NOT EDIT -- auto-generated by scripts/sync-agent-host-protocol.ts
8 >
9 > import type { URI } from '../common/state.js';
10 > import type { BaseParams } from '../common/commands.js';
11 > import type { Message, SideChatSelection } from './state.js';
12 >
13 > // ─── createChat ──────────────────────────────────────────────────────────────
14 >
15 > /**
16 > * How a new chat uses its source chat and turn.
17 > */
18 > export const enum ChatSourceKind {
19 > /** Copy source history through the referenced turn into the new chat. */
20 > Fork = 'fork',
21 > /** Supply source context without copying it into the new chat's visible history. */
22 > SideChat = 'sideChat',
23 > }
24 >
25 > /**
26 > * Copies source history through a completed turn into the new chat.
27 > */
28 > export interface ForkChatSource {
29 > /** Discriminant */
30 > kind: ChatSourceKind.Fork;
31 > /** URI of the existing source chat. */
32 > chat: URI;
33 > /**
34 > * Completed turn identifier in the source chat.
35 > *
36 > * Content through this turn is copied into the new chat's visible `turns`.
37 > */
38 > turnId: string;
39 > }
40 >
41 > /**
42 > * Supplies source context to a new side chat without copying it into the side
43 > * chat's visible history.
44 > */
45 > export interface SideChatSource {
46 > /** Discriminant */
47 > kind: ChatSourceKind.SideChat;
48 > /** URI of the existing source chat. */
49 > chat: URI;
50 > /**
51 > * Stable source-turn identifier in the source chat.
52 > *
53 > * Hosts resolve this id against the source chat's current `activeTurn` or its
54 > * retained `turns` when accepting `createChat`. If it names the current
55 > * active turn, the host snapshots the source chat's retained history plus
56 > * that turn's current user message and any partial assistant response already
57 > * available. Once that turn later becomes historical, it is still referenced
58 > * by this same identifier.
59 > */
60 > turnId: string;
61 > /**
62 > * Optional immutable selected-text snapshot to carry into the created side
63 > * chat's origin.
64 > *
65 > * When present, the host MUST snapshot and preserve this exact selection when
66 > * it accepts `createChat`; later source-turn deltas do not alter it.
67 > */
68 > selection?: SideChatSelection;
69 > }
70 >
71 > /**
72 > * Identifies a source chat for a new chat.
73 > */
74 > export type ChatSource =
75 > | ForkChatSource
76 > | SideChatSource;
77 >
78 > /**
79 > * Creates a new chat within a session.
80 > *
81 > * @category Commands
82 > * @method createChat
83 > * @direction Client → Server
84 > * @messageType Request
85 > * @version 1
86 > */
87 > export interface CreateChatParams extends BaseParams {
88 > /** Session URI containing the new chat. */
89 > channel: URI;
90 > /** Chat URI (client-chosen, e.g. `ahp-chat:/<uuid>`). */
91 > chat: URI;
92 > /** Optional initial message for the new chat. */
93 > initialMessage?: Message;
94 > /**
95 > * Optional source chat and source turn.
96 > *
97 > * The source chat MUST belong to this session. Clients MUST only request
98 > * `kind: "fork"` when the selected agent advertises
99 > * `capabilities.multipleChats.fork`, and `kind: "sideChat"` when the
100 > * selected agent advertises `capabilities.multipleChats.sideChat`. Both
101 > * source forms carry a stable top-level `turnId`. Forks target completed
102 > * turns. Side chats also carry a stable `turnId`, which the host resolves
103 > * against the source chat's current active turn or retained history. If it
104 > * resolves to the active turn, the host snapshots the currently available
105 > * partial response when accepting `createChat`. When
106 > * `source.kind === "sideChat"` and `source.selection` is present, the host
107 > * also snapshots and preserves that exact selected text in the created chat's
108 > * origin; any `responsePartId` there is provenance only, not a live range.
109 > */
110 > source?: ChatSource;
111 > /**
112 > * Initial working-directory subset for this chat. Every entry MUST be
113 > * present in the owning session's `workingDirectories`; the server MUST
114 > * reject any entry that is not. When absent, the chat inherits the full
115 > * session set. Forked chats (those whose `source.kind` is `"fork"`) inherit
116 > * the source chat's `workingDirectories`; this field is ignored for forks.
117 > *
118 > * A client MUST NOT supply this field unless the agent advertises
119 > * {@link AgentCapabilities.multipleWorkingDirectories}.
120 > */
121 > workingDirectories?: URI[];
122 > /**
123 > * The chat's primary working directory — the distinguished root this chat is
124 > * centered on. When set, it MUST be one of the chat's effective working
125 > * directories ({@link workingDirectories}, or the session's set when that is
126 > * omitted). A client SHOULD supply this when the agent advertises
127 > * {@link MultipleWorkingDirectoriesCapability.requiresPrimary}; a host MAY
128 > * reject creation that omits it, or fall back to the first of the chat's
129 > * directories. Fixed at creation and reported (read-only) on
130 > * {@link ChatState.primaryWorkingDirectory}. Ignored for forks (a chat whose
131 > * `source.kind` is `"fork"` inherits the source chat's primary).
132 > */
133 > primaryWorkingDirectory?: URI;
134 > }
135 >
136 > // ─── disposeChat ─────────────────────────────────────────────────────────────
137 >
138 > /**
139 > * Disposes a chat and cleans up server-side resources.
140 > *
141 > * @category Commands
142 > * @method disposeChat
143 > * @direction Client → Server
144 > * @messageType Request
145 > * @version 1
146 > */
147 > export interface DisposeChatParams extends BaseParams { }
src/vs/workbench/services/extensions/common/extensionDescriptionRegistry.ts 147 covered LOC · 41 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extensionDescriptionRegistry.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { ExtensionIdentifier, ExtensionIdentifierMap, ExtensionIdentifierSet, IExtensionDescription } from '../../../../platform/extensions/common/extensions.js';
7 > import { Emitter } from '../../../../base/common/event.js';
8 > import * as path from '../../../../base/common/path.js';
9 > import { Disposable, IDisposable, toDisposable } from '../../../../base/common/lifecycle.js';
10 > import { promiseWithResolvers } from '../../../../base/common/async.js';
11 >
12 > export class DeltaExtensionsResult {
13 > constructor(
14 public readonly versionId: number,
15 public readonly removedDueToLooping: IExtensionDescription[]
16 ) { }
18 >
19 > export interface IReadOnlyExtensionDescriptionRegistry {
20 > containsActivationEvent(activationEvent: string): boolean;
21 > containsExtension(extensionId: ExtensionIdentifier): boolean;
22 > getExtensionDescriptionsForActivationEvent(activationEvent: string): IExtensionDescription[];
23 > getAllExtensionDescriptions(): IExtensionDescription[];
24 > getExtensionDescription(extensionId: ExtensionIdentifier | string): IExtensionDescription | undefined;
25 > getExtensionDescriptionByUUID(uuid: string): IExtensionDescription | undefined;
26 > getExtensionDescriptionByIdOrUUID(extensionId: ExtensionIdentifier | string, uuid: string | undefined): IExtensionDescription | undefined;
27 > }
28 >
29 > export class ExtensionDescriptionRegistry extends Disposable implements IReadOnlyExtensionDescriptionRegistry {
30 >
31 > public static isHostExtension(extensionId: ExtensionIdentifier | string, myRegistry: ExtensionDescriptionRegistry, globalRegistry: ExtensionDescriptionRegistry): boolean {
32 > if (myRegistry.getExtensionDescription(extensionId)) {
33 > // I have this extension
34 > return false;
35 > }
36 > const extensionDescription = globalRegistry.getExtensionDescription(extensionId); extensionDescriptionRegistry.ts
37 > if (!extensionDescription) {
38 > // unknown extension extensionDescriptionRegistry.ts
39 > return false;
40 > }
41 > if ((extensionDescription.main || extensionDescription.browser) && extensionDescription.api === 'none') { extensionDescriptionRegistry.ts
43 > }
44 > return false; extensionDescriptionRegistry.ts
46 >
47 > private readonly _onDidChange = this._register(new Emitter<void>());
48 > public readonly onDidChange = this._onDidChange.event;
49 >
50 > private _versionId: number = 0;
51 > private _extensionDescriptions: IExtensionDescription[];
52 > private _extensionsMap!: ExtensionIdentifierMap<IExtensionDescription>;
53 > private _extensionsArr!: IExtensionDescription[];
54 > private _activationMap!: Map<string, IExtensionDescription[]>;
55 >
56 > constructor(
57 private readonly _activationEventsReader: IActivationEventsReader,
58 extensionDescriptions: IExtensionDescription[]
62 this._initialize();
63 }
65 > private _initialize(): void {
66 // Ensure extensions are stored in the order: builtin, user, under development
67 this._extensionDescriptions.sort(extensionCmp);
90 }
91 }
93 > public set(extensionDescriptions: IExtensionDescription[]): { versionId: number } {
94 this._extensionDescriptions = extensionDescriptions;
95 this._initialize();
100 };
101 }
103 > public deltaExtensions(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): DeltaExtensionsResult {
104 // It is possible that an extension is removed, only to be added again at a different version
105 // so we will first handle removals
118 return new DeltaExtensionsResult(this._versionId, looping);
119 }
121 > private static _findLoopingExtensions(extensionDescriptions: IExtensionDescription[]): IExtensionDescription[] {
122 const G = new class {
123
202 return nodes.map(id => descs.get(id)!);
203 }
205 > public containsActivationEvent(activationEvent: string): boolean {
206 return this._activationMap.has(activationEvent);
207 }
209 > public containsExtension(extensionId: ExtensionIdentifier): boolean {
210 return this._extensionsMap.has(extensionId);
211 }
213 > public getExtensionDescriptionsForActivationEvent(activationEvent: string): IExtensionDescription[] {
214 const extensions = this._activationMap.get(activationEvent);
215 return extensions ? extensions.slice(0) : [];
216 }
218 > public getAllExtensionDescriptions(): IExtensionDescription[] {
219 return this._extensionsArr.slice(0);
220 }
222 > public getSnapshot(): ExtensionDescriptionRegistrySnapshot {
223 return new ExtensionDescriptionRegistrySnapshot(
224 this._versionId,
226 );
227 }
229 > public getExtensionDescription(extensionId: ExtensionIdentifier | string): IExtensionDescription | undefined {
230 const extension = this._extensionsMap.get(extensionId);
231 return extension ? extension : undefined;
232 }
234 > public getExtensionDescriptionByUUID(uuid: string): IExtensionDescription | undefined {
235 for (const extensionDescription of this._extensionsArr) {
236 if (extensionDescription.uuid === uuid) {
240 return undefined;
241 }
243 > public getExtensionDescriptionByIdOrUUID(extensionId: ExtensionIdentifier | string, uuid: string | undefined): IExtensionDescription | undefined {
244 return (
245 this.getExtensionDescription(extensionId)
247 );
248 }
250 >
251 > export class ExtensionDescriptionRegistrySnapshot {
252 > constructor(
253 public readonly versionId: number,
254 public readonly extensions: readonly IExtensionDescription[]
255 ) { }
257 >
258 > export interface IActivationEventsReader {
259 > readActivationEvents(extensionDescription: IExtensionDescription): string[];
260 > }
261 >
262 > export class LockableExtensionDescriptionRegistry implements IReadOnlyExtensionDescriptionRegistry {
263 >
264 > private readonly _actual: ExtensionDescriptionRegistry;
265 > private readonly _lock = new Lock();
266 >
267 > constructor(activationEventsReader: IActivationEventsReader) {
268 this._actual = new ExtensionDescriptionRegistry(activationEventsReader, []);
269 }
271 > public async acquireLock(customerName: string): Promise<ExtensionDescriptionRegistryLock> {
272 const lock = await this._lock.acquire(customerName);
273 return new ExtensionDescriptionRegistryLock(this, lock);
274 }
276 > public deltaExtensions(acquiredLock: ExtensionDescriptionRegistryLock, toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): DeltaExtensionsResult {
277 if (!acquiredLock.isAcquiredFor(this)) {
278 throw new Error('Lock is not held');
280 return this._actual.deltaExtensions(toAdd, toRemove);
281 }
283 > public containsActivationEvent(activationEvent: string): boolean {
284 return this._actual.containsActivationEvent(activationEvent);
285 }
286 > public containsExtension(extensionId: ExtensionIdentifier): boolean { extensionDescriptionRegistry.ts
287 return this._actual.containsExtension(extensionId);
288 }
289 > public getExtensionDescriptionsForActivationEvent(activationEvent: string): IExtensionDescription[] { extensionDescriptionRegistry.ts
290 return this._actual.getExtensionDescriptionsForActivationEvent(activationEvent);
291 }
292 > public getAllExtensionDescriptions(): IExtensionDescription[] { extensionDescriptionRegistry.ts
293 return this._actual.getAllExtensionDescriptions();
294 }
295 > public getSnapshot(): ExtensionDescriptionRegistrySnapshot { extensionDescriptionRegistry.ts
296 return this._actual.getSnapshot();
297 }
298 > public getExtensionDescription(extensionId: ExtensionIdentifier | string): IExtensionDescription | undefined { extensionDescriptionRegistry.ts
299 return this._actual.getExtensionDescription(extensionId);
300 }
301 > public getExtensionDescriptionByUUID(uuid: string): IExtensionDescription | undefined { extensionDescriptionRegistry.ts
302 return this._actual.getExtensionDescriptionByUUID(uuid);
303 }
304 > public getExtensionDescriptionByIdOrUUID(extensionId: ExtensionIdentifier | string, uuid: string | undefined): IExtensionDescription | undefined { extensionDescriptionRegistry.ts
305 return this._actual.getExtensionDescriptionByIdOrUUID(extensionId, uuid);
306 }
308 >
309 > export class ExtensionDescriptionRegistryLock extends Disposable {
310 >
311 > private _isDisposed = false;
312 >
313 > constructor(
314 private readonly _registry: LockableExtensionDescriptionRegistry,
315 lock: IDisposable
318 this._register(lock);
319 }
321 > public isAcquiredFor(registry: LockableExtensionDescriptionRegistry): boolean {
322 return !this._isDisposed && this._registry === registry;
323 }
325 >
326 > class LockCustomer {
327 > public readonly promise: Promise<IDisposable>;
328 > private readonly _resolve: (value: IDisposable) => void;
329 >
330 > constructor(
331 public readonly name: string
332 ) {
335 this._resolve = withResolvers.resolve;
336 }
338 > resolve(value: IDisposable): void {
339 this._resolve(value);
340 }
342 >
343 class Lock {
344 private readonly _pendingCustomers: LockCustomer[] = [];
345 private _isLocked = false;
347 > public async acquire(customerName: string): Promise<IDisposable> {
348 const customer = new LockCustomer(customerName);
349 this._pendingCustomers.push(customer);
351 return customer.promise;
352 }
354 > private _advance(): void {
355 if (this._isLocked) {
356 // cannot advance yet
385 customer.resolve(toDisposable(releaseLock));
386 }
388 >
389 > const enum SortBucket {
390 > Builtin = 0,
391 > User = 1,
392 > Dev = 2
393 > }
394 >
395 > /**
396 > * Ensure that:
397 > * - first are builtin extensions
398 > * - second are user extensions
399 > * - third are extensions under development
400 > *
401 > * In each bucket, extensions must be sorted alphabetically by their folder name.
402 > */
403 function extensionCmp(a: IExtensionDescription, b: IExtensionDescription): number {
404 const aSortBucket = (a.isBuiltin ? SortBucket.Builtin : a.isUnderDevelopment ? SortBucket.Dev : SortBucket.User);
417 return 0;
418 }
420 function removeExtensions(arr: IExtensionDescription[], toRemove: ExtensionIdentifier[]): IExtensionDescription[] {
421 const toRemoveSet = new ExtensionIdentifierSet(toRemove);
src/vs/base/common/labels.ts 146 covered LOC · 12 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- labels.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { hasDriveLetter, toSlashes } from './extpath.js';
7 > import { posix, sep, win32 } from './path.js';
8 > import { isMacintosh, isWindows, OperatingSystem, OS } from './platform.js';
9 > import { extUri, extUriIgnorePathCase } from './resources.js';
10 > import { rtrim, startsWithIgnoreCase } from './strings.js';
11 > import { URI } from './uri.js';
12 >
13 > export interface IPathLabelFormatting {
14 >
15 > /**
16 > * The OS the path label is from to produce a label
17 > * that matches OS expectations.
18 > */
19 > readonly os: OperatingSystem;
20 >
21 > /**
22 > * Whether to add a `~` when the path is in the
23 > * user home directory.
24 > *
25 > * Note: this only applies to Linux, macOS but not
26 > * Windows.
27 > */
28 > readonly tildify?: IUserHomeProvider;
29 >
30 > /**
31 > * Whether to convert to a relative path if the path
32 > * is within any of the opened workspace folders.
33 > */
34 > readonly relative?: IRelativePathProvider;
35 > }
36 >
37 > export interface IRelativePathProvider {
38 >
39 > /**
40 > * Whether to not add a prefix when in multi-root workspace.
41 > */
42 > readonly noPrefix?: boolean;
43 >
44 > getWorkspace(): { folders: { uri: URI; name?: string }[] };
45 > getWorkspaceFolder(resource: URI): { uri: URI; name?: string } | null;
46 > }
47 >
48 > export interface IUserHomeProvider {
49 > userHome: URI;
50 > }
51 >
52 > export function getPathLabel(resource: URI, formatting: IPathLabelFormatting): string {
53 const { os, tildify: tildifier, relative: relatifier } = formatting;
54
93 return pathLib.normalize(normalizeDriveLetter(absolutePath, os === OperatingSystem.Windows));
94 }
95 > labels.ts
96 function getRelativePathLabel(resource: URI, relativePathProvider: IRelativePathProvider, os: OperatingSystem): string | undefined {
97 const pathLib = os === OperatingSystem.Windows ? win32 : posix;
137 return relativePathLabel;
138 }
139 > labels.ts
140 > export function normalizeDriveLetter(path: string, isWindowsOS: boolean = isWindows): string {
141 if (hasDriveLetter(path, isWindowsOS)) {
142 return path.charAt(0).toUpperCase() + path.slice(1);
145 return path;
146 }
147 > labels.ts
148 > let normalizedUserHomeCached: { original: string; normalized: string } = Object.create(null);
149 > export function tildify(path: string, userHome: string, os = OS): string {
150 if (os === OperatingSystem.Windows || !path || !userHome) {
151 return path; // unsupported on Windows
174 return path;
175 }
176 > labels.ts
177 > export function untildify(path: string, userHome: string): string {
178 return path.replace(/^~($|\/|\\)/, `${userHome}$1`);
179 }
180 > labels.ts
181 > /**
182 > * Shortens the paths but keeps them easy to distinguish.
183 > * Replaces not important parts with ellipsis.
184 > * Every shorten path matches only one original path and vice versa.
185 > *
186 > * Algorithm for shortening paths is as follows:
187 > * 1. For every path in list, find unique substring of that path.
188 > * 2. Unique substring along with ellipsis is shortened path of that path.
189 > * 3. To find unique substring of path, consider every segment of length from 1 to path.length of path from end of string
190 > * and if present segment is not substring to any other paths then present segment is unique path,
191 > * else check if it is not present as suffix of any other path and present segment is suffix of path itself,
192 > * if it is true take present segment as unique path.
193 > * 4. Apply ellipsis to unique segment according to whether segment is present at start/in-between/end of path.
194 > *
195 > * Example 1
196 > * 1. consider 2 paths i.e. ['a\\b\\c\\d', 'a\\f\\b\\c\\d']
197 > * 2. find unique path of first path,
198 > * a. 'd' is present in path2 and is suffix of path2, hence not unique of present path.
199 > * b. 'c' is present in path2 and 'c' is not suffix of present path, similarly for 'b' and 'a' also.
200 > * c. 'd\\c' is suffix of path2.
201 > * d. 'b\\c' is not suffix of present path.
202 > * e. 'a\\b' is not present in path2, hence unique path is 'a\\b...'.
203 > * 3. for path2, 'f' is not present in path1 hence unique is '...\\f\\...'.
204 > *
205 > * Example 2
206 > * 1. consider 2 paths i.e. ['a\\b', 'a\\b\\c'].
207 > * a. Even if 'b' is present in path2, as 'b' is suffix of path1 and is not suffix of path2, unique path will be '...\\b'.
208 > * 2. for path2, 'c' is not present in path1 hence unique path is '..\\c'.
209 > */
210 > const ellipsis = '\u2026';
211 > const unc = '\\\\';
212 > const urlSchemaRegexp = /^[^:/\\?#]+?:\/\//;
213 > const home = '~';
214 > export function shorten(paths: string[], defaultPathSeparator: string = sep): string[] {
215 const shortenedPaths: string[] = new Array(paths.length);
216
323 return shortenedPaths;
324 }
325 > labels.ts
326 > export interface ISeparator {
327 > label: string;
328 > }
329 >
330 > enum Type {
331 > TEXT,
332 > VARIABLE,
333 > SEPARATOR
334 > }
335 >
336 > interface ISegment {
337 > value: string;
338 > type: Type;
339 > }
340 >
341 > /**
342 > * Helper to insert values for specific template variables into the string. E.g. "this $(is) a $(template)" can be
343 > * passed to this function together with an object that maps "is" and "template" to strings to have them replaced.
344 > * @param value string to which template is applied
345 > * @param values the values of the templates to use
346 > */
347 > export function template(template: string, values: { [key: string]: string | ISeparator | undefined | null } = Object.create(null)): string {
348 const segments: ISegment[] = [];
349
409 }).map(segment => segment.value).join('');
410 }
411 > labels.ts
412 > /**
413 > * Handles mnemonics for menu items. Depending on OS:
414 > * - Windows: Supported via & character (replace && with &)
415 > * - Linux: Supported via & character (replace && with &)
416 > * - macOS: Unsupported (replace && with empty string)
417 > */
418 > export function mnemonicMenuLabel(label: string, forceDisableMnemonics?: boolean): string {
419 if (isMacintosh || forceDisableMnemonics) {
420 return label.replace(/\(&&\w\)|&&/g, '').replace(/&/g, isMacintosh ? '&' : '&&');
423 return label.replace(/&&|&/g, m => m === '&' ? '&&' : '&');
424 }
425 > labels.ts
426 > /**
427 > * Handles mnemonics for buttons. Depending on OS:
428 > * - Windows: Supported via & character (replace && with & and & with && for escaping)
429 > * - Linux: Supported via _ character (replace && with _)
430 > * - macOS: Unsupported (replace && with empty string)
431 > * When forceDisableMnemonics is set, returns just the label without mnemonics.
432 > */
433 > export function mnemonicButtonLabel(label: string, forceDisableMnemonics: true): string;
434 > export function mnemonicButtonLabel(label: string, forceDisableMnemonics?: false): { readonly withMnemonic: string; readonly withoutMnemonic: string };
435 > export function mnemonicButtonLabel(label: string, forceDisableMnemonics?: boolean): { readonly withMnemonic: string; readonly withoutMnemonic: string } | string {
436 const withoutMnemonic = label.replace(/\(&&\w\)|&&/g, '');
437
451 return { withMnemonic, withoutMnemonic };
452 }
453 > labels.ts
454 > export function unmnemonicLabel(label: string): string {
455 return label.replace(/&/g, '&&');
456 }
457 > labels.ts
458 > /**
459 > * Splits a recent label in name and parent path, supporting both '/' and '\' and workspace suffixes.
460 > * If the location is remote, the remote name is included in the name part.
461 > */
462 > export function splitRecentLabel(recentLabel: string): { name: string; parentPath: string } {
463 if (recentLabel.endsWith(']')) {
464 // label with workspace suffix
472 return splitName(recentLabel);
473 }
474 > labels.ts
475 function splitName(fullPath: string): { name: string; parentPath: string } {
476 const p = fullPath.indexOf('/') !== -1 ? posix : win32;
src/vs/workbench/services/extensions/common/extensionHostProtocol.ts 142 covered LOC · 3 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extensionHostProtocol.ts
2 > * Copyright (c) Microsoft 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 { URI, UriComponents, UriDto } from '../../../../base/common/uri.js';
8 > import { ExtensionIdentifier, IExtensionDescription } from '../../../../platform/extensions/common/extensions.js';
9 > import { ILoggerResource, LogLevel } from '../../../../platform/log/common/log.js';
10 > import { IRemoteConnectionData } from '../../../../platform/remote/common/remoteAuthorityResolver.js';
11 >
12 > export interface IExtensionDescriptionSnapshot {
13 > readonly versionId: number;
14 > readonly allExtensions: IExtensionDescription[];
15 > readonly activationEvents: { [extensionId: string]: string[] };
16 > readonly myExtensions: ExtensionIdentifier[];
17 > }
18 >
19 > export interface IExtensionDescriptionDelta {
20 > readonly versionId: number;
21 > readonly toRemove: ExtensionIdentifier[];
22 > readonly toAdd: IExtensionDescription[];
23 > readonly addActivationEvents: { [extensionId: string]: string[] };
24 > readonly myToRemove: ExtensionIdentifier[];
25 > readonly myToAdd: ExtensionIdentifier[];
26 > }
27 >
28 > export interface IExtensionHostInitData {
29 > version: string;
30 > quality: string | undefined;
31 > commit?: string;
32 > date?: string;
33 > /**
34 > * When set to `0`, no polling for the parent process still running will happen.
35 > */
36 > parentPid: number | 0;
37 > environment: IEnvironment;
38 > workspace?: IStaticWorkspaceData | null;
39 > extensions: IExtensionDescriptionSnapshot;
40 > nlsBaseUrl?: URI;
41 > telemetryInfo: {
42 > readonly sessionId: string;
43 > readonly machineId: string;
44 > readonly sqmId: string;
45 > readonly devDeviceId: string;
46 > readonly firstSessionDate: string;
47 > readonly msftInternal?: boolean;
48 > };
49 > remoteExtensionTips?: { readonly [remoteName: string]: unknown };
50 > virtualWorkspaceExtensionTips?: { readonly [remoteName: string]: unknown };
51 > logLevel: LogLevel;
52 > loggers: UriDto<ILoggerResource>[];
53 > logsLocation: URI;
54 > autoStart: boolean;
55 > remote: { isRemote: boolean; authority: string | undefined; connectionData: IRemoteConnectionData | null };
56 > consoleForward: { includeStack: boolean; logNative: boolean };
57 > uiKind: UIKind;
58 > messagePorts?: ReadonlyMap<string, MessagePortLike>;
59 > handle?: string;
60 > /**
61 > * The value of the `extensionEnabledApiProposalsFallback`-experiment: a comma-separated list of
62 > * `publisher.extension:proposalName` entries that are granted proposed API access even when the
63 > * extension has not declared the proposal. Only set on `stable` builds.
64 > */
65 > enabledApiProposalsFallback?: string;
66 > }
67 >
68 > export interface IEnvironment {
69 > isExtensionDevelopmentDebug: boolean;
70 > appName: string;
71 > appHost: string;
72 > appRoot?: URI;
73 > appLanguage: string;
74 > isExtensionTelemetryLoggingOnly: boolean;
75 > appUriScheme: string;
76 > isPortable?: boolean;
77 > extensionDevelopmentLocationURI?: URI[];
78 > extensionTestsLocationURI?: URI;
79 > globalStorageHome: URI;
80 > workspaceStorageHome: URI;
81 > useHostProxy?: boolean;
82 > skipWorkspaceStorageLock?: boolean;
83 > extensionLogLevel?: [string, LogLevel][];
84 > isSessionsWindow?: boolean;
85 > }
86 >
87 > export interface IStaticWorkspaceData {
88 > id: string;
89 > name: string;
90 > transient?: boolean;
91 > configuration?: UriComponents | null;
92 > isUntitled?: boolean | null;
93 > }
94 >
95 > export interface MessagePortLike {
96 > postMessage(message: unknown, transfer?: Transferable[]): void;
97 > addEventListener(type: 'message', listener: (e: MessageEvent<unknown>) => unknown): void;
98 > removeEventListener(type: 'message', listener: (e: MessageEvent<unknown>) => unknown): void;
99 > start(): void;
100 > }
101 >
102 > export enum UIKind {
103 > Desktop = 1,
104 > Web = 2
105 > }
106 >
107 > export const enum ExtensionHostExitCode {
108 > // nodejs uses codes 1-13 and exit codes >128 are signal exits
109 > VersionMismatch = 55,
110 > UnexpectedError = 81,
111 > }
112 >
113 > export interface IExtHostReadyMessage {
114 > type: 'VSCODE_EXTHOST_IPC_READY';
115 > }
116 >
117 > export interface IExtHostSocketMessage {
118 > type: 'VSCODE_EXTHOST_IPC_SOCKET';
119 > initialDataChunk: string;
120 > skipWebSocketFrames: boolean;
121 > permessageDeflate: boolean;
122 > inflateBytes: string;
123 > }
124 >
125 > export interface IExtHostReduceGraceTimeMessage {
126 > type: 'VSCODE_EXTHOST_IPC_REDUCE_GRACE_TIME';
127 > }
128 >
129 > export const enum MessageType {
130 > Initialized,
131 > Ready,
132 > Terminate
133 > }
134 >
135 > export function createMessageOfType(type: MessageType): VSBuffer {
136 const result = VSBuffer.alloc(1);
137
144 return result;
145 }
147 > export function isMessageOfType(message: VSBuffer, type: MessageType): boolean {
148 if (message.byteLength !== 1) {
149 return false;
157 }
158 }
160 > export const enum NativeLogMarkers {
161 > Start = 'START_NATIVE_LOG',
162 > End = 'END_NATIVE_LOG',
163 > }
src/vs/platform/markers/common/markers.ts 140 covered LOC · 8 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- markers.ts
2 > * Copyright (c) Microsoft 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 Severity from '../../../base/common/severity.js';
9 > import { URI } from '../../../base/common/uri.js';
10 > import { localize } from '../../../nls.js';
11 > import { createDecorator } from '../../instantiation/common/instantiation.js';
12 >
13 > export interface IMarkerReadOptions {
14 > owner?: string;
15 > resource?: URI;
16 > severities?: number;
17 > take?: number;
18 > ignoreResourceFilters?: boolean;
19 > }
20 >
21 > export interface IMarkerService {
22 > readonly _serviceBrand: undefined;
23 >
24 > getStatistics(): MarkerStatistics;
25 >
26 > changeOne(owner: string, resource: URI, markers: IMarkerData[]): void;
27 >
28 > changeAll(owner: string, data: IResourceMarker[]): void;
29 >
30 > remove(owner: string, resources: URI[]): void;
31 >
32 > read(filter?: IMarkerReadOptions): IMarker[];
33 >
34 > installResourceFilter(resource: URI, reason: string): IDisposable;
35 >
36 > readonly onMarkerChanged: Event<readonly URI[]>;
37 > }
38 >
39 > /**
40 > *
41 > */
42 > export interface IRelatedInformation {
43 > resource: URI;
44 > message: string;
45 > startLineNumber: number;
46 > startColumn: number;
47 > endLineNumber: number;
48 > endColumn: number;
49 > }
50 >
51 > export const enum MarkerTag {
52 > Unnecessary = 1,
53 > Deprecated = 2
54 > }
55 >
56 > export enum MarkerSeverity {
57 > Hint = 1,
58 > Info = 2,
59 > Warning = 4,
60 > Error = 8,
61 > }
62 >
63 > export namespace MarkerSeverity {
64 >
65 > export function compare(a: MarkerSeverity, b: MarkerSeverity): number {
66 return b - a;
67 }
68 > markers.ts
69 > const _displayStrings: { [value: number]: string } = Object.create(null);
70 > _displayStrings[MarkerSeverity.Error] = localize('sev.error', "Error");
71 > _displayStrings[MarkerSeverity.Warning] = localize('sev.warning', "Warning");
72 > _displayStrings[MarkerSeverity.Info] = localize('sev.info', "Info");
73 >
74 > export function toString(a: MarkerSeverity): string {
75 return _displayStrings[a] || '';
76 }
77 > markers.ts
78 > const _displayStringsPlural: { [value: number]: string } = Object.create(null);
79 > _displayStringsPlural[MarkerSeverity.Error] = localize('sev.errors', "Errors");
80 > _displayStringsPlural[MarkerSeverity.Warning] = localize('sev.warnings', "Warnings");
81 > _displayStringsPlural[MarkerSeverity.Info] = localize('sev.infos', "Infos");
82 >
83 > export function toStringPlural(a: MarkerSeverity): string {
84 return _displayStringsPlural[a] || '';
85 }
86 > markers.ts
87 > export function fromSeverity(severity: Severity): MarkerSeverity {
88 switch (severity) {
89 case Severity.Error: return MarkerSeverity.Error;
93 }
94 }
95 > markers.ts
96 > export function toSeverity(severity: MarkerSeverity): Severity {
97 switch (severity) {
98 case MarkerSeverity.Error: return Severity.Error;
102 }
103 }
104 > } markers.ts
105 >
106 > /**
107 > * A structure defining a problem/warning/etc.
108 > */
109 > export interface IMarkerData {
110 > code?: string | { value: string; target: URI };
111 > severity: MarkerSeverity;
112 > message: string;
113 > source?: string;
114 > startLineNumber: number;
115 > startColumn: number;
116 > endLineNumber: number;
117 > endColumn: number;
118 > modelVersionId?: number;
119 > relatedInformation?: IRelatedInformation[];
120 > tags?: MarkerTag[];
121 > origin?: string | undefined;
122 > }
123 >
124 > export interface IResourceMarker {
125 > resource: URI;
126 > marker: IMarkerData;
127 > }
128 >
129 > export interface IMarker {
130 > owner: string;
131 > resource: URI;
132 > severity: MarkerSeverity;
133 > code?: string | { value: string; target: URI };
134 > message: string;
135 > source?: string;
136 > startLineNumber: number;
137 > startColumn: number;
138 > endLineNumber: number;
139 > endColumn: number;
140 > modelVersionId?: number;
141 > relatedInformation?: IRelatedInformation[];
142 > tags?: MarkerTag[];
143 > origin?: string | undefined;
144 > }
145 >
146 > export interface MarkerStatistics {
147 > errors: number;
148 > warnings: number;
149 > infos: number;
150 > unknowns: number;
151 > }
152 >
153 > export namespace IMarkerData {
154 > const emptyString = '';
155 > export function makeKey(markerData: IMarkerData): string {
156 return makeKeyOptionalMessage(markerData, true);
157 }
158 > markers.ts
159 > export function makeKeyOptionalMessage(markerData: IMarkerData, useMessage: boolean): string {
160 const result: string[] = [emptyString];
161 if (markerData.source) {
209 return result.join('¦');
210 }
211 > } markers.ts
212 >
213 > export const IMarkerService = createDecorator<IMarkerService>('markerService');
src/vs/platform/opener/common/opener.ts 139 covered LOC · 2 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- opener.ts
2 > * Copyright (c) Microsoft 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 { IDisposable } from '../../../base/common/lifecycle.js';
8 > import { URI } from '../../../base/common/uri.js';
9 > import { IEditorOptions, ITextEditorSelection } from '../../editor/common/editor.js';
10 > import { createDecorator } from '../../instantiation/common/instantiation.js';
11 >
12 > export const IOpenerService = createDecorator<IOpenerService>('openerService');
13 >
14 > export type OpenInternalOptions = {
15 >
16 > /**
17 > * Signals that the intent is to open an editor to the side
18 > * of the currently active editor.
19 > */
20 > readonly openToSide?: boolean;
21 >
22 > /**
23 > * Extra editor options to apply in case an editor is used to open.
24 > */
25 > readonly editorOptions?: IEditorOptions;
26 >
27 > /**
28 > * Signals that the editor to open was triggered through a user
29 > * action, such as keyboard or mouse usage.
30 > */
31 > readonly fromUserGesture?: boolean;
32 >
33 > /**
34 > * Allow command links to be handled.
35 > *
36 > * If this is an array, then only the commands included in the array can be run.
37 > */
38 > readonly allowCommands?: boolean | readonly string[];
39 > };
40 >
41 > export type OpenExternalOptions = {
42 > readonly openExternal?: boolean;
43 > readonly allowTunneling?: boolean;
44 > readonly allowContributedOpeners?: boolean | string;
45 > readonly fromWorkspace?: boolean;
46 > readonly skipValidation?: boolean;
47 > };
48 >
49 > export type OpenOptions = OpenInternalOptions & OpenExternalOptions;
50 >
51 > export type ResolveExternalUriOptions = { readonly allowTunneling?: boolean };
52 >
53 > export interface IResolvedExternalUri extends IDisposable {
54 > resolved: URI;
55 > }
56 >
57 > export interface IOpener {
58 > open(resource: URI | string, options?: OpenInternalOptions | OpenExternalOptions): Promise<boolean>;
59 > }
60 >
61 > export interface IExternalOpener {
62 > openExternal(href: string, ctx: { sourceUri: URI; preferredOpenerId?: string }, token: CancellationToken): Promise<boolean>;
63 > dispose?(): void;
64 > }
65 >
66 > export interface IValidator {
67 > shouldOpen(resource: URI | string, openOptions?: OpenOptions): Promise<boolean>;
68 > }
69 >
70 > export interface IExternalUriResolver {
71 > resolveExternalUri(resource: URI, options?: OpenOptions): Promise<{ resolved: URI; dispose(): void } | undefined>;
72 > }
73 >
74 > export interface IOpenerService {
75 >
76 > readonly _serviceBrand: undefined;
77 >
78 > /**
79 > * Register a participant that can handle the open() call.
80 > */
81 > registerOpener(opener: IOpener): IDisposable;
82 >
83 > /**
84 > * Register a participant that can validate if the URI resource be opened.
85 > * Validators are run before openers.
86 > */
87 > registerValidator(validator: IValidator): IDisposable;
88 >
89 > /**
90 > * Register a participant that can resolve an external URI resource to be opened.
91 > */
92 > registerExternalUriResolver(resolver: IExternalUriResolver): IDisposable;
93 >
94 > /**
95 > * Sets the handler for opening externally. If not provided,
96 > * a default handler will be used.
97 > */
98 > setDefaultExternalOpener(opener: IExternalOpener): void;
99 >
100 > /**
101 > * Registers a new opener external resources openers.
102 > */
103 > registerExternalOpener(opener: IExternalOpener): IDisposable;
104 >
105 > /**
106 > * Opens a resource, like a webaddress, a document uri, or executes command.
107 > *
108 > * @param resource A resource
109 > * @return A promise that resolves when the opening is done.
110 > */
111 > open(resource: URI | string, options?: OpenInternalOptions | OpenExternalOptions): Promise<boolean>;
112 >
113 > /**
114 > * Resolve a resource to its external form.
115 > * @throws whenever resolvers couldn't resolve this resource externally.
116 > */
117 > resolveExternalUri(resource: URI, options?: ResolveExternalUriOptions): Promise<IResolvedExternalUri>;
118 > }
119 >
120 > /**
121 > * Encodes selection into the `URI`.
122 > *
123 > * IMPORTANT: you MUST use `extractSelection` to separate the selection
124 > * again from the original `URI` before passing the `URI` into any
125 > * component that is not aware of selections.
126 > */
127 > export function withSelection(uri: URI, selection: ITextEditorSelection): URI {
128 return uri.with({ fragment: `${selection.startLineNumber},${selection.startColumn}${selection.endLineNumber ? `-${selection.endLineNumber}${selection.endColumn ? `,${selection.endColumn}` : ''}` : ''}` });
129 }
130 > opener.ts
131 > /**
132 > * file:///some/file.js#73
133 > * file:///some/file.js#L73
134 > * file:///some/file.js#73,84
135 > * file:///some/file.js#L73,84
136 > * file:///some/file.js#73-83
137 > * file:///some/file.js#L73-L83
138 > * file:///some/file.js#73,84-83,52
139 > * file:///some/file.js#L73,84-L83,52
140 > */
141 > export function extractSelection(uri: URI): { selection: ITextEditorSelection | undefined; uri: URI } {
142 let selection: ITextEditorSelection | undefined = undefined;
143 const match = /^L?(\d+)(?:,(\d+))?(-L?(\d+)(?:,(\d+))?)?/.exec(uri.fragment);
src/vs/workbench/services/userDataProfile/common/userDataProfile.ts 139 covered LOC · 4 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- userDataProfile.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { isUndefined } from '../../../../base/common/types.js';
7 > import { Event } from '../../../../base/common/event.js';
8 > import { localize, localize2 } from '../../../../nls.js';
9 > import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
10 > import { IUserDataProfile, IUserDataProfileOptions, IUserDataProfileUpdateOptions, ProfileResourceType, ProfileResourceTypeFlags } from '../../../../platform/userDataProfile/common/userDataProfile.js';
11 > import { RawContextKey } from '../../../../platform/contextkey/common/contextkey.js';
12 > import { URI } from '../../../../base/common/uri.js';
13 > import { registerIcon } from '../../../../platform/theme/common/iconRegistry.js';
14 > import { Codicon } from '../../../../base/common/codicons.js';
15 > import { ITreeItem, ITreeItemLabel } from '../../../common/views.js';
16 > import { CancellationToken } from '../../../../base/common/cancellation.js';
17 > import { IDisposable } from '../../../../base/common/lifecycle.js';
18 > import { IProductService } from '../../../../platform/product/common/productService.js';
19 >
20 > export interface DidChangeUserDataProfileEvent {
21 > readonly previous: IUserDataProfile;
22 > readonly profile: IUserDataProfile;
23 > join(promise: Promise<void>): void;
24 > }
25 >
26 > export const IUserDataProfileService = createDecorator<IUserDataProfileService>('IUserDataProfileService');
27 > export interface IUserDataProfileService {
28 > readonly _serviceBrand: undefined;
29 > readonly currentProfile: IUserDataProfile;
30 > readonly onDidChangeCurrentProfile: Event<DidChangeUserDataProfileEvent>;
31 > updateCurrentProfile(currentProfile: IUserDataProfile): Promise<void>;
32 > }
33 >
34 > export interface IProfileTemplateInfo {
35 > readonly name: string;
36 > readonly url: string;
37 > }
38 >
39 > export const IUserDataProfileManagementService = createDecorator<IUserDataProfileManagementService>('IUserDataProfileManagementService');
40 > export interface IUserDataProfileManagementService {
41 > readonly _serviceBrand: undefined;
42 >
43 > createProfile(name: string, options?: IUserDataProfileOptions): Promise<IUserDataProfile>;
44 > createAndEnterProfile(name: string, options?: IUserDataProfileOptions): Promise<IUserDataProfile>;
45 > createAndEnterTransientProfile(): Promise<IUserDataProfile>;
46 > removeProfile(profile: IUserDataProfile): Promise<void>;
47 > updateProfile(profile: IUserDataProfile, updateOptions: IUserDataProfileUpdateOptions): Promise<IUserDataProfile>;
48 > switchProfile(profile: IUserDataProfile): Promise<void>;
49 > getBuiltinProfileTemplates(): Promise<IProfileTemplateInfo[]>;
50 > getDefaultProfileToUse(): IUserDataProfile;
51 > }
52 >
53 > export interface IUserDataProfileTemplate {
54 > readonly name: string;
55 > readonly icon?: string;
56 > readonly settings?: string;
57 > readonly keybindings?: string;
58 > readonly tasks?: string;
59 > readonly snippets?: string;
60 > readonly globalState?: string;
61 > readonly extensions?: string;
62 > readonly mcp?: string;
63 > }
64 >
65 > export function isUserDataProfileTemplate(thing: unknown): thing is IUserDataProfileTemplate {
66 const candidate = thing as IUserDataProfileTemplate | undefined;
67
72 && (isUndefined(candidate.mcp) || typeof candidate.mcp === 'string'));
73 }
75 > export const PROFILE_URL_AUTHORITY = 'profile';
76 > export function toUserDataProfileUri(path: string, productService: IProductService): URI {
77 return URI.from({
78 scheme: productService.urlProtocol,
81 });
82 }
84 > export const PROFILE_URL_AUTHORITY_PREFIX = 'profile-';
85 > export function isProfileURL(uri: URI): boolean {
86 return uri.authority === PROFILE_URL_AUTHORITY || new RegExp(`^${PROFILE_URL_AUTHORITY_PREFIX}`).test(uri.authority);
87 }
89 > export interface IUserDataProfileCreateOptions extends IUserDataProfileOptions {
90 > readonly name?: string;
91 > readonly resourceTypeFlags?: ProfileResourceTypeFlags;
92 > }
93 >
94 > export interface IProfileImportOptions extends IUserDataProfileCreateOptions {
95 > readonly name?: string;
96 > readonly icon?: string;
97 > readonly mode?: 'apply';
98 > }
99 >
100 > export const IUserDataProfileImportExportService = createDecorator<IUserDataProfileImportExportService>('IUserDataProfileImportExportService');
101 > export interface IUserDataProfileImportExportService {
102 > readonly _serviceBrand: undefined;
103 >
104 > registerProfileContentHandler(id: string, profileContentHandler: IUserDataProfileContentHandler): IDisposable;
105 > unregisterProfileContentHandler(id: string): void;
106 >
107 > resolveProfileTemplate(uri: URI): Promise<IUserDataProfileTemplate | null>;
108 > exportProfile(profile: IUserDataProfile, exportFlags?: ProfileResourceTypeFlags): Promise<void>;
109 > createFromProfile(from: IUserDataProfile, options: IUserDataProfileCreateOptions, token: CancellationToken): Promise<IUserDataProfile | undefined>;
110 > createProfileFromTemplate(profileTemplate: IUserDataProfileTemplate, options: IUserDataProfileCreateOptions, token: CancellationToken): Promise<IUserDataProfile | undefined>;
111 > createTroubleshootProfile(): Promise<void>;
112 > }
113 >
114 > export interface IProfileResourceInitializer {
115 > initialize(content: string): Promise<void>;
116 > }
117 >
118 > export interface IProfileResource {
119 > getContent(profile: IUserDataProfile): Promise<string>;
120 > apply(content: string, profile: IUserDataProfile): Promise<void>;
121 > }
122 >
123 > export interface IProfileResourceTreeItem extends ITreeItem {
124 > readonly type: ProfileResourceType;
125 > readonly label: ITreeItemLabel;
126 > isFromDefaultProfile(): boolean;
127 > getChildren(): Promise<IProfileResourceChildTreeItem[] | undefined>;
128 > getContent(): Promise<string>;
129 > }
130 >
131 > export interface IProfileResourceChildTreeItem extends ITreeItem {
132 > parent: IProfileResourceTreeItem;
133 > }
134 >
135 > export interface ISaveProfileResult {
136 > readonly id: string;
137 > readonly link: URI;
138 > }
139 >
140 > export interface IUserDataProfileContentHandler {
141 > readonly name: string;
142 > readonly description?: string;
143 > readonly extensionId?: string;
144 > saveProfile(name: string, content: string, token: CancellationToken): Promise<ISaveProfileResult | null>;
145 > readProfile(idOrUri: string | URI, token: CancellationToken): Promise<string | null>;
146 > }
147 >
148 > export const defaultUserDataProfileIcon = registerIcon('defaultProfile-icon', Codicon.settings, localize('defaultProfileIcon', 'Icon for Default Profile.'));
149 >
150 > export const PROFILES_TITLE = localize2('profiles', 'Profiles');
151 > export const PROFILES_CATEGORY = { ...PROFILES_TITLE };
152 > export const PROFILE_EXTENSION = 'code-profile';
153 > export const PROFILE_FILTER = [{ name: localize('profile', "Profile"), extensions: [PROFILE_EXTENSION] }];
154 > export const CURRENT_PROFILE_CONTEXT = new RawContextKey<string>('currentProfile', '');
155 > export const HAS_PROFILES_CONTEXT = new RawContextKey<boolean>('hasProfiles', false);
src/vs/platform/remote/common/remoteAuthorityResolver.ts 135 covered LOC · 11 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- remoteAuthorityResolver.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { ErrorNoTelemetry } from '../../../base/common/errors.js';
7 > import { Event } from '../../../base/common/event.js';
8 > import { URI } from '../../../base/common/uri.js';
9 > import { createDecorator } from '../../instantiation/common/instantiation.js';
10 >
11 > export const IRemoteAuthorityResolverService = createDecorator<IRemoteAuthorityResolverService>('remoteAuthorityResolverService');
12 >
13 > export const enum RemoteConnectionType {
14 > WebSocket,
15 > Managed
16 > }
17 >
18 > export class ManagedRemoteConnection {
19 > public readonly type = RemoteConnectionType.Managed;
20 >
21 > constructor(
22 public readonly id: number
23 ) { }
25 > public toString(): string {
26 return `Managed(${this.id})`;
27 }
29 >
30 > export class WebSocketRemoteConnection {
31 > public readonly type = RemoteConnectionType.WebSocket;
32 >
33 > constructor(
34 public readonly host: string,
35 public readonly port: number,
36 ) { }
38 > public toString(): string {
39 return `WebSocket(${this.host}:${this.port})`;
40 }
42 >
43 > export type RemoteConnection = WebSocketRemoteConnection | ManagedRemoteConnection;
44 >
45 > export type RemoteConnectionOfType<T extends RemoteConnectionType> = RemoteConnection & { type: T };
46 >
47 > export interface ResolvedAuthority {
48 > readonly authority: string;
49 > readonly connectTo: RemoteConnection;
50 > readonly connectionToken: string | undefined;
51 > }
52 >
53 > export interface ResolvedOptions {
54 > readonly extensionHostEnv?: { [key: string]: string | null };
55 > readonly isTrusted?: boolean;
56 > readonly authenticationSession?: { id: string; providerId: string };
57 > }
58 >
59 > export interface TunnelDescription {
60 > remoteAddress: { port: number; host: string };
61 > localAddress: { port: number; host: string } | string;
62 > privacy?: string;
63 > protocol?: string;
64 > }
65 > export interface TunnelPrivacy {
66 > themeIcon: string;
67 > id: string;
68 > label: string;
69 > }
70 > export interface TunnelInformation {
71 > environmentTunnels?: TunnelDescription[];
72 > features?: {
73 > elevation: boolean;
74 > public?: boolean;
75 > privacyOptions: TunnelPrivacy[];
76 > protocol: boolean;
77 > };
78 > }
79 >
80 > export interface ResolverResult {
81 > authority: ResolvedAuthority;
82 > options?: ResolvedOptions;
83 > tunnelInformation?: TunnelInformation;
84 > }
85 >
86 > export interface IRemoteConnectionData {
87 > connectTo: RemoteConnection;
88 > connectionToken: string | undefined;
89 > }
90 >
91 > export enum RemoteAuthorityResolverErrorCode {
92 > Unknown = 'Unknown',
93 > NotAvailable = 'NotAvailable',
94 > TemporarilyNotAvailable = 'TemporarilyNotAvailable',
95 > NoResolverFound = 'NoResolverFound',
96 > InvalidAuthority = 'InvalidAuthority'
97 > }
98 >
99 > export class RemoteAuthorityResolverError extends ErrorNoTelemetry {
100 >
101 > public static isNotAvailable(err: any): boolean {
102 return (err instanceof RemoteAuthorityResolverError) && err._code === RemoteAuthorityResolverErrorCode.NotAvailable;
103 }
105 > public static isTemporarilyNotAvailable(err: any): boolean {
106 return (err instanceof RemoteAuthorityResolverError) && err._code === RemoteAuthorityResolverErrorCode.TemporarilyNotAvailable;
107 }
109 > public static isNoResolverFound(err: any): err is RemoteAuthorityResolverError {
110 return (err instanceof RemoteAuthorityResolverError) && err._code === RemoteAuthorityResolverErrorCode.NoResolverFound;
111 }
113 > public static isInvalidAuthority(err: any): boolean {
114 return (err instanceof RemoteAuthorityResolverError) && err._code === RemoteAuthorityResolverErrorCode.InvalidAuthority;
115 }
117 > public static isHandled(err: any): boolean {
118 return (err instanceof RemoteAuthorityResolverError) && err.isHandled;
119 }
121 > public readonly _message: string | undefined;
122 > public readonly _code: RemoteAuthorityResolverErrorCode;
123 > public readonly _detail: unknown;
124 >
125 > public isHandled: boolean;
126 >
127 > constructor(message?: string, code: RemoteAuthorityResolverErrorCode = RemoteAuthorityResolverErrorCode.Unknown, detail?: unknown) {
128 super(message);
129
138 Object.setPrototypeOf(this, RemoteAuthorityResolverError.prototype);
139 }
141 >
142 > export interface IRemoteAuthorityResolverService {
143 >
144 > readonly _serviceBrand: undefined;
145 >
146 > readonly onDidChangeConnectionData: Event<void>;
147 >
148 > resolveAuthority(authority: string): Promise<ResolverResult>;
149 > getConnectionData(authority: string): IRemoteConnectionData | null;
150 > /**
151 > * Get the canonical URI for a `vscode-remote://` URI.
152 > *
153 > * **NOTE**: This can throw e.g. in cases where there is no resolver installed for the specific remote authority.
154 > *
155 > * @param uri The `vscode-remote://` URI
156 > */
157 > getCanonicalURI(uri: URI): Promise<URI>;
158 >
159 > _clearResolvedAuthority(authority: string): void;
160 > _setResolvedAuthority(resolvedAuthority: ResolvedAuthority, resolvedOptions?: ResolvedOptions): void;
161 > _setResolvedAuthorityError(authority: string, err: any): void;
162 > _setAuthorityConnectionToken(authority: string, connectionToken: string): void;
163 > _setCanonicalURIProvider(provider: (uri: URI) => Promise<URI>): void;
164 > }
165 >
166 > export function getRemoteAuthorityPrefix(remoteAuthority: string): string {
167 const plusIndex = remoteAuthority.indexOf('+');
168 if (plusIndex === -1) {
src/vs/workbench/contrib/chat/common/promptSyntax/promptTypes.ts 131 covered LOC · 4 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- promptTypes.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { LanguageSelector } from '../../../../../editor/common/languageSelector.js';
7 > import { localize } from '../../../../../nls.js';
8 >
9 > /**
10 > * Documentation link for the reusable prompts feature.
11 > */
12 > export const PROMPT_DOCUMENTATION_URL = 'https://aka.ms/vscode-ghcp-prompt-snippets';
13 > export const INSTRUCTIONS_DOCUMENTATION_URL = 'https://aka.ms/vscode-ghcp-custom-instructions';
14 > export const AGENT_DOCUMENTATION_URL = 'https://aka.ms/vscode-ghcp-custom-chat-modes'; // todo
15 > export const SKILL_DOCUMENTATION_URL = 'https://aka.ms/vscode-agent-skills';
16 > // TODO: update link when available
17 > export const HOOK_DOCUMENTATION_URL = 'https://aka.ms/vscode-chat-hooks';
18 >
19 > /**
20 > * Language ID for the reusable prompt syntax.
21 > */
22 > export const PROMPT_LANGUAGE_ID = 'prompt';
23 >
24 > /**
25 > * Language ID for instructions syntax.
26 > */
27 > export const INSTRUCTIONS_LANGUAGE_ID = 'instructions';
28 >
29 > /**
30 > * Language ID for agent syntax.
31 > */
32 > export const AGENT_LANGUAGE_ID = 'chatagent';
33 >
34 > /**
35 > * Language ID for skill syntax.
36 > */
37 > export const SKILL_LANGUAGE_ID = 'skill';
38 >
39 > /**
40 > * Prompt and instructions files language selector.
41 > */
42 > export const ALL_PROMPTS_LANGUAGE_SELECTOR: LanguageSelector = [PROMPT_LANGUAGE_ID, INSTRUCTIONS_LANGUAGE_ID, AGENT_LANGUAGE_ID, SKILL_LANGUAGE_ID];
43 >
44 > /**
45 > * Configuration key for enabling the agent debug log feature.
46 > */
47 > export const AGENT_DEBUG_LOG_ENABLED_SETTING = 'github.copilot.chat.agentDebugLog.enabled';
48 >
49 > /**
50 > * Configuration key for enabling file logging for the agent debug log.
51 > */
52 > export const AGENT_DEBUG_LOG_FILE_LOGGING_ENABLED_SETTING = 'github.copilot.chat.agentDebugLog.fileLogging.enabled';
53 >
54 > /**
55 > * Configuration key for enabling agent debug logging for agent host (Copilot CLI) sessions.
56 > * Registered in core (see `chat.shared.contribution.ts`) since only core consumes it.
57 > */
58 > export const AgentHostAgentDebugLogEnabledSettingId = 'chat.agentHost.agentDebugLog.enabled';
59 >
60 > /**
61 > * Configuration key for the maximum number of debug events kept in memory for
62 > * agent host (Copilot CLI) sessions. Registered in core (see
63 > * `chat.shared.contribution.ts`) since only core consumes it.
64 > */
65 > export const AgentHostAgentDebugLogMaxEventsSettingId = 'chat.agentHost.agentDebugLog.maxEventsInMemory';
66 >
67 > /**
68 > * The name of the troubleshoot slash command / skill.
69 > */
70 > export const TROUBLESHOOT_COMMAND_NAME = 'troubleshoot';
71 >
72 > /**
73 > * URI scheme used by the Copilot extension for built-in skills.
74 > */
75 > export const COPILOT_SKILL_URI_SCHEME = 'copilot-skill';
76 >
77 > /**
78 > * Path fragment that identifies the troubleshoot skill in a URI.
79 > */
80 > export const TROUBLESHOOT_SKILL_PATH = 'troubleshoot/SKILL.md';
81 >
82 > /**
83 > * The language id for a prompts type.
84 > */
85 > export function getLanguageIdForPromptsType(type: PromptsType): string {
86 switch (type) {
87 case PromptsType.prompt:
100 }
101 }
103 > export function getPromptsTypeForLanguageId(languageId: string): PromptsType | undefined {
104 switch (languageId) {
105 case PROMPT_LANGUAGE_ID:
116 }
117 }
119 >
120 > /**
121 > * What the prompt is used for.
122 > */
123 > export enum PromptsType {
124 > instructions = 'instructions',
125 > prompt = 'prompt',
126 > agent = 'agent',
127 > skill = 'skill',
128 > hook = 'hook'
129 > }
130 > export function isValidPromptType(type: string): type is PromptsType {
131 return Object.values(PromptsType).includes(type as PromptsType);
132 }
134 > export enum Target {
135 > VSCode = 'vscode',
136 > GitHubCopilot = 'github-copilot',
137 > Claude = 'claude',
138 > Undefined = 'undefined',
139 > }
140 >
141 > /**
142 > * Tracks where prompt files originate from.
143 > */
144 > export enum PromptFileSource {
145 > GitHubWorkspace = 'github-workspace',
146 > CopilotPersonal = 'copilot-personal',
147 > ClaudePersonal = 'claude-personal',
148 > ClaudeWorkspace = 'claude-workspace',
149 > ClaudeWorkspaceLocal = 'claude-workspace-local',
150 > AgentsWorkspace = 'agents-workspace',
151 > AgentsPersonal = 'agents-personal',
152 > ConfigWorkspace = 'config-workspace',
153 > ConfigPersonal = 'config-personal',
154 > UserData = 'user-data',
155 > ExtensionContribution = 'extension-contribution',
156 > ExtensionAPI = 'extension-api',
157 > Plugin = 'plugin',
158 > }
159 >
160 > /**
161 > * Returns a human-readable description for a prompt file source.
162 > */
163 > export function getSourceDescription(source: PromptFileSource): string | undefined {
164 switch (source) {
165 case PromptFileSource.AgentsWorkspace:
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/platform/agentHost/common/agentHostConnectionsService.ts 126 covered LOC · 1 range

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- notebooks.ts
2 > * Copyright (c) Microsoft 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 * as vscode from 'vscode';
7 > import { es5ClassCompat } from './es5ClassCompat.js';
8 > import { illegalArgument } from '../../../../base/common/errors.js';
9 > import { Mimes, normalizeMimeType, isTextStreamMime } from '../../../../base/common/mime.js';
10 > import { generateUuid } from '../../../../base/common/uuid.js';
11 >
12 > export enum NotebookCellKind {
13 > Markup = 1,
14 > Code = 2
15 > }
16 >
17 > export class NotebookRange {
18 > static isNotebookRange(thing: unknown): thing is vscode.NotebookRange {
19 if (thing instanceof NotebookRange) {
20 return true;
26 && typeof (<NotebookRange>thing).end === 'number';
27 }
29 > private _start: number;
30 > private _end: number;
31 >
32 > get start() {
33 return this._start;
34 }
36 > get end() {
37 return this._end;
38 }
40 > get isEmpty(): boolean {
41 return this._start === this._end;
42 }
44 > constructor(start: number, end: number) {
45 if (start < 0) {
46 throw illegalArgument('start must be positive');
57 }
58 }
60 > with(change: { start?: number; end?: number }): NotebookRange {
61 let start = this._start;
62 let end = this._end;
73 return new NotebookRange(start, end);
74 }
75 > } notebooks.ts
76 >
77 > export class NotebookCellData {
78 >
79 > static validate(data: NotebookCellData): void {
80 if (typeof data.kind !== 'number') {
81 throw new Error('NotebookCellData MUST have \'kind\' property');
88 }
89 }
91 > static isNotebookCellDataArray(value: unknown): value is vscode.NotebookCellData[] {
92 return Array.isArray(value) && (<unknown[]>value).every(elem => NotebookCellData.isNotebookCellData(elem));
93 }
95 > static isNotebookCellData(value: unknown): value is vscode.NotebookCellData {
96 // return value instanceof NotebookCellData;
97 return true;
98 }
100 > kind: NotebookCellKind;
101 > value: string;
102 > languageId: string;
103 > mime?: string;
104 > outputs?: vscode.NotebookCellOutput[];
105 > metadata?: Record<string, unknown>;
106 > executionSummary?: vscode.NotebookCellExecutionSummary;
107 >
108 > constructor(kind: NotebookCellKind, value: string, languageId: string, mime?: string, outputs?: vscode.NotebookCellOutput[], metadata?: Record<string, unknown>, executionSummary?: vscode.NotebookCellExecutionSummary) {
109 this.kind = kind;
110 this.value = value;
117 NotebookCellData.validate(this);
118 }
119 > } notebooks.ts
120 >
121 > export class NotebookData {
122 >
123 > cells: NotebookCellData[];
124 > metadata?: { [key: string]: unknown };
125 >
126 > constructor(cells: NotebookCellData[]) {
127 this.cells = cells;
128 }
129 > } notebooks.ts
130 >
131 > @es5ClassCompat
132 > export class NotebookEdit implements vscode.NotebookEdit {
133 >
134 > static isNotebookCellEdit(thing: unknown): thing is NotebookEdit {
135 if (thing instanceof NotebookEdit) {
136 return true;
142 && Array.isArray((<NotebookEdit>thing).newCells);
143 }
144 > notebooks.ts
145 > static replaceCells(range: NotebookRange, newCells: NotebookCellData[]): NotebookEdit {
146 return new NotebookEdit(range, newCells);
147 }
148 > notebooks.ts
149 > static insertCells(index: number, newCells: vscode.NotebookCellData[]): vscode.NotebookEdit {
150 return new NotebookEdit(new NotebookRange(index, index), newCells);
151 }
152 > notebooks.ts
153 > static deleteCells(range: NotebookRange): NotebookEdit {
154 return new NotebookEdit(range, []);
155 }
156 > notebooks.ts
157 > static updateCellMetadata(index: number, newMetadata: { [key: string]: unknown }): NotebookEdit {
158 const edit = new NotebookEdit(new NotebookRange(index, index), []);
159 edit.newCellMetadata = newMetadata;
160 return edit;
161 }
162 > notebooks.ts
163 > static updateNotebookMetadata(newMetadata: { [key: string]: unknown }): NotebookEdit {
164 const edit = new NotebookEdit(new NotebookRange(0, 0), []);
165 edit.newNotebookMetadata = newMetadata;
166 return edit;
167 }
168 > notebooks.ts
169 > range: NotebookRange;
170 > newCells: NotebookCellData[];
171 > newCellMetadata?: { [key: string]: unknown };
172 > newNotebookMetadata?: { [key: string]: unknown };
173 >
174 > constructor(range: NotebookRange, newCells: NotebookCellData[]) {
175 this.range = range;
176 this.newCells = newCells;
177 }
178 > } notebooks.ts
179 >
180 > export class NotebookCellOutputItem {
181 >
182 > static isNotebookCellOutputItem(obj: unknown): obj is vscode.NotebookCellOutputItem {
183 > if (obj instanceof NotebookCellOutputItem) {
184 > return true;
185 > }
186 > if (!obj) {
187 > return false;
188 > }
189 > return typeof (<vscode.NotebookCellOutputItem>obj).mime === 'string'
190 > && (<vscode.NotebookCellOutputItem>obj).data instanceof Uint8Array;
191 > }
192 >
193 > static error(err: Error | { name: string; message?: string; stack?: string }): NotebookCellOutputItem {
194 const obj = {
195 name: err.name,
199 return NotebookCellOutputItem.json(obj, 'application/vnd.code.notebook.error');
200 }
201 > notebooks.ts
202 > static stdout(value: string): NotebookCellOutputItem {
203 return NotebookCellOutputItem.text(value, 'application/vnd.code.notebook.stdout');
204 }
205 > notebooks.ts
206 > static stderr(value: string): NotebookCellOutputItem {
207 return NotebookCellOutputItem.text(value, 'application/vnd.code.notebook.stderr');
208 }
209 > notebooks.ts
210 > static bytes(value: Uint8Array, mime: string = 'application/octet-stream'): NotebookCellOutputItem {
211 return new NotebookCellOutputItem(value, mime);
212 }
213 > notebooks.ts
214 > static #encoder = new TextEncoder();
215 >
216 > static text(value: string, mime: string = Mimes.text): NotebookCellOutputItem {
217 const bytes = NotebookCellOutputItem.#encoder.encode(String(value));
218 return new NotebookCellOutputItem(bytes, mime);
219 }
220 > notebooks.ts
221 > static json(value: unknown, mime: string = 'text/x-json'): NotebookCellOutputItem {
222 const rawStr = JSON.stringify(value, undefined, '\t');
223 return NotebookCellOutputItem.text(rawStr, mime);
224 }
225 > notebooks.ts
226 > constructor(
227 public data: Uint8Array,
228 public mime: string
234 this.mime = mimeNormalized;
235 }
236 > } notebooks.ts
237 >
238 > export class NotebookCellOutput {
239 >
240 > static isNotebookCellOutput(candidate: unknown): candidate is vscode.NotebookCellOutput {
241 if (candidate instanceof NotebookCellOutput) {
242 return true;
247 return typeof (<NotebookCellOutput>candidate).id === 'string' && Array.isArray((<NotebookCellOutput>candidate).items);
248 }
249 > notebooks.ts
250 > static ensureUniqueMimeTypes(items: NotebookCellOutputItem[], warn: boolean = false): NotebookCellOutputItem[] {
251 const seen = new Set<string>();
252 const removeIdx = new Set<number>();
270 return items.filter((_item, index) => !removeIdx.has(index));
271 }
272 > notebooks.ts
273 > id: string;
274 > items: NotebookCellOutputItem[];
275 > metadata?: Record<string, unknown>;
276 >
277 > constructor(
278 items: NotebookCellOutputItem[],
279 idOrMetadata?: string | Record<string, unknown>,
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/workbench/contrib/chat/common/promptSyntax/hookTypes.ts 122 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- hookTypes.ts
2 > * Copyright (c) Microsoft 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 { Target } from './promptTypes.js';
8 >
9 > /**
10 > * Enum of hook types across all targets. For the set of supported hooks per target, see HOOKS_BY_TARGET.
11 > */
12 > export enum HookType {
13 > SessionStart = 'SessionStart',
14 > SessionEnd = 'SessionEnd',
15 > UserPromptSubmit = 'UserPromptSubmit',
16 > PreToolUse = 'PreToolUse',
17 > PostToolUse = 'PostToolUse',
18 > PreCompact = 'PreCompact',
19 > SubagentStart = 'SubagentStart',
20 > SubagentStop = 'SubagentStop',
21 > Stop = 'Stop',
22 > ErrorOccurred = 'ErrorOccurred',
23 > }
24 >
25 > /**
26 > * String literal type derived from HookType enum values.
27 > */
28 > export type HookTypeValue = `${HookType}`;
29 >
30 > export const HOOKS_BY_TARGET: Record<Target, Record<string, HookType>> = {
31 > // see https://code.visualstudio.com/docs/copilot/customization/hooks#_hook-lifecycle-events
32 > [Target.VSCode]: {
33 > 'SessionStart': HookType.SessionStart,
34 > 'UserPromptSubmit': HookType.UserPromptSubmit,
35 > 'PreToolUse': HookType.PreToolUse,
36 > 'PostToolUse': HookType.PostToolUse,
37 > 'PreCompact': HookType.PreCompact,
38 > 'SubagentStart': HookType.SubagentStart,
39 > 'SubagentStop': HookType.SubagentStop,
40 > 'Stop': HookType.Stop,
41 > },
42 > // see https://docs.github.com/en/copilot/concepts/agents/coding-agent/about-hooks#types-of-hooks
43 > [Target.GitHubCopilot]: {
44 > 'sessionStart': HookType.SessionStart,
45 > 'sessionEnd': HookType.SessionEnd,
46 > 'userPromptSubmitted': HookType.UserPromptSubmit,
47 > 'preToolUse': HookType.PreToolUse,
48 > 'postToolUse': HookType.PostToolUse,
49 > 'agentStop': HookType.Stop,
50 > 'subagentStop': HookType.SubagentStop,
51 > 'errorOccurred': HookType.ErrorOccurred
52 > },
53 > // see https://docs.anthropic.com/en/docs/claude-code/hooks
54 > [Target.Claude]: {
55 > 'SessionStart': HookType.SessionStart,
56 > 'UserPromptSubmit': HookType.UserPromptSubmit,
57 > 'PreToolUse': HookType.PreToolUse,
58 > 'PostToolUse': HookType.PostToolUse,
59 > 'PreCompact': HookType.PreCompact,
60 > 'SubagentStart': HookType.SubagentStart,
61 > 'SubagentStop': HookType.SubagentStop,
62 > 'Stop': HookType.Stop,
63 > },
64 > // if no target, just list all known hook types.
65 > [Target.Undefined]: Object.fromEntries(
66 > Object.values(HookType).map(h => [h, h])
67 > ) as Record<string, HookType>
68 > };
69 >
70 > /**
71 > * Metadata for a hook type including localized label and description.
72 > */
73 > export interface IHookTypeMeta {
74 > readonly label: string;
75 > readonly description: string;
76 > }
77 >
78 > /**
79 > * Metadata for hook types including localized labels and descriptions
80 > */
81 > export const HOOK_METADATA: { [key in HookType]: IHookTypeMeta } = {
82 > [HookType.SessionStart]: {
83 > label: nls.localize('hookType.sessionStart.label', "Session Start"),
84 > description: nls.localize('hookType.sessionStart.description', "Executed when a new agent session begins.")
85 > },
86 > [HookType.UserPromptSubmit]: {
87 > label: nls.localize('hookType.userPromptSubmit.label', "User Prompt Submit"),
88 > description: nls.localize('hookType.userPromptSubmit.description', "Executed when the user submits a prompt to the agent.")
89 > },
90 > [HookType.PreToolUse]: {
91 > label: nls.localize('hookType.preToolUse.label', "Pre-Tool Use"),
92 > description: nls.localize('hookType.preToolUse.description', "Executed before the agent uses any tool.")
93 > },
94 > [HookType.PostToolUse]: {
95 > label: nls.localize('hookType.postToolUse.label', "Post-Tool Use"),
96 > description: nls.localize('hookType.postToolUse.description', "Executed after a tool completes execution successfully.")
97 > },
98 > [HookType.PreCompact]: {
99 > label: nls.localize('hookType.preCompact.label', "Pre-Compact"),
100 > description: nls.localize('hookType.preCompact.description', "Executed before the agent compacts the conversation context.")
101 > },
102 > [HookType.SubagentStart]: {
103 > label: nls.localize('hookType.subagentStart.label', "Subagent Start"),
104 > description: nls.localize('hookType.subagentStart.description', "Executed when a subagent is started.")
105 > },
106 > [HookType.SubagentStop]: {
107 > label: nls.localize('hookType.subagentStop.label', "Subagent Stop"),
108 > description: nls.localize('hookType.subagentStop.description', "Executed when a subagent stops.")
109 > },
110 > [HookType.Stop]: {
111 > label: nls.localize('hookType.stop.label', "Stop"),
112 > description: nls.localize('hookType.stop.description', "Executed when the agent stops.")
113 > },
114 > [HookType.SessionEnd]: {
115 > label: nls.localize('hookType.sessionEnd.label', "Session End"),
116 > description: nls.localize('hookType.sessionEnd.description', "Executed when an agent session ends.")
117 > },
118 > [HookType.ErrorOccurred]: {
119 > label: nls.localize('hookType.errorOccurred.label', "Error Occurred"),
120 > description: nls.localize('hookType.errorOccurred.description', "Executed when an error occurs during the agent session.")
121 > }
122 > };
src/vs/workbench/api/common/extHostTypes/workspaceEdit.ts 120 covered LOC · 18 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- workspaceEdit.ts
2 > * Copyright (c) Microsoft 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 * as vscode from 'vscode';
7 > import { coalesceInPlace } from '../../../../base/common/arrays.js';
8 > import { ResourceMap } from '../../../../base/common/map.js';
9 > import { URI } from '../../../../base/common/uri.js';
10 > import { CellEditType, ICellMetadataEdit, IDocumentMetadataEdit } from '../../../contrib/notebook/common/notebookCommon.js';
11 > import { NotebookEdit } from './notebooks.js';
12 > import { SnippetTextEdit } from './snippetTextEdit.js';
13 > import { es5ClassCompat } from './es5ClassCompat.js';
14 > import { Position } from './position.js';
15 > import { Range } from './range.js';
16 > import { TextEdit } from './textEdit.js';
17 >
18 > export interface IFileOperationOptions {
19 > readonly overwrite?: boolean;
20 > readonly ignoreIfExists?: boolean;
21 > readonly ignoreIfNotExists?: boolean;
22 > readonly recursive?: boolean;
23 > readonly contents?: Uint8Array | vscode.DataTransferFile;
24 > }
25 >
26 > export const enum FileEditType {
27 > File = 1,
28 > Text = 2,
29 > Cell = 3,
30 > CellReplace = 5,
31 > Snippet = 6,
32 > }
33 >
34 > export interface IFileOperation {
35 > readonly _type: FileEditType.File;
36 > readonly from?: URI;
37 > readonly to?: URI;
38 > readonly options?: IFileOperationOptions;
39 > readonly metadata?: vscode.WorkspaceEditEntryMetadata;
40 > }
41 >
42 > export interface IFileTextEdit {
43 > readonly _type: FileEditType.Text;
44 > readonly uri: URI;
45 > readonly edit: TextEdit;
46 > readonly metadata?: vscode.WorkspaceEditEntryMetadata;
47 > }
48 >
49 > export interface IFileSnippetTextEdit {
50 > readonly _type: FileEditType.Snippet;
51 > readonly uri: URI;
52 > readonly range: vscode.Range;
53 > readonly edit: vscode.SnippetString;
54 > readonly metadata?: vscode.WorkspaceEditEntryMetadata;
55 > readonly keepWhitespace?: boolean;
56 > }
57 >
58 > export interface IFileCellEdit {
59 > readonly _type: FileEditType.Cell;
60 > readonly uri: URI;
61 > readonly edit?: ICellMetadataEdit | IDocumentMetadataEdit;
62 > readonly metadata?: vscode.WorkspaceEditEntryMetadata;
63 > }
64 >
65 > export interface ICellEdit {
66 > readonly _type: FileEditType.CellReplace;
67 > readonly metadata?: vscode.WorkspaceEditEntryMetadata;
68 > readonly uri: URI;
69 > readonly index: number;
70 > readonly count: number;
71 > readonly cells: vscode.NotebookCellData[];
72 > }
73 >
74 > export type WorkspaceEditEntry = IFileOperation | IFileTextEdit | IFileSnippetTextEdit | IFileCellEdit | ICellEdit;
75 >
76 > @es5ClassCompat
77 > export class WorkspaceEdit implements vscode.WorkspaceEdit {
78
79 private readonly _edits: WorkspaceEditEntry[] = [];
81 >
82 > _allEntries(): ReadonlyArray<WorkspaceEditEntry> {
83 return this._edits;
84 }
86 > // --- file
87 > renameFile(from: vscode.Uri, to: vscode.Uri, options?: { readonly overwrite?: boolean; readonly ignoreIfExists?: boolean }, metadata?: vscode.WorkspaceEditEntryMetadata): void {
88 this._edits.push({ _type: FileEditType.File, from, to, options, metadata });
89 }
91 > createFile(uri: vscode.Uri, options?: { readonly overwrite?: boolean; readonly ignoreIfExists?: boolean; readonly contents?: Uint8Array | vscode.DataTransferFile }, metadata?: vscode.WorkspaceEditEntryMetadata): void {
92 this._edits.push({ _type: FileEditType.File, from: undefined, to: uri, options, metadata });
93 }
95 > deleteFile(uri: vscode.Uri, options?: { readonly recursive?: boolean; readonly ignoreIfNotExists?: boolean }, metadata?: vscode.WorkspaceEditEntryMetadata): void {
96 this._edits.push({ _type: FileEditType.File, from: uri, to: undefined, options, metadata });
97 }
99 > // --- notebook
100 > private replaceNotebookMetadata(uri: URI, value: Record<string, unknown>, metadata?: vscode.WorkspaceEditEntryMetadata): void {
101 this._edits.push({ _type: FileEditType.Cell, metadata, uri, edit: { editType: CellEditType.DocumentMetadata, metadata: value } });
102 }
104 > private replaceNotebookCells(uri: URI, startOrRange: vscode.NotebookRange, cellData: vscode.NotebookCellData[], metadata?: vscode.WorkspaceEditEntryMetadata): void {
105 const start = startOrRange.start;
106 const end = startOrRange.end;
110 }
111 }
113 > private replaceNotebookCellMetadata(uri: URI, index: number, cellMetadata: Record<string, unknown>, metadata?: vscode.WorkspaceEditEntryMetadata): void {
114 this._edits.push({ _type: FileEditType.Cell, metadata, uri, edit: { editType: CellEditType.Metadata, index, metadata: cellMetadata } });
115 }
117 > // --- text
118 > replace(uri: URI, range: Range, newText: string, metadata?: vscode.WorkspaceEditEntryMetadata): void {
119 this._edits.push({ _type: FileEditType.Text, uri, edit: new TextEdit(range, newText), metadata });
120 }
122 > insert(resource: URI, position: Position, newText: string, metadata?: vscode.WorkspaceEditEntryMetadata): void {
123 this.replace(resource, new Range(position, position), newText, metadata);
124 }
126 > delete(resource: URI, range: Range, metadata?: vscode.WorkspaceEditEntryMetadata): void {
127 this.replace(resource, range, '', metadata);
128 }
130 > // --- text (Maplike)
131 > has(uri: URI): boolean {
132 return this._edits.some(edit => edit._type === FileEditType.Text && edit.uri.toString() === uri.toString());
133 }
135 > set(uri: URI, edits: ReadonlyArray<TextEdit | SnippetTextEdit>): void;
136 > set(uri: URI, edits: ReadonlyArray<[TextEdit | SnippetTextEdit, vscode.WorkspaceEditEntryMetadata | undefined]>): void;
137 > set(uri: URI, edits: readonly NotebookEdit[]): void;
138 > set(uri: URI, edits: ReadonlyArray<[NotebookEdit, vscode.WorkspaceEditEntryMetadata | undefined]>): void;
139 >
140 > set(uri: URI, edits: null | undefined | ReadonlyArray<TextEdit | SnippetTextEdit | NotebookEdit | [NotebookEdit, vscode.WorkspaceEditEntryMetadata | undefined] | [TextEdit | SnippetTextEdit, vscode.WorkspaceEditEntryMetadata | undefined]>): void {
141 if (!edits) {
142 // remove all text, snippet, or notebook edits for `uri`
186 }
187 }
189 > get(uri: URI): TextEdit[] {
190 const res: TextEdit[] = [];
191 for (const candidate of this._edits) {
196 return res;
197 }
199 > entries(): [URI, TextEdit[]][] {
200 const textEdits = new ResourceMap<[URI, TextEdit[]]>();
201 for (const candidate of this._edits) {
211 return [...textEdits.values()];
212 }
214 > get size(): number {
215 return this.entries().length;
216 }
218 > toJSON(): [URI, TextEdit[]][] {
219 return this.entries();
220 }
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/workbench/api/common/extHostEditorTabs.ts 114 covered LOC · 25 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostEditorTabs.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { diffSets } from '../../../base/common/collections.js';
7 > import { Emitter } from '../../../base/common/event.js';
8 > import { assertReturnsDefined } from '../../../base/common/types.js';
9 > import { URI } from '../../../base/common/uri.js';
10 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
11 > import { IEditorTabDto, IEditorTabGroupDto, IExtHostEditorTabsShape, MainContext, MainThreadEditorTabsShape, TabInputKind, TabModelOperationKind, TabOperation } from './extHost.protocol.js';
12 > import { IExtHostRpcService } from './extHostRpcService.js';
13 > import * as typeConverters from './extHostTypeConverters.js';
14 > import { ChatEditorTabInput, CustomEditorTabInput, InteractiveWindowInput, NotebookDiffEditorTabInput, NotebookEditorTabInput, TerminalEditorTabInput, TextDiffTabInput, TextMergeTabInput, TextTabInput, WebviewEditorTabInput, TextMultiDiffTabInput } from './extHostTypes.js';
15 > import type * as vscode from 'vscode';
16 >
17 > export interface IExtHostEditorTabs extends IExtHostEditorTabsShape {
18 > readonly _serviceBrand: undefined;
19 > tabGroups: vscode.TabGroups;
20 > }
21 >
22 > export const IExtHostEditorTabs = createDecorator<IExtHostEditorTabs>('IExtHostEditorTabs');
23 >
24 > type AnyTabInput = TextTabInput | TextDiffTabInput | TextMultiDiffTabInput | CustomEditorTabInput | NotebookEditorTabInput | NotebookDiffEditorTabInput | WebviewEditorTabInput | TerminalEditorTabInput | InteractiveWindowInput | ChatEditorTabInput;
25 >
26 > class ExtHostEditorTab {
27 > private _apiObject: vscode.Tab | undefined;
28 > private _dto!: IEditorTabDto;
29 > private _input: AnyTabInput | undefined;
30 > private _parentGroup: ExtHostEditorTabGroup;
31 > private readonly _activeTabIdGetter: () => string;
32 >
33 > constructor(dto: IEditorTabDto, parentGroup: ExtHostEditorTabGroup, activeTabIdGetter: () => string) {
34 this._activeTabIdGetter = activeTabIdGetter;
35 this._parentGroup = parentGroup;
36 this.acceptDtoUpdate(dto);
37 }
39 > get apiObject(): vscode.Tab {
40 if (!this._apiObject) {
41 // Don't want to lose reference to parent `this` in the getters
69 return this._apiObject;
70 }
72 > get tabId(): string {
73 return this._dto.id;
74 }
76 > acceptDtoUpdate(dto: IEditorTabDto) {
77 this._dto = dto;
78 this._input = this._initInput();
79 }
81 > private _initInput() {
82 switch (this._dto.input.kind) {
83 case TabInputKind.TextInput:
107 }
108 }
110 >
111 > class ExtHostEditorTabGroup {
112 >
113 > private _apiObject: vscode.TabGroup | undefined;
114 > private _dto: IEditorTabGroupDto;
115 > private _tabs: ExtHostEditorTab[] = [];
116 > private _activeTabId: string = '';
117 > private _activeGroupIdGetter: () => number | undefined;
118 >
119 > constructor(dto: IEditorTabGroupDto, activeGroupIdGetter: () => number | undefined) {
120 this._dto = dto;
121 this._activeGroupIdGetter = activeGroupIdGetter;
123 this._reconcileTabs(dto);
124 }
126 > get apiObject(): vscode.TabGroup {
127 if (!this._apiObject) {
128 // Don't want to lose reference to parent `this` in the getters
147 return this._apiObject;
148 }
150 > get groupId(): number {
151 return this._dto.groupId;
152 }
154 > get tabs(): ExtHostEditorTab[] {
155 return this._tabs;
156 }
158 > acceptGroupDtoUpdate(dto: IEditorTabGroupDto) {
159 this._dto = dto;
160 }
162 > /**
163 > * Accepts a full group dto during a complete tab-model resync, reusing the
164 > * existing {@link ExtHostEditorTab} instances for tabs that still exist so
165 > * their (and this group's) frozen `apiObject` keeps a stable identity.
166 > * Extensions routinely key `Map`/`WeakMap`/`Set` collections by these
167 > * objects, so recreating them on every resync would break those lookups and
168 > * leak whatever they retain.
169 > */
170 > acceptModelUpdate(dto: IEditorTabGroupDto) {
171 this._dto = dto;
172 this._reconcileTabs(dto);
173 }
175 > private _reconcileTabs(dto: IEditorTabGroupDto) {
176 const existingTabsById = new Map<string, ExtHostEditorTab>();
177 for (const tab of this._tabs) {
192 });
193 }
195 > acceptTabOperation(operation: TabOperation): ExtHostEditorTab {
196 // In the open case we add the tab to the group
197 if (operation.kind === TabModelOperationKind.TAB_OPEN) {
239 return tab;
240 }
242 > // Not a getter since it must be a function to be used as a callback for the tabs
243 > activeTabId(): string {
244 return this._activeTabId;
245 }
247 >
248 > export class ExtHostEditorTabs implements IExtHostEditorTabs {
249 > readonly _serviceBrand: undefined;
250 >
251 > private readonly _proxy: MainThreadEditorTabsShape;
252 > private readonly _onDidChangeTabs = new Emitter<vscode.TabChangeEvent>();
253 > private readonly _onDidChangeTabGroups = new Emitter<vscode.TabGroupChangeEvent>();
254 >
255 > // Have to use ! because this gets initialized via an RPC proxy
256 > private _activeGroupId!: number;
257 >
258 > private _extHostTabGroups: ExtHostEditorTabGroup[] = [];
259 >
260 > private _apiObject: vscode.TabGroups | undefined;
261 >
262 > constructor(@IExtHostRpcService extHostRpc: IExtHostRpcService) {
263 this._proxy = extHostRpc.getProxy(MainContext.MainThreadEditorTabs);
264 }
266 > get tabGroups(): vscode.TabGroups {
267 if (!this._apiObject) {
268 const that = this;
306 return this._apiObject;
307 }
309 > $acceptEditorTabModel(tabGroups: IEditorTabGroupDto[]): void {
310
311 const groupIdsBefore = new Set(this._extHostTabGroups.map(group => group.groupId));
347 this._onDidChangeTabGroups.fire(Object.freeze({ opened, closed, changed }));
348 }
350 > $acceptTabGroupUpdate(groupDto: IEditorTabGroupDto) {
351 const group = this._extHostTabGroups.find(group => group.groupId === groupDto.groupId);
352 if (!group) {
359 this._onDidChangeTabGroups.fire(Object.freeze({ changed: [group.apiObject], opened: [], closed: [] }));
360 }
362 > $acceptTabOperation(operation: TabOperation) {
363 const group = this._extHostTabGroups.find(group => group.groupId === operation.groupId);
364 if (!group) {
393 }
394 }
396 > private _findExtHostTabFromApi(apiTab: vscode.Tab): ExtHostEditorTab | undefined {
397 for (const group of this._extHostTabGroups) {
398 for (const tab of group.tabs) {
404 return;
405 }
407 > private _findExtHostTabGroupFromApi(apiTabGroup: vscode.TabGroup): ExtHostEditorTabGroup | undefined {
408 return this._extHostTabGroups.find(candidate => candidate.apiObject === apiTabGroup);
409 }
411 > private async _closeTabs(tabs: vscode.Tab[], preserveFocus?: boolean): Promise<boolean> {
412 const extHostTabIds: string[] = [];
413 for (const tab of tabs) {
420 return this._proxy.$closeTab(extHostTabIds, preserveFocus);
421 }
423 > private async _closeGroups(groups: vscode.TabGroup[], preserverFoucs?: boolean): Promise<boolean> {
424 const extHostGroupIds: number[] = [];
425 for (const group of groups) {
432 return this._proxy.$closeGroup(extHostGroupIds, preserverFoucs);
433 }
435 >
436 > //#region Utils
437 function isTabGroup(obj: unknown): obj is vscode.TabGroup {
438 const tabGroup = obj as vscode.TabGroup;
src/vs/workbench/services/configurationResolver/common/configurationResolver.ts 114 covered LOC · 2 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- configurationResolver.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IStringDictionary } from '../../../../base/common/collections.js';
7 > import { ErrorNoTelemetry } from '../../../../base/common/errors.js';
8 > import { IProcessEnvironment } from '../../../../base/common/platform.js';
9 > import { ConfigurationTarget } from '../../../../platform/configuration/common/configuration.js';
10 > import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
11 > import { IWorkspaceFolderData } from '../../../../platform/workspace/common/workspace.js';
12 > import { ConfigurationResolverExpression } from './configurationResolverExpression.js';
13 >
14 > export const IConfigurationResolverService = createDecorator<IConfigurationResolverService>('configurationResolverService');
15 >
16 > export interface IConfigurationResolverService {
17 > readonly _serviceBrand: undefined;
18 >
19 > /** Variables the resolver is able to resolve. */
20 > readonly resolvableVariables: ReadonlySet<string>;
21 >
22 > resolveWithEnvironment(environment: IProcessEnvironment, folder: IWorkspaceFolderData | undefined, value: string): Promise<string>;
23 >
24 > /**
25 > * Recursively resolves all variables in the given config and returns a copy of it with substituted values.
26 > * Command variables are only substituted if a "commandValueMapping" dictionary is given and if it contains an entry for the command.
27 > */
28 > resolveAsync<T>(folder: IWorkspaceFolderData | undefined, config: T): Promise<T extends ConfigurationResolverExpression<infer R> ? R : T>;
29 >
30 > /**
31 > * Recursively resolves all variables (including commands and user input) in the given config and returns a copy of it with substituted values.
32 > * If a "variables" dictionary (with names -> command ids) is given, command variables are first mapped through it before being resolved.
33 > *
34 > * @param section For example, 'tasks' or 'debug'. Used for resolving inputs.
35 > * @param variables Aliases for commands.
36 > */
37 > resolveWithInteractionReplace(folder: IWorkspaceFolderData | undefined, config: unknown, section?: string, variables?: IStringDictionary<string>, target?: ConfigurationTarget): Promise<any>;
38 >
39 > /**
40 > * Similar to resolveWithInteractionReplace, except without the replace. Returns a map of variables and their resolution.
41 > * Keys in the map will be of the format input:variableName or command:variableName.
42 > */
43 > resolveWithInteraction(folder: IWorkspaceFolderData | undefined, config: unknown, section?: string, variables?: IStringDictionary<string>, target?: ConfigurationTarget): Promise<Map<string, string> | undefined>;
44 >
45 > /**
46 > * Contributes a variable that can be resolved later. Consumers that use resolveAny, resolveWithInteraction,
47 > * and resolveWithInteractionReplace will have contributed variables resolved.
48 > */
49 > contributeVariable(variable: string, resolution: () => Promise<string | undefined>): void;
50 > }
51 >
52 > interface PromptStringInputInfo {
53 > id: string;
54 > type: 'promptString';
55 > description: string;
56 > default?: string;
57 > password?: boolean;
58 > }
59 >
60 > interface PickStringInputInfo {
61 > id: string;
62 > type: 'pickString';
63 > description: string;
64 > options: (string | { value: string; label?: string })[];
65 > default?: string;
66 > }
67 >
68 > interface CommandInputInfo {
69 > id: string;
70 > type: 'command';
71 > command: string;
72 > args?: any;
73 > }
74 >
75 > export type ConfiguredInput = PromptStringInputInfo | PickStringInputInfo | CommandInputInfo;
76 >
77 > export enum VariableKind {
78 > Unknown = 'unknown',
79 >
80 > Env = 'env',
81 > Config = 'config',
82 > Command = 'command',
83 > Input = 'input',
84 > ExtensionInstallFolder = 'extensionInstallFolder',
85 > TaskVar = 'taskVar',
86 >
87 > WorkspaceFolder = 'workspaceFolder',
88 > Cwd = 'cwd',
89 > WorkspaceFolderBasename = 'workspaceFolderBasename',
90 > UserHome = 'userHome',
91 > LineNumber = 'lineNumber',
92 > ColumnNumber = 'columnNumber',
93 > SelectedText = 'selectedText',
94 > File = 'file',
95 > FileWorkspaceFolder = 'fileWorkspaceFolder',
96 > FileWorkspaceFolderBasename = 'fileWorkspaceFolderBasename',
97 > RelativeFile = 'relativeFile',
98 > RelativeFileDirname = 'relativeFileDirname',
99 > FileDirname = 'fileDirname',
100 > FileExtname = 'fileExtname',
101 > FileBasename = 'fileBasename',
102 > FileBasenameNoExtension = 'fileBasenameNoExtension',
103 > FileDirnameBasename = 'fileDirnameBasename',
104 > ExecPath = 'execPath',
105 > ExecInstallFolder = 'execInstallFolder',
106 > PathSeparator = 'pathSeparator',
107 > PathSeparatorAlias = '/'
108 > }
109 >
110 > export const allVariableKinds = Object.values(VariableKind).filter((value): value is VariableKind => typeof value === 'string');
111 >
112 > export class VariableError extends ErrorNoTelemetry {
113 > constructor(public readonly variable: VariableKind, message?: string) {
114 super(message);
115 }
src/vs/editor/common/core/position.ts 113 covered LOC · 16 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;
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/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/workbench/services/path/common/pathService.ts 111 covered LOC · 10 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- pathService.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { isValidBasename } from '../../../../base/common/extpath.js';
7 > import { Schemas } from '../../../../base/common/network.js';
8 > import { IPath, win32, posix } from '../../../../base/common/path.js';
9 > import { OperatingSystem, OS } from '../../../../base/common/platform.js';
10 > import { basename } from '../../../../base/common/resources.js';
11 > import { URI } from '../../../../base/common/uri.js';
12 > import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
13 > import { getVirtualWorkspaceScheme } from '../../../../platform/workspace/common/virtualWorkspace.js';
14 > import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.js';
15 > import { IWorkbenchEnvironmentService } from '../../environment/common/environmentService.js';
16 > import { IRemoteAgentService } from '../../remote/common/remoteAgentService.js';
17 >
18 > export const IPathService = createDecorator<IPathService>('pathService');
19 >
20 > /**
21 > * Provides access to path related properties that will match the
22 > * environment. If the environment is connected to a remote, the
23 > * path properties will match that of the remotes operating system.
24 > */
25 > export interface IPathService {
26 >
27 > readonly _serviceBrand: undefined;
28 >
29 > /**
30 > * The correct path library to use for the target environment. If
31 > * the environment is connected to a remote, this will be the
32 > * path library of the remote file system. Otherwise it will be
33 > * the local file system's path library depending on the OS.
34 > */
35 > readonly path: Promise<IPath>;
36 >
37 > /**
38 > * Determines the best default URI scheme for the current workspace.
39 > * It uses information about whether we're running remote, in browser,
40 > * or native combined with information about the current workspace to
41 > * find the best default scheme.
42 > */
43 > readonly defaultUriScheme: string;
44 >
45 > /**
46 > * Converts the given path to a file URI to use for the target
47 > * environment. If the environment is connected to a remote, it
48 > * will use the path separators according to the remote file
49 > * system. Otherwise it will use the local file system's path
50 > * separators.
51 > */
52 > fileURI(path: string): Promise<URI>;
53 >
54 > /**
55 > * Resolves the user-home directory for the target environment.
56 > * If the envrionment is connected to a remote, this will be the
57 > * remote's user home directory, otherwise the local one unless
58 > * `preferLocal` is set to `true`.
59 > */
60 > userHome(options: { preferLocal: true }): URI;
61 > userHome(options?: { preferLocal: boolean }): Promise<URI>;
62 >
63 > /**
64 > * Figures out if the provided resource has a valid file name
65 > * for the operating system the file is saved to.
66 > *
67 > * Note: this currently only supports `file` and `vscode-file`
68 > * protocols where we know the limits of the file systems behind
69 > * these OS. Other remotes are not supported and this method
70 > * will always return `true` for them.
71 > */
72 > hasValidBasename(resource: URI, basename?: string): Promise<boolean>;
73 > hasValidBasename(resource: URI, os: OperatingSystem, basename?: string): boolean;
74 >
75 > /**
76 > * @deprecated use `userHome` instead.
77 > */
78 > readonly resolvedUserHome: URI | undefined;
79 > }
80 >
81 > export abstract class AbstractPathService implements IPathService {
82 >
83 > declare readonly _serviceBrand: undefined;
84 >
85 > private resolveOS: Promise<OperatingSystem>;
86 >
87 > private resolveUserHome: Promise<URI>;
88 > private maybeUnresolvedUserHome: URI | undefined;
89 >
90 > constructor(
91 private localUserHome: URI,
92 @IRemoteAgentService private readonly remoteAgentService: IRemoteAgentService,
110 })();
111 }
113 > hasValidBasename(resource: URI, basename?: string): Promise<boolean>;
114 > hasValidBasename(resource: URI, os: OperatingSystem, basename?: string): boolean;
115 > hasValidBasename(resource: URI, arg2?: string | OperatingSystem, basename?: string): boolean | Promise<boolean> {
116
117 // async version
123 return this.doHasValidBasename(resource, arg2, basename);
124 }
126 > private doHasValidBasename(resource: URI, os: OperatingSystem, name?: string): boolean {
127
128 // Our `isValidBasename` method only works with our
135 return true;
136 }
138 > get defaultUriScheme(): string {
139 return AbstractPathService.findDefaultUriScheme(this.environmentService, this.contextService);
140 }
142 > static findDefaultUriScheme(environmentService: IWorkbenchEnvironmentService, contextService: IWorkspaceContextService): string {
143 if (environmentService.remoteAuthority) {
144 return Schemas.vscodeRemote;
162 return Schemas.file;
163 }
165 > userHome(options?: { preferLocal: boolean }): Promise<URI>;
166 > userHome(options: { preferLocal: true }): URI;
167 > userHome(options?: { preferLocal: boolean }): Promise<URI> | URI {
168 return options?.preferLocal ? this.localUserHome : this.resolveUserHome;
169 }
171 > get resolvedUserHome(): URI | undefined {
172 return this.maybeUnresolvedUserHome;
173 }
175 > get path(): Promise<IPath> {
176 return this.resolveOS.then(os => {
177 return os === OperatingSystem.Windows ?
180 });
181 }
183 > async fileURI(_path: string): Promise<URI> {
184 let authority = '';
185
src/vs/base/common/dataTransfer.ts 108 covered LOC · 19 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- dataTransfer.ts
2 > * Copyright (c) Microsoft 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 './arrays.js';
7 > import { Iterable } from './iterator.js';
8 > import { URI } from './uri.js';
9 > import { generateUuid } from './uuid.js';
10 >
11 > export interface IDataTransferFile {
12 > readonly id: string;
13 > readonly name: string;
14 > readonly uri?: URI;
15 > data(): Promise<Uint8Array>;
16 > }
17 >
18 > export interface IDataTransferItem {
19 > id?: string;
20 > asString(): Thenable<string>;
21 > asFile(): IDataTransferFile | undefined;
22 > value: unknown;
23 > }
24 >
25 > export function createStringDataTransferItem(stringOrPromise: string | Promise<string>, id?: string): IDataTransferItem {
26 return {
27 id,
31 };
32 }
34 > export function createFileDataTransferItem(fileName: string, uri: URI | undefined, data: () => Promise<Uint8Array>, id?: string): IDataTransferItem {
35 const file = { id: generateUuid(), name: fileName, uri, data };
36 return {
41 };
42 }
44 > export interface IReadonlyVSDataTransfer extends Iterable<readonly [string, IDataTransferItem]> {
45 > /**
46 > * Get the total number of entries in this data transfer.
47 > */
48 > get size(): number;
49 >
50 > /**
51 > * Check if this data transfer contains data for `mimeType`.
52 > *
53 > * This uses exact matching and does not support wildcards.
54 > */
55 > has(mimeType: string): boolean;
56 >
57 > /**
58 > * Check if this data transfer contains data matching `pattern`.
59 > *
60 > * This allows matching for wildcards, such as `image/*`.
61 > *
62 > * Use the special `files` mime type to match any file in the data transfer.
63 > */
64 > matches(pattern: string): boolean;
65 >
66 > /**
67 > * Retrieve the first entry for `mimeType`.
68 > *
69 > * Note that if you want to find all entries for a given mime type, use {@link IReadonlyVSDataTransfer.entries} instead.
70 > */
71 > get(mimeType: string): IDataTransferItem | undefined;
72 > }
73 >
74 > export class VSDataTransfer implements IReadonlyVSDataTransfer {
75
76 private readonly _entries = new Map<string, IDataTransferItem[]>();
78 > public get size(): number {
79 let size = 0;
80 for (const _ of this._entries) {
83 return size;
84 }
86 > public has(mimeType: string): boolean {
87 return this._entries.has(this.toKey(mimeType));
88 }
90 > public matches(pattern: string): boolean {
91 const mimes = [...this._entries.keys()];
92 if (Iterable.some(this, ([_, item]) => item.asFile())) {
96 return matchesMimeType_normalized(normalizeMimeType(pattern), mimes);
97 }
99 > public get(mimeType: string): IDataTransferItem | undefined {
100 return this._entries.get(this.toKey(mimeType))?.[0];
101 }
103 > /**
104 > * Add a new entry to this data transfer.
105 > *
106 > * This does not replace existing entries for `mimeType`.
107 > */
108 > public append(mimeType: string, value: IDataTransferItem): void {
109 const existing = this._entries.get(mimeType);
110 if (existing) {
114 }
115 }
117 > /**
118 > * Set the entry for a given mime type.
119 > *
120 > * This replaces all existing entries for `mimeType`.
121 > */
122 > public replace(mimeType: string, value: IDataTransferItem): void {
123 this._entries.set(this.toKey(mimeType), [value]);
124 }
126 > /**
127 > * Remove all entries for `mimeType`.
128 > */
129 > public delete(mimeType: string) {
130 this._entries.delete(this.toKey(mimeType));
131 }
133 > /**
134 > * Iterate over all `[mime, item]` pairs in this data transfer.
135 > *
136 > * There may be multiple entries for each mime type.
137 > */
138 > public *[Symbol.iterator](): IterableIterator<readonly [string, IDataTransferItem]> {
139 for (const [mine, items] of this._entries) {
140 for (const item of items) {
143 }
144 }
146 > private toKey(mimeType: string): string {
147 return normalizeMimeType(mimeType);
148 }
149 > } dataTransfer.ts
150 >
151 function normalizeMimeType(mimeType: string): string {
152 return mimeType.toLowerCase();
153 }
155 > export function matchesMimeType(pattern: string, mimeTypes: readonly string[]): boolean {
156 return matchesMimeType_normalized(
157 normalizeMimeType(pattern),
158 mimeTypes.map(normalizeMimeType));
159 }
161 function matchesMimeType_normalized(normalizedPattern: string, normalizedMimeTypes: readonly string[]): boolean {
162 // Anything wildcard
183 return false;
184 }
186 >
187 > export const UriList = Object.freeze({
188 > // http://amundsen.com/hypermedia/urilist/
189 > create: (entries: ReadonlyArray<string | URI>): string => {
190 return distinct(entries.map(x => x.toString())).join('\r\n');
191 },
192 > split: (str: string): string[] => { dataTransfer.ts
193 return str.split('\r\n');
194 },
195 > parse: (str: string): string[] => { dataTransfer.ts
196 return UriList.split(str).filter(value => !value.startsWith('#'));
197 }
198 > }); dataTransfer.ts
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/workbench/api/common/extHostTelemetry.ts 107 covered LOC · 19 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostTelemetry.ts
2 > * Copyright (c) Microsoft 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 * as vscode from 'vscode';
7 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
8 > import { Event, Emitter } from '../../../base/common/event.js';
9 > import { ExtHostTelemetryShape } from './extHost.protocol.js';
10 > import { ICommonProperties, TelemetryLevel } from '../../../platform/telemetry/common/telemetry.js';
11 > import { ILogger, ILoggerService } from '../../../platform/log/common/log.js';
12 > import { IExtHostInitDataService } from './extHostInitDataService.js';
13 > import { ExtensionIdentifier, IExtensionDescription } from '../../../platform/extensions/common/extensions.js';
14 > import { UIKind } from '../../services/extensions/common/extensionHostProtocol.js';
15 > import { cleanData, cleanRemoteAuthority, TelemetryLogGroup } from '../../../platform/telemetry/common/telemetryUtils.js';
16 > import { mixin } from '../../../base/common/objects.js';
17 > import { Disposable } from '../../../base/common/lifecycle.js';
18 > import { localize } from '../../../nls.js';
19 >
20 > type ExtHostTelemetryEventData = Record<string, any> & {
21 > properties?: Record<string, any>;
22 > measurements?: Record<string, number>;
23 > };
24 >
25 > export class ExtHostTelemetry extends Disposable implements ExtHostTelemetryShape {
26 >
27 > readonly _serviceBrand: undefined;
28 >
29 > private readonly _onDidChangeTelemetryEnabled = this._register(new Emitter<boolean>());
30 > readonly onDidChangeTelemetryEnabled: Event<boolean> = this._onDidChangeTelemetryEnabled.event;
31 >
32 > private readonly _onDidChangeTelemetryConfiguration = this._register(new Emitter<vscode.TelemetryConfiguration>());
33 > readonly onDidChangeTelemetryConfiguration: Event<vscode.TelemetryConfiguration> = this._onDidChangeTelemetryConfiguration.event;
34 >
35 > private _productConfig: { usage: boolean; error: boolean } = { usage: true, error: true };
36 > private _level: TelemetryLevel = TelemetryLevel.NONE;
37 > private _oldTelemetryEnablement: boolean | undefined;
38 > private readonly _inLoggingOnlyMode: boolean = false;
39 > private readonly _outputLogger: ILogger;
40 > private readonly _telemetryLoggers = new Map<string, ExtHostTelemetryLogger[]>();
41 >
42 > constructor(
43 isWorker: boolean,
44 @IExtHostInitDataService private readonly initData: IExtHostInitDataService,
55 }));
56 }
58 > getTelemetryConfiguration(): boolean {
59 return this._level === TelemetryLevel.USAGE;
60 }
62 > getTelemetryDetails(): vscode.TelemetryConfiguration {
63 return {
64 isCrashEnabled: this._level >= TelemetryLevel.CRASH,
67 };
68 }
70 > instantiateLogger(extension: IExtensionDescription, sender: vscode.TelemetrySender, options?: vscode.TelemetryLoggerOptions) {
71 const telemetryDetails = this.getTelemetryDetails();
72 const logger = new ExtHostTelemetryLogger(
83 return logger.apiTelemetryLogger;
84 }
86 > $initializeTelemetryLevel(level: TelemetryLevel, supportsTelemetry: boolean, productConfig?: { usage: boolean; error: boolean }): void {
87 this._level = level;
88 this._productConfig = productConfig ?? { usage: true, error: true };
89 }
91 > getBuiltInCommonProperties(extension: IExtensionDescription): ICommonProperties {
92 const commonProperties: ICommonProperties = Object.create(null);
93 // TODO @lramos15, does os info like node arch, platform version, etc exist here.
125 return commonProperties;
126 }
128 > $onDidChangeTelemetryLevel(level: TelemetryLevel): void {
129 this._oldTelemetryEnablement = this.getTelemetryConfiguration();
130 this._level = level;
151 this._onDidChangeTelemetryConfiguration.fire(this.getTelemetryDetails());
152 }
154 > onExtensionError(extension: ExtensionIdentifier, error: Error): boolean {
155 const loggers = this._telemetryLoggers.get(extension.value);
156 const nonDisposedLoggers = loggers?.filter(l => !l.isDisposed);
169 return errorEmitted;
170 }
172 >
173 > export class ExtHostTelemetryLogger {
174 >
175 > static validateSender(sender: vscode.TelemetrySender): void {
176 > if (typeof sender !== 'object') {
177 > throw new TypeError('TelemetrySender argument is invalid');
178 > }
179 > if (typeof sender.sendEventData !== 'function') {
180 > throw new TypeError('TelemetrySender.sendEventData must be a function');
181 > }
182 > if (typeof sender.sendErrorData !== 'function') {
183 > throw new TypeError('TelemetrySender.sendErrorData must be a function');
184 > }
185 > if (typeof sender.flush !== 'undefined' && typeof sender.flush !== 'function') {
186 > throw new TypeError('TelemetrySender.flush must be a function or undefined');
187 > }
188 > }
189 >
190 > private readonly _onDidChangeEnableStates = new Emitter<vscode.TelemetryLogger>();
191 > private readonly _ignoreBuiltinCommonProperties: boolean;
192 > private readonly _additionalCommonProperties: Record<string, any> | undefined;
193 > public readonly ignoreUnhandledExtHostErrors: boolean;
194 >
195 > private _telemetryEnablements: { isUsageEnabled: boolean; isErrorsEnabled: boolean };
196 > private _apiObject: vscode.TelemetryLogger | undefined;
197 > private _sender: vscode.TelemetrySender | undefined;
198 >
199 > constructor(
200 sender: vscode.TelemetrySender,
201 options: vscode.TelemetryLoggerOptions | undefined,
212 this._telemetryEnablements = { isUsageEnabled: telemetryEnablements.isUsageEnabled, isErrorsEnabled: telemetryEnablements.isErrorsEnabled };
213 }
215 > updateTelemetryEnablements(isUsageEnabled: boolean, isErrorsEnabled: boolean): void {
216 if (this._apiObject) {
217 this._telemetryEnablements = { isUsageEnabled, isErrorsEnabled };
219 }
220 }
222 > mixInCommonPropsAndCleanData(data: ExtHostTelemetryEventData): Record<string, any> {
223 // Some telemetry modules prefer to break properties and measurmements up
224 // We mix common properties into the properties tab.
244 return data;
245 }
247 > private logEvent(eventName: string, data?: Record<string, any>): void {
248 // No sender means likely disposed of, we should no-op
249 if (!this._sender) {
262 this._logger.trace(eventName, data);
263 }
265 > logUsage(eventName: string, data?: Record<string, any>): void {
266 if (!this._telemetryEnablements.isUsageEnabled) {
267 return;
269 this.logEvent(eventName, data);
270 }
272 > logError(eventNameOrException: Error | string, data?: Record<string, any>): void {
273 if (!this._telemetryEnablements.isErrorsEnabled || !this._sender) {
274 return;
297 }
298 }
300 > get apiTelemetryLogger(): vscode.TelemetryLogger {
301 if (!this._apiObject) {
302 const that = this;
317 return this._apiObject;
318 }
320 > get isDisposed(): boolean {
321 return !this._sender;
322 }
324 > dispose(): void {
325 if (this._sender?.flush) {
326 let tempSender: vscode.TelemetrySender | undefined = this._sender;
333 this._onDidChangeEnableStates.dispose();
334 }
336 >
337 > export function isNewAppInstall(firstSessionDate: string): boolean {
338 const installAge = Date.now() - new Date(firstSessionDate).getTime();
339 return isNaN(installAge) ? false : installAge < 1000 * 60 * 60 * 24; // install age is less than a day
340 }
342 > export const IExtHostTelemetry = createDecorator<IExtHostTelemetry>('IExtHostTelemetry');
343 > export interface IExtHostTelemetry extends ExtHostTelemetry, ExtHostTelemetryShape { }
src/vs/platform/agentHost/common/state/protocol/channels-changeset/commands.ts 105 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- commands.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > // allow-any-unicode-comment-file
7 > // DO NOT EDIT -- auto-generated by scripts/sync-agent-host-protocol.ts
8 >
9 > import type { URI, ContentRef, StringOrMarkdown, TextRange } from '../common/state.js';
10 > import type { BaseParams } from '../common/commands.js';
11 >
12 > // ─── invokeChangesetOperation ────────────────────────────────────────────────
13 >
14 > /**
15 > * Discriminator for {@link ChangesetOperationTarget}. Mirrors the
16 > * non-`Changeset` members of {@link ChangesetOperationScope} — the
17 > * `Changeset` scope has no target.
18 > *
19 > * @category Commands
20 > */
21 > export const enum ChangesetOperationTargetKind {
22 > /** Operation acts on a single file. */
23 > Resource = 'resource',
24 > /** Operation acts on a line range within a single file. */
25 > Range = 'range',
26 > }
27 >
28 > /**
29 > * Identifies the file or range a {@link ChangesetOperation} should act on.
30 > *
31 > * The `kind` MUST match one of the operation's declared
32 > * {@link ChangesetOperation.scopes}.
33 > *
34 > * @category Commands
35 > */
36 > export type ChangesetOperationTarget =
37 > | { kind: ChangesetOperationTargetKind.Resource; resource: URI; side?: 'before' | 'after' }
38 > | { kind: ChangesetOperationTargetKind.Range; resource: URI; side?: 'before' | 'after'; range: TextRange };
39 >
40 > /**
41 > * Optional follow-up surfaced by the server after an operation completes —
42 > * a {@link ContentRef} the client can fetch and display.
43 > *
44 > * Set `external` to `true` to open the content in the user's preferred
45 > * external handler (e.g. browser); otherwise the client is expected to
46 > * surface it inline.
47 > *
48 > * @category Commands
49 > */
50 > export interface ChangesetOperationFollowUp {
51 > content: ContentRef;
52 > /** When `true`, open in an external handler rather than inline. */
53 > external?: boolean;
54 > }
55 >
56 > /**
57 > * Invokes a server-defined {@link ChangesetOperation} against a changeset,
58 > * a single file, or a line range.
59 > *
60 > * The server validates that `operationId` exists in the changeset's
61 > * current `operations` list and that the requested `target.kind` is
62 > * contained in the operation's `scopes`. Invalid combinations result in a
63 > * JSON-RPC error.
64 > *
65 > * State changes resulting from invocation flow back through the normal
66 > * `changeset/*` action stream on the relevant changeset URIs. Clients
67 > * SHOULD NOT synthesise local optimistic changes for invocations unless
68 > * the server explicitly opts in via a future capability.
69 > *
70 > * @category Commands
71 > * @method invokeChangesetOperation
72 > * @direction Client → Server
73 > * @messageType Request
74 > * @version 2
75 > */
76 > export interface InvokeChangesetOperationParams extends BaseParams {
77 > /** The expanded changeset URI. */
78 > channel: URI;
79 > /** Matches {@link ChangesetOperation.id} from the changeset's `operations` list. */
80 > operationId: string;
81 > /**
82 > * Target of the operation. Required iff the chosen scope is
83 > * `'resource'` or `'range'`. Omit for changeset-scoped operations.
84 > */
85 > target?: ChangesetOperationTarget;
86 > }
87 >
88 > /**
89 > * Result of the {@link InvokeChangesetOperationParams | `invokeChangesetOperation`}
90 > * command.
91 > *
92 > * Success is implicit: the server returns this result when it accepted
93 > * the operation. Failure is signalled by rejecting the JSON-RPC request
94 > * with an appropriate error code, not by any field on this result. The
95 > * operation MAY still produce subsequent failure feedback through the
96 > * {@link ChangesetStatusChangedAction | `changeset/statusChanged`} stream.
97 > *
98 > * @category Commands
99 > */
100 > export interface InvokeChangesetOperationResult {
101 > /** Optional human-readable message describing the result. */
102 > message?: StringOrMarkdown;
103 > /** Optional follow-up: a URI to open (e.g. a PR), a content ref, etc. */
104 > followUp?: ChangesetOperationFollowUp;
105 > }
src/vs/workbench/services/configurationResolver/common/configurationResolverExpression.ts 105 covered LOC · 13 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- configurationResolverExpression.ts
2 > * Copyright (c) Microsoft 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 { isLinux, isMacintosh, isWindows } from '../../../../base/common/platform.js';
8 > import { ConfiguredInput } from './configurationResolver.js';
9 >
10 > /** A replacement found in the object, as ${name} or ${name:arg} */
11 > export type Replacement = {
12 > /** ${name:arg} */
13 > id: string;
14 > /** The `name:arg` in ${name:arg} */
15 > inner: string;
16 > /** The `name` in ${name:arg} */
17 > name: string;
18 > /** The `arg` in ${name:arg} */
19 > arg?: string;
20 > };
21 >
22 > interface IConfigurationResolverExpression<T> {
23 > /**
24 > * Gets the replacements which have not yet been
25 > * resolved.
26 > */
27 > unresolved(): Iterable<Replacement>;
28 >
29 > /**
30 > * Gets the replacements which have been resolved.
31 > */
32 > resolved(): Iterable<[Replacement, IResolvedValue]>;
33 >
34 > /**
35 > * Resolves a replacement into the string value.
36 > * If the value is undefined, the original variable text will be preserved.
37 > */
38 > resolve(replacement: Replacement, data: string | IResolvedValue): void;
39 >
40 > /**
41 > * Returns the complete object. Any unresolved replacements are left intact.
42 > */
43 > toObject(): T;
44 > }
45 >
46 > type PropertyLocation = {
47 > object: any;
48 > propertyName: string | number;
49 > replaceKeyName?: boolean;
50 > };
51 >
52 > export interface IResolvedValue {
53 > value: string | undefined;
54 >
55 > /** Present when the variable is resolved from an input field. */
56 > input?: ConfiguredInput;
57 > }
58 >
59 > interface IReplacementLocation {
60 > replacement: Replacement;
61 > locations: PropertyLocation[];
62 > resolved?: IResolvedValue;
63 > }
64 >
65 > export class ConfigurationResolverExpression<T> implements IConfigurationResolverExpression<T> {
66 > public static readonly VARIABLE_LHS = '${';
67 >
68 > private readonly locations = new Map<string, IReplacementLocation>();
69 > private root: T;
70 > private stringRoot: boolean;
71 > /**
72 > * Callbacks when a new replacement is made, so that nested resolutions from
73 > * `expr.unresolved()` can be fulfilled in the same iteration.
74 > */
75 > private newReplacementNotifiers = new Set<(r: Replacement) => void>();
76 >
77 > private constructor(object: T) {
78 // If the input is a string, wrap it in an object so we can use the same logic
79 if (typeof object === 'string') {
86 }
87 }
89 > /**
90 > * Creates a new {@link ConfigurationResolverExpression} from an object.
91 > * Note that platform-specific keys (i.e. `windows`, `osx`, `linux`) are
92 > * applied during parsing.
93 > */
94 > public static parse<T>(object: T): ConfigurationResolverExpression<T> {
95 if (object instanceof ConfigurationResolverExpression) {
96 return object;
102 return expr;
103 }
105 > private applyPlatformSpecificKeys() {
106 // eslint-disable-next-line local/code-no-any-casts
107 const config = this.root as any; // already cloned by ctor, safe to change
116 delete config.linux;
117 }
119 > private parseVariable(str: string, start: number): { replacement: Replacement; end: number } | undefined {
120 if (str[start] !== '$' || str[start + 1] !== '{') {
121 return undefined;
185 }
186 }
188 > private parseString(object: any, propertyName: string | number, value: string, replaceKeyName?: boolean, replacementPath?: string[]): void {
189 let pos = 0;
190 while (pos < value.length) {
215 }
216 }
218 > public *unresolved(): Iterable<Replacement> {
219 const newReplacements = new Map<string, Replacement>();
220 const notifier = (replacement: Replacement) => {
243 this.newReplacementNotifiers.delete(notifier);
244 }
246 > public resolved(): Iterable<[Replacement, IResolvedValue]> {
247 return Iterable.map(Iterable.filter(this.locations.values(), l => !!l.resolved), l => [l.replacement, l.resolved!]);
248 }
250 > public resolve(replacement: Replacement, data: string | IResolvedValue): void {
251 if (typeof data !== 'object') {
252 data = { value: String(data) };
266 }
267 }
269 > private _resolveAtLocation(replacement: Replacement, { replaceKeyName, propertyName, object }: PropertyLocation, data: IResolvedValue, path: string[] = []) {
270 if (data.value === undefined) {
271 return;
290 path.pop();
291 }
293 > private _renameKeyInLocations(obj: object, oldKey: string, newKey: string) {
294 for (const location of this.locations.values()) {
295 for (const loc of location.locations) {
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/model/prefixSumComputer.ts 103 covered LOC · 20 ranges

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- htmlContent.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { illegalArgument } from './errors.js';
7 > import { escapeIcons } from './iconLabels.js';
8 > import { Schemas } from './network.js';
9 > import { isEqual } from './resources.js';
10 > import { escapeRegExpCharacters } from './strings.js';
11 > import { URI, UriComponents } from './uri.js';
12 >
13 > export interface MarkdownStringTrustedOptions {
14 > readonly enabledCommands: readonly string[];
15 > }
16 >
17 > export interface IMarkdownString {
18 > readonly value: string;
19 > readonly isTrusted?: boolean | MarkdownStringTrustedOptions;
20 > readonly supportThemeIcons?: boolean;
21 > readonly supportHtml?: boolean;
22 > /** @internal */
23 > readonly supportAlertSyntax?: boolean;
24 > readonly baseUri?: UriComponents;
25 > uris?: { [href: string]: UriComponents };
26 > }
27 >
28 > export const enum MarkdownStringTextNewlineStyle {
29 > Paragraph = 0,
30 > Break = 1,
31 > }
32 >
33 > export class MarkdownString implements IMarkdownString {
34 >
35 > public value: string;
36 > public isTrusted?: boolean | MarkdownStringTrustedOptions;
37 > public supportThemeIcons?: boolean;
38 > public supportHtml?: boolean;
39 > public supportAlertSyntax?: boolean;
40 > public baseUri?: URI;
41 > public uris?: { [href: string]: UriComponents } | undefined;
42 >
43 > public static lift(dto: IMarkdownString): MarkdownString {
44 const markdownString = new MarkdownString(dto.value, dto);
45 markdownString.uris = dto.uris;
47 return markdownString;
48 }
50 > constructor(
51 value: string = '',
52 isTrustedOrOptions: boolean | { isTrusted?: boolean | MarkdownStringTrustedOptions; supportThemeIcons?: boolean; supportHtml?: boolean; supportAlertSyntax?: boolean } = false,
70 }
71 }
73 > appendText(value: string, newlineStyle: MarkdownStringTextNewlineStyle = MarkdownStringTextNewlineStyle.Paragraph): MarkdownString {
74 this.value += escapeMarkdownSyntaxTokens(this.supportThemeIcons ? escapeIcons(value) : value) // CodeQL [SM02383] The Markdown is fully sanitized after being rendered.
75 .replace(/([ \t]+)/g, (_match, g1) => '&nbsp;'.repeat(g1.length)) // CodeQL [SM02383] The Markdown is fully sanitized after being rendered.
79 return this;
80 }
82 > appendMarkdown(value: string): MarkdownString {
83 this.value += value;
84 return this;
85 }
87 > appendCodeblock(langId: string, code: string): MarkdownString {
88 this.value += `\n${appendEscapedMarkdownCodeBlockFence(code, langId)}\n`;
89 return this;
90 }
92 > appendLink(target: URI | string, label: string, title?: string): MarkdownString {
93 this.value += '[';
94 this.value += this._escape(label, ']');
101 return this;
102 }
104 > private _escape(value: string, ch: string): string {
105 const r = new RegExp(escapeRegExpCharacters(ch), 'g');
106 return value.replace(r, (match, offset) => {
112 });
113 }
114 > } htmlContent.ts
115 >
116 > export function isEmptyMarkdownString(oneOrMany: IMarkdownString | IMarkdownString[] | null | undefined): boolean {
117 if (isMarkdownString(oneOrMany)) {
118 return !oneOrMany.value;
123 }
124 }
126 > export function isMarkdownString(thing: unknown): thing is IMarkdownString {
127 if (thing instanceof MarkdownString) {
128 return true;
135 return false;
136 }
138 > export function markdownStringEqual(a: IMarkdownString, b: IMarkdownString): boolean {
139 if (a === b) {
140 return true;
150 }
151 }
153 > export function escapeMarkdownSyntaxTokens(text: string): string {
154 // escape markdown syntax tokens: http://daringfireball.net/projects/markdown/syntax#backslash
155 return text
157 .replace(/^([ \t]*)-/gm, '$1\\-'); // CodeQL [SM02383] Backslash is escaped in the character class
158 }
160 > /**
161 > * Escapes only the characters that would break out of markdown link text
162 > * (`[label](url)`) syntax: `\` and `]`. Use this when the escaped string is
163 > * displayed as the visible label of a link, since renderers that extract the
164 > * link text without re-parsing markdown (e.g. the chat inline anchor / skill
165 > * pill) would otherwise show full `escapeMarkdownSyntaxTokens` backslashes
166 > * (`\-`, `\.`, ...) verbatim.
167 > */
168 > export function escapeMarkdownLinkLabel(text: string): string {
169 return text.replace(/[\\\]]/g, '\\$&');
170 }
172 > /**
173 > * @see https://github.com/microsoft/vscode/issues/193746
174 > */
175 > export function appendEscapedMarkdownCodeBlockFence(code: string, langId: string) {
176 const longestFenceLength =
177 code.match(/^`+/gm)?.reduce((a, b) => (a.length > b.length ? a : b)).length ??
187 ].join('\n');
188 }
190 > /**
191 > * Wraps arbitrary text in a markdown inline code span using a backtick fence
192 > * long enough to safely contain any backtick sequences present in the text.
193 > *
194 > * Backticks inside an inline code span cannot be backslash-escaped per the
195 > * CommonMark spec — the only safe way is to choose a delimiter run longer
196 > * than any run of backticks in the content (and pad with spaces if the
197 > * content begins or ends with a backtick).
198 > */
199 > export function appendEscapedMarkdownInlineCode(text: string): string {
200 const longestBacktickRun = Math.max(0, ...(text.match(/`+/g) ?? []).map(m => m.length));
201 const fence = '`'.repeat(longestBacktickRun + 1);
204 return `${fence}${content}${fence}`;
205 }
207 > export function escapeDoubleQuotes(input: string) {
208 return input.replace(/"/g, '&quot;');
209 }
211 > export function removeMarkdownEscapes(text: string): string {
212 if (!text) {
213 return text;
215 return text.replace(/\\([\\`*_{}[\]()#+\-.!~])/g, '$1');
216 }
218 > export function parseHrefAndDimensions(href: string): { href: string; dimensions: string[] } {
219 const dimensions: string[] = [];
220 const splitted = href.split('|').map(s => s.trim());
237 return { href, dimensions };
238 }
240 > export function createMarkdownLink(text: string, href: string, title?: string, escapeTokens = true): string {
241 return `[${escapeTokens ? escapeMarkdownSyntaxTokens(text) : text}](${href}${title ? ` "${escapeMarkdownSyntaxTokens(title)}"` : ''})`;
242 }
244 > export function createMarkdownCommandLink(command: { text: string; id: string; arguments?: unknown[]; tooltip: string }, escapeTokens = true): string {
245 const uri = createCommandUri(command.id, ...(command.arguments || [])).toString();
246 return createMarkdownLink(command.text, uri, command.tooltip, escapeTokens);
247 }
249 > export function createCommandUri(commandId: string, ...commandArgs: unknown[]): URI {
250 return URI.from({
251 scheme: Schemas.command,
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/workbench/services/configuration/common/configuration.ts 101 covered LOC · 1 range

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 { ConfigurationScope } from '../../../../platform/configuration/common/configurationRegistry.js';
7 > import { URI } from '../../../../base/common/uri.js';
8 > import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
9 > import { refineServiceDecorator } from '../../../../platform/instantiation/common/instantiation.js';
10 > import { Event } from '../../../../base/common/event.js';
11 > import { ResourceMap } from '../../../../base/common/map.js';
12 > import { IAnyWorkspaceIdentifier } from '../../../../platform/workspace/common/workspace.js';
13 >
14 > export const FOLDER_CONFIG_FOLDER_NAME = '.vscode';
15 > export const FOLDER_SETTINGS_NAME = 'settings';
16 > export const FOLDER_SETTINGS_PATH = `${FOLDER_CONFIG_FOLDER_NAME}/${FOLDER_SETTINGS_NAME}.json`;
17 >
18 > export const defaultSettingsSchemaId = 'vscode://schemas/settings/default';
19 > export const userSettingsSchemaId = 'vscode://schemas/settings/user';
20 > export const profileSettingsSchemaId = 'vscode://schemas/settings/profile';
21 > export const machineSettingsSchemaId = 'vscode://schemas/settings/machine';
22 > export const workspaceSettingsSchemaId = 'vscode://schemas/settings/workspace';
23 > export const folderSettingsSchemaId = 'vscode://schemas/settings/folder';
24 > export const launchSchemaId = 'vscode://schemas/launch';
25 > export const tasksSchemaId = 'vscode://schemas/tasks';
26 > export const mcpSchemaId = 'vscode://schemas/mcp';
27 >
28 > export const APPLICATION_SCOPES = [ConfigurationScope.APPLICATION, ConfigurationScope.APPLICATION_MACHINE];
29 > export const PROFILE_SCOPES = [ConfigurationScope.MACHINE, ConfigurationScope.WINDOW, ConfigurationScope.RESOURCE, ConfigurationScope.LANGUAGE_OVERRIDABLE, ConfigurationScope.MACHINE_OVERRIDABLE];
30 > export const LOCAL_MACHINE_PROFILE_SCOPES = [ConfigurationScope.WINDOW, ConfigurationScope.RESOURCE, ConfigurationScope.LANGUAGE_OVERRIDABLE];
31 > export const LOCAL_MACHINE_SCOPES = [ConfigurationScope.APPLICATION, ...LOCAL_MACHINE_PROFILE_SCOPES];
32 > export const REMOTE_MACHINE_SCOPES = [ConfigurationScope.MACHINE, ConfigurationScope.APPLICATION_MACHINE, ConfigurationScope.WINDOW, ConfigurationScope.RESOURCE, ConfigurationScope.LANGUAGE_OVERRIDABLE, ConfigurationScope.MACHINE_OVERRIDABLE];
33 > export const WORKSPACE_SCOPES = [ConfigurationScope.WINDOW, ConfigurationScope.RESOURCE, ConfigurationScope.LANGUAGE_OVERRIDABLE, ConfigurationScope.MACHINE_OVERRIDABLE];
34 > export const FOLDER_SCOPES = [ConfigurationScope.RESOURCE, ConfigurationScope.LANGUAGE_OVERRIDABLE, ConfigurationScope.MACHINE_OVERRIDABLE];
35 >
36 > export const TASKS_CONFIGURATION_KEY = 'tasks';
37 > export const LAUNCH_CONFIGURATION_KEY = 'launch';
38 > export const MCP_CONFIGURATION_KEY = 'mcp';
39 >
40 > export const WORKSPACE_STANDALONE_CONFIGURATIONS = Object.create(null);
41 > WORKSPACE_STANDALONE_CONFIGURATIONS[TASKS_CONFIGURATION_KEY] = `${FOLDER_CONFIG_FOLDER_NAME}/${TASKS_CONFIGURATION_KEY}.json`;
42 > WORKSPACE_STANDALONE_CONFIGURATIONS[LAUNCH_CONFIGURATION_KEY] = `${FOLDER_CONFIG_FOLDER_NAME}/${LAUNCH_CONFIGURATION_KEY}.json`;
43 > WORKSPACE_STANDALONE_CONFIGURATIONS[MCP_CONFIGURATION_KEY] = `${FOLDER_CONFIG_FOLDER_NAME}/${MCP_CONFIGURATION_KEY}.json`;
44 > export const USER_STANDALONE_CONFIGURATIONS = Object.create(null);
45 > USER_STANDALONE_CONFIGURATIONS[TASKS_CONFIGURATION_KEY] = `${TASKS_CONFIGURATION_KEY}.json`;
46 > USER_STANDALONE_CONFIGURATIONS[MCP_CONFIGURATION_KEY] = `${MCP_CONFIGURATION_KEY}.json`;
47 >
48 > export type ConfigurationKey = { type: 'defaults' | 'user' | 'workspaces' | 'folder'; key: string };
49 >
50 > export interface IConfigurationCache {
51 >
52 > needsCaching(resource: URI): boolean;
53 > read(key: ConfigurationKey): Promise<string>;
54 > write(key: ConfigurationKey, content: string): Promise<void>;
55 > remove(key: ConfigurationKey): Promise<void>;
56 >
57 > }
58 >
59 > export type RestrictedSettings = {
60 > default: ReadonlyArray<string>;
61 > application?: ReadonlyArray<string>;
62 > userLocal?: ReadonlyArray<string>;
63 > userRemote?: ReadonlyArray<string>;
64 > workspace?: ReadonlyArray<string>;
65 > workspaceFolder?: ResourceMap<ReadonlyArray<string>>;
66 > };
67 >
68 > export const IWorkbenchConfigurationService = refineServiceDecorator<IConfigurationService, IWorkbenchConfigurationService>(IConfigurationService);
69 > export interface IWorkbenchConfigurationService extends IConfigurationService {
70 > /**
71 > * Restricted settings defined in each configuration target
72 > */
73 > readonly restrictedSettings: RestrictedSettings;
74 >
75 > /**
76 > * Event that triggers when the restricted settings changes
77 > */
78 > readonly onDidChangeRestrictedSettings: Event<RestrictedSettings>;
79 >
80 > /**
81 > * A promise that resolves when the remote configuration is loaded in a remote window.
82 > * The promise is resolved immediately if the window is not remote.
83 > */
84 > whenRemoteConfigurationLoaded(): Promise<void>;
85 >
86 > /**
87 > * Initialize configuration service for the given workspace
88 > * @param arg workspace Identifier
89 > */
90 > initialize(arg: IAnyWorkspaceIdentifier): Promise<void>;
91 >
92 > /**
93 > * Returns true if the setting can be applied for all profiles otherwise false.
94 > * @param setting
95 > */
96 > isSettingAppliedForAllProfiles(setting: string): boolean;
97 > }
98 >
99 > export const TASKS_DEFAULT = '{\n\t\"version\": \"2.0.0\",\n\t\"tasks\": []\n}';
100 >
101 > export const APPLY_ALL_PROFILES_SETTING = 'workbench.settings.applyToAllProfiles';
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/secrets/common/secrets.ts 99 covered LOC · 15 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- secrets.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { SequencerByKey } from '../../../base/common/async.js';
7 > import { IEncryptionService } from '../../encryption/common/encryptionService.js';
8 > import { createDecorator } from '../../instantiation/common/instantiation.js';
9 > import { IStorageService, IStorageValueChangeEvent, InMemoryStorageService, StorageScope, StorageTarget } from '../../storage/common/storage.js';
10 > import { Emitter, Event } from '../../../base/common/event.js';
11 > import { ILogService } from '../../log/common/log.js';
12 > import { Disposable, DisposableStore } from '../../../base/common/lifecycle.js';
13 > import { Lazy } from '../../../base/common/lazy.js';
14 > import { isWindows } from '../../../base/common/platform.js';
15 >
16 > /**
17 > * The storage key prefix used for all secrets.
18 > */
19 > export const SECRET_STORAGE_PREFIX = 'secret://';
20 >
21 > /**
22 > * Builds the full storage key for a secret.
23 > */
24 > export function secretStorageKey(key: string): string {
25 return `${SECRET_STORAGE_PREFIX}${key}`;
26 }
27 > secrets.ts
28 > /**
29 > * Reads an encrypted secret from storage and decrypts it.
30 > * @param key The secret key (without the `secret://` prefix).
31 > * @param storageGet A function that reads the encrypted value from storage given a full storage key.
32 > * @param decrypt A function that decrypts the encrypted value.
33 > * @param logService Optional logger for trace output.
34 > */
35 export async function readEncryptedSecret(
36 key: string,
51 return result;
52 }
53 > secrets.ts
54 > /**
55 > * Encrypts a secret value and writes it to storage.
56 > * @param key The secret key (without the `secret://` prefix).
57 > * @param value The plaintext secret value.
58 > * @param storageSet A function that writes the encrypted value to storage given a full storage key.
59 > * @param encrypt A function that encrypts the plaintext value.
60 > * @param logService Optional logger for trace output.
61 > */
62 export async function writeEncryptedSecret(
63 key: string,
74 logService?.trace('[secrets] stored encrypted secret for key:', fullKey);
75 }
76 > secrets.ts
77 > /**
78 > * Secret keys that should be shared between the VS Code app and the agents app.
79 > * When the agents app starts and doesn't have these secrets, it requests them
80 > * from VS Code via crossAppIPC.
81 > */
82 > export const CROSS_APP_SHARED_SECRET_KEYS: readonly string[] = [
83 > '{"extensionId":"vscode.github-authentication","key":"github.auth"}',
84 > ];
85 >
86 > export const ISecretStorageService = createDecorator<ISecretStorageService>('secretStorageService');
87 >
88 > export interface ISecretStorageProvider {
89 > type: 'in-memory' | 'persisted' | 'unknown';
90 > get(key: string): Promise<string | undefined>;
91 > set(key: string, value: string): Promise<void>;
92 > delete(key: string): Promise<void>;
93 > keys?(): Promise<string[]>;
94 > }
95 >
96 > export interface ISecretStorageService extends ISecretStorageProvider {
97 > readonly _serviceBrand: undefined;
98 > readonly onDidChangeSecret: Event<string>;
99 > }
100 >
101 > export class BaseSecretStorageService extends Disposable implements ISecretStorageService {
102 > declare readonly _serviceBrand: undefined;
103 >
104 > protected readonly onDidChangeSecretEmitter = this._register(new Emitter<string>());
105 > readonly onDidChangeSecret: Event<string> = this.onDidChangeSecretEmitter.event;
106 >
107 > protected readonly _sequencer = new SequencerByKey<string>();
108 >
109 > private _type: 'in-memory' | 'persisted' | 'unknown' = 'unknown';
110 >
111 > private readonly _onDidChangeValueDisposable = this._register(new DisposableStore());
112 >
113 > constructor(
114 private readonly _useInMemoryStorage: boolean,
115 @IStorageService private _storageService: IStorageService,
133
134 private _lazyStorageService: Lazy<Promise<IStorageService>> = new Lazy(() => this.initialize());
135 > protected get resolvedStorageService() { secrets.ts
136 return this._lazyStorageService.value;
137 }
138 > secrets.ts
139 > get(key: string): Promise<string | undefined> {
140 return this._sequencer.queue(key, async () => {
141 const storageService = await this.resolvedStorageService;
156 });
157 }
158 > secrets.ts
159 > set(key: string, value: string): Promise<void> {
160 return this._sequencer.queue(key, async () => {
161 const storageService = await this.resolvedStorageService;
176 });
177 }
178 > secrets.ts
179 > delete(key: string): Promise<void> {
180 return this._sequencer.queue(key, async () => {
181 const storageService = await this.resolvedStorageService;
188 });
189 }
190 > secrets.ts
191 > keys(): Promise<string[]> {
192 return this._sequencer.queue('__keys__', async () => {
193 const storageService = await this.resolvedStorageService;
198 });
199 }
200 > secrets.ts
201 > private getValueFromStorage(key: string, fullKey: string, storageService: IStorageService): string | undefined {
202 if (this.useSharedStorage(key)) {
203 this._logService.trace(`[SecretStorageService] Fetching value for cross-app shared secret: ${fullKey}`);
206 return storageService.get(fullKey, StorageScope.APPLICATION);
207 }
208 > secrets.ts
209 > private setValueInStorage(key: string, fullKey: string, value: string, storageService: IStorageService): void {
210 if (this.useSharedStorage(key)) {
211 this._logService.trace(`[SecretStorageService] Setting value for cross-app shared secret: ${fullKey}`);
215 storageService.store(fullKey, value, StorageScope.APPLICATION, StorageTarget.MACHINE);
216 }
217 > secrets.ts
218 > private async initialize(): Promise<IStorageService> {
219 let storageService;
220 if (!this._useInMemoryStorage && await this._encryptionService.isEncryptionAvailable()) {
241 return storageService;
242 }
243 > secrets.ts
244 > protected reinitialize(): void {
245 this._lazyStorageService = new Lazy(() => this.initialize());
246 }
247 > secrets.ts
248 > private onDidChangeValue(key: string): void {
249 if (!key.startsWith(SECRET_STORAGE_PREFIX)) {
250 return;
256 this.onDidChangeSecretEmitter.fire(secretKey);
257 }
258 > } secrets.ts
src/vs/workbench/services/remote/common/remoteAgentService.ts 99 covered LOC · 2 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- remoteAgentService.ts
2 > * Copyright (c) Microsoft 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 { RemoteAgentConnectionContext, IRemoteAgentEnvironment } from '../../../../platform/remote/common/remoteAgentEnvironment.js';
8 > import { IChannel, IServerChannel } from '../../../../base/parts/ipc/common/ipc.js';
9 > import { IDiagnosticInfoOptions, IDiagnosticInfo } from '../../../../platform/diagnostics/common/diagnostics.js';
10 > import { Event } from '../../../../base/common/event.js';
11 > import { PersistentConnectionEvent } from '../../../../platform/remote/common/remoteAgentConnection.js';
12 > import { ITelemetryData, TelemetryLevel } from '../../../../platform/telemetry/common/telemetry.js';
13 > import { timeout } from '../../../../base/common/async.js';
14 >
15 > export const IRemoteAgentService = createDecorator<IRemoteAgentService>('remoteAgentService');
16 >
17 > export interface IRemoteAgentService {
18 > readonly _serviceBrand: undefined;
19 >
20 > getConnection(): IRemoteAgentConnection | null;
21 > /**
22 > * Get the remote environment. In case of an error, returns `null`.
23 > */
24 > getEnvironment(): Promise<IRemoteAgentEnvironment | null>;
25 > /**
26 > * Get the remote environment. Can return an error.
27 > */
28 > getRawEnvironment(): Promise<IRemoteAgentEnvironment | null>;
29 > /**
30 > * Get exit information for a remote extension host.
31 > */
32 > getExtensionHostExitInfo(reconnectionToken: string): Promise<IExtensionHostExitInfo | null>;
33 >
34 > /**
35 > * Gets the round trip time from the remote extension host. Note that this
36 > * may be delayed if the extension host is busy.
37 > */
38 > getRoundTripTime(): Promise<number | undefined>;
39 >
40 > /**
41 > * Gracefully ends the current connection, if any.
42 > */
43 > endConnection(): Promise<void>;
44 >
45 > getDiagnosticInfo(options: IDiagnosticInfoOptions): Promise<IDiagnosticInfo | undefined>;
46 > updateTelemetryLevel(telemetryLevel: TelemetryLevel): Promise<void>;
47 > logTelemetry(eventName: string, data?: ITelemetryData): Promise<void>;
48 > flushTelemetry(): Promise<void>;
49 > }
50 >
51 > export interface IExtensionHostExitInfo {
52 > code: number;
53 > signal: string;
54 > }
55 >
56 > export interface IRemoteAgentConnection {
57 > readonly remoteAuthority: string;
58 >
59 > readonly onReconnecting: Event<void>;
60 > readonly onDidStateChange: Event<PersistentConnectionEvent>;
61 >
62 > end(): Promise<void>;
63 > dispose(): void;
64 > getChannel<T extends IChannel>(channelName: string): T;
65 > withChannel<T extends IChannel, R>(channelName: string, callback: (channel: T) => Promise<R>): Promise<R>;
66 > registerChannel<T extends IServerChannel<RemoteAgentConnectionContext>>(channelName: string, channel: T): void;
67 > getInitialConnectionTimeMs(): Promise<number>;
68 > updateGraceTime(graceTime: number): void;
69 > }
70 >
71 > export interface IRemoteConnectionLatencyMeasurement {
72 >
73 > readonly initial: number | undefined;
74 > readonly current: number;
75 > readonly average: number;
76 >
77 > readonly high: boolean;
78 > }
79 >
80 > export const remoteConnectionLatencyMeasurer = new class {
81 >
82 > readonly maxSampleCount = 5;
83 > readonly sampleDelay = 2000;
84 >
85 > readonly initial: number[] = [];
86 > readonly maxInitialCount = 3;
87 >
88 > readonly average: number[] = [];
89 > readonly maxAverageCount = 100;
90 >
91 > readonly highLatencyMultiple = 2;
92 > readonly highLatencyMinThreshold = 500;
93 > readonly highLatencyMaxThreshold = 1500;
94 >
95 > lastMeasurement: IRemoteConnectionLatencyMeasurement | undefined = undefined;
96 > get latency() { return this.lastMeasurement; }
97 >
98 > async measure(remoteAgentService: IRemoteAgentService): Promise<IRemoteConnectionLatencyMeasurement | undefined> {
99 let currentLatency = Infinity;
100
src/vs/base/common/sseParser.ts 98 covered LOC · 9 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- sseParser.ts
2 > * Copyright (c) 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 > * Parser for Server-Sent Events (SSE) streams according to the HTML specification.
8 > * @see https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation
9 > */
10 >
11 > /**
12 > * Represents an event dispatched from an SSE stream.
13 > */
14 > export interface ISSEEvent {
15 > /**
16 > * The event type. If not specified, the type is "message".
17 > */
18 > type: string;
19 >
20 > /**
21 > * The event data.
22 > */
23 > data: string;
24 >
25 > /**
26 > * The last event ID, used for reconnection.
27 > */
28 > id?: string;
29 >
30 > /**
31 > * Reconnection time in milliseconds.
32 > */
33 > retry?: number;
34 > }
35 >
36 > /**
37 > * Callback function type for event dispatch.
38 > */
39 > export type SSEEventHandler = (event: ISSEEvent) => void;
40 >
41 > const enum Chr {
42 > CR = 13, // '\r'
43 > LF = 10, // '\n'
44 > COLON = 58, // ':'
45 > SPACE = 32, // ' '
46 > }
47 >
48 > /**
49 > * Parser for Server-Sent Events (SSE) streams.
50 > */
51 > export class SSEParser {
52 > private dataBuffer = '';
53 > private eventTypeBuffer = '';
54 > private currentEventId?: string;
55 > private lastEventIdBuffer?: string;
56 > private reconnectionTime?: number;
57 > private buffer: Uint8Array[] = [];
58 > private endedOnCR = false;
59 > private readonly onEventHandler: SSEEventHandler;
60 > private readonly decoder: TextDecoder;
61 > /**
62 > * Creates a new SSE parser.
63 > * @param onEvent The callback to invoke when an event is dispatched.
64 > */
65 > constructor(onEvent: SSEEventHandler) {
66 this.onEventHandler = onEvent;
67 this.decoder = new TextDecoder('utf-8');
68 }
70 > /**
71 > * Gets the last event ID received by this parser.
72 > */
73 > public getLastEventId(): string | undefined {
74 return this.lastEventIdBuffer;
75 }
76 > /** sseParser.ts
77 > * Gets the reconnection time in milliseconds, if one was specified by the server.
78 > */
79 > public getReconnectionTime(): number | undefined {
80 return this.reconnectionTime;
81 }
83 > /**
84 > * Feeds a chunk of the SSE stream to the parser.
85 > * @param chunk The chunk to parse as a Uint8Array of UTF-8 encoded data.
86 > */
87 > public feed(chunk: Uint8Array): void {
88 if (chunk.length === 0) {
89 return;
125 }
126 }
127 > /** sseParser.ts
128 > * Processes a single line from the SSE stream.
129 > */
130 > private processLine(line: string): void {
131 if (!line.length) {
132 this.dispatchEvent();
160 this.processField(field, value);
161 }
162 > /** sseParser.ts
163 > * Processes a field with the given name and value.
164 > */
165 > private processField(field: string, value: string): void {
166 switch (field) {
167 case 'event':
194 }
195 }
196 > /** sseParser.ts
197 > * Dispatches the event based on the current buffer states.
198 > */
199 > private dispatchEvent(): void {
200 // If the data buffer is empty, reset the buffers and return
201 if (this.dataBuffer === '') {
231 this.reset();
232 }
233 > sseParser.ts
234 > /**
235 > * Resets the parser state.
236 > */
237 > public reset(): void {
238 this.dataBuffer = '';
239 this.eventTypeBuffer = '';
241 // Note: lastEventIdBuffer is not reset as it's used for reconnection
242 }
243 > } sseParser.ts
244
245
src/vs/workbench/api/common/extHostConfiguration.ts 97 covered LOC · 19 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostConfiguration.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { mixin, deepClone } from '../../../base/common/objects.js';
7 > import { Event, Emitter } from '../../../base/common/event.js';
8 > import type * as vscode from 'vscode';
9 > import { ExtHostWorkspace, IExtHostWorkspace } from './extHostWorkspace.js';
10 > import { ExtHostConfigurationShape, MainThreadConfigurationShape, IConfigurationInitData, MainContext } from './extHost.protocol.js';
11 > import { ConfigurationTarget as ExtHostConfigurationTarget } from './extHostTypes.js';
12 > import { ConfigurationTarget, IConfigurationChange, IConfigurationData, IConfigurationOverrides } from '../../../platform/configuration/common/configuration.js';
13 > import { Configuration, ConfigurationChangeEvent } from '../../../platform/configuration/common/configurationModels.js';
14 > import { ConfigurationScope, OVERRIDE_PROPERTY_REGEX } from '../../../platform/configuration/common/configurationRegistry.js';
15 > import { isObject } from '../../../base/common/types.js';
16 > import { ExtensionIdentifier, IExtensionDescription } from '../../../platform/extensions/common/extensions.js';
17 > import { Barrier } from '../../../base/common/async.js';
18 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
19 > import { IExtHostRpcService } from './extHostRpcService.js';
20 > import { ILogService } from '../../../platform/log/common/log.js';
21 > import { Workspace } from '../../../platform/workspace/common/workspace.js';
22 > import { URI } from '../../../base/common/uri.js';
23 >
24 function lookUp(tree: unknown, key: string) {
25 if (key) {
33 return undefined;
34 }
36 > export type ConfigurationInspect<T> = {
37 > key: string;
38 >
39 > defaultValue?: T;
40 > globalLocalValue?: T;
41 > globalRemoteValue?: T;
42 > globalValue?: T;
43 > workspaceValue?: T;
44 > workspaceFolderValue?: T;
45 >
46 > defaultLanguageValue?: T;
47 > globalLocalLanguageValue?: T;
48 > globalRemoteLanguageValue?: T;
49 > globalLanguageValue?: T;
50 > workspaceLanguageValue?: T;
51 > workspaceFolderLanguageValue?: T;
52 >
53 > languageIds?: string[];
54 > };
55 >
56 function isUri(thing: unknown): thing is vscode.Uri {
57 return thing instanceof URI;
58 }
60 function isResourceLanguage(thing: unknown): thing is { uri: URI; languageId: string } {
61 return isObject(thing)
64 && typeof (thing as Record<string, unknown>).languageId === 'string';
65 }
67 function isLanguage(thing: unknown): thing is { languageId: string } {
68 return isObject(thing)
71 && typeof (thing as Record<string, unknown>).languageId === 'string';
72 }
74 function isWorkspaceFolder(thing: unknown): thing is vscode.WorkspaceFolder {
75 return isObject(thing)
78 && (!(thing as Record<string, unknown>).index || typeof (thing as Record<string, unknown>).index === 'number');
79 }
81 function scopeToOverrides(scope: vscode.ConfigurationScope | undefined | null): IConfigurationOverrides | undefined {
82 if (isUri(scope)) {
97 return undefined;
98 }
100 > export class ExtHostConfiguration implements ExtHostConfigurationShape {
101 >
102 > readonly _serviceBrand: undefined;
103 >
104 > private readonly _proxy: MainThreadConfigurationShape;
105 > private readonly _logService: ILogService;
106 > private readonly _extHostWorkspace: ExtHostWorkspace;
107 > private readonly _barrier: Barrier;
108 > private _actual: ExtHostConfigProvider | null;
109 >
110 > constructor(
111 @IExtHostRpcService extHostRpc: IExtHostRpcService,
112 @IExtHostWorkspace extHostWorkspace: IExtHostWorkspace,
119 this._actual = null;
120 }
122 > public getConfigProvider(): Promise<ExtHostConfigProvider> {
123 return this._barrier.wait().then(_ => this._actual!);
124 }
126 > $initializeConfiguration(data: IConfigurationInitData): void {
127 this._actual = new ExtHostConfigProvider(this._proxy, this._extHostWorkspace, data, this._logService);
128 // Push the config provider into ExtHostWorkspace so it can read settings synchronously
131 this._barrier.open();
132 }
134 > $acceptConfigurationChanged(data: IConfigurationInitData, change: IConfigurationChange): void {
135 this.getConfigProvider().then(provider => provider.$acceptConfigurationChanged(data, change));
136 }
138 >
139 > export class ExtHostConfigProvider {
140 >
141 > private readonly _onDidChangeConfiguration = new Emitter<vscode.ConfigurationChangeEvent>();
142 > private readonly _proxy: MainThreadConfigurationShape;
143 > private readonly _extHostWorkspace: ExtHostWorkspace;
144 > private _configurationScopes: Map<string, ConfigurationScope | undefined>;
145 > private _configuration: Configuration;
146 > private _logService: ILogService;
147 >
148 > constructor(proxy: MainThreadConfigurationShape, extHostWorkspace: ExtHostWorkspace, data: IConfigurationInitData, logService: ILogService) {
149 this._proxy = proxy;
150 this._logService = logService;
153 this._configurationScopes = this._toMap(data.configurationScopes);
154 }
156 > get onDidChangeConfiguration(): Event<vscode.ConfigurationChangeEvent> {
157 return this._onDidChangeConfiguration && this._onDidChangeConfiguration.event;
158 }
160 > $acceptConfigurationChanged(data: IConfigurationInitData, change: IConfigurationChange) {
161 const previous = { data: this._configuration.toData(), workspace: this._extHostWorkspace.workspace };
162 this._configuration = Configuration.parse(data, this._logService);
164 this._onDidChangeConfiguration.fire(this._toConfigurationChangeEvent(change, previous));
165 }
167 > getConfiguration(section?: string, scope?: vscode.ConfigurationScope | null, extensionDescription?: IExtensionDescription): vscode.WorkspaceConfiguration {
168 const overrides = scopeToOverrides(scope) || {};
169 const config = this._toReadonlyValue(this._configuration.getValue(section, overrides, this._extHostWorkspace.workspace));
297 return Object.freeze(result);
298 }
300 > private _toReadonlyValue(result: unknown): unknown {
301 const readonlyProxy = (target: unknown): unknown => {
302 return isObject(target) ?
313 return readonlyProxy(result);
314 }
316 > private _validateConfigurationAccess(key: string, overrides?: IConfigurationOverrides, extensionId?: ExtensionIdentifier): void {
317 const scope = OVERRIDE_PROPERTY_REGEX.test(key) ? ConfigurationScope.RESOURCE : this._configurationScopes.get(key);
318 const extensionIdText = extensionId ? `[${extensionId.value}] ` : '';
330 }
331 }
333 > private _toConfigurationChangeEvent(change: IConfigurationChange, previous: { data: IConfigurationData; workspace: Workspace | undefined }): vscode.ConfigurationChangeEvent {
334 const event = new ConfigurationChangeEvent(change, previous, this._configuration, this._extHostWorkspace.workspace, this._logService);
335 return Object.freeze({
337 });
338 }
340 > private _toMap(scopes: [string, ConfigurationScope | undefined][]): Map<string, ConfigurationScope | undefined> {
341 return scopes.reduce((result, scope) => { result.set(scope[0], scope[1]); return result; }, new Map<string, ConfigurationScope | undefined>());
342 }
344 > }
345 >
346 > export const IExtHostConfiguration = createDecorator<IExtHostConfiguration>('IExtHostConfiguration');
347 > export interface IExtHostConfiguration extends ExtHostConfiguration { }
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/workbench/api/common/extHostTunnelService.ts 94 covered LOC · 17 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostTunnelService.ts
2 > * Copyright (c) Microsoft 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 { Emitter } from '../../../base/common/event.js';
8 > import { Disposable, IDisposable, toDisposable } from '../../../base/common/lifecycle.js';
9 > import * as nls from '../../../nls.js';
10 > import { IExtensionDescription } from '../../../platform/extensions/common/extensions.js';
11 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
12 > import { ILogService } from '../../../platform/log/common/log.js';
13 > import { DisposableTunnel, ProvidedOnAutoForward, ProvidedPortAttributes, RemoteTunnel, TunnelCreationOptions, TunnelOptions, TunnelPrivacyId } from '../../../platform/tunnel/common/tunnel.js';
14 > import { ExtHostTunnelServiceShape, MainContext, MainThreadTunnelServiceShape, PortAttributesSelector, TunnelDto } from './extHost.protocol.js';
15 > import { IExtHostInitDataService } from './extHostInitDataService.js';
16 > import { IExtHostRpcService } from './extHostRpcService.js';
17 > import * as types from './extHostTypes.js';
18 > import { CandidatePort } from '../../services/remote/common/tunnelModel.js';
19 > import * as vscode from 'vscode';
20 >
21 > class ExtensionTunnel extends DisposableTunnel implements vscode.Tunnel { }
22 >
23 > export namespace TunnelDtoConverter {
24 > export function fromApiTunnel(tunnel: vscode.Tunnel): TunnelDto {
25 return {
26 remoteAddress: tunnel.remoteAddress,
31 };
32 }
33 > export function fromServiceTunnel(tunnel: RemoteTunnel): TunnelDto { extHostTunnelService.ts
34 return {
35 remoteAddress: {
43 };
44 }
46 >
47 > export interface Tunnel extends vscode.Disposable {
48 > remote: { port: number; host: string };
49 > localAddress: string;
50 > }
51 >
52 > export interface IExtHostTunnelService extends ExtHostTunnelServiceShape {
53 > readonly _serviceBrand: undefined;
54 > openTunnel(extension: IExtensionDescription, forward: TunnelOptions): Promise<vscode.Tunnel | undefined>;
55 > getTunnels(): Promise<vscode.TunnelDescription[]>;
56 > onDidChangeTunnels: vscode.Event<void>;
57 > setTunnelFactory(provider: vscode.RemoteAuthorityResolver | undefined, managedRemoteAuthority: vscode.ManagedResolvedAuthority | undefined): Promise<IDisposable>;
58 > registerPortsAttributesProvider(portSelector: PortAttributesSelector, provider: vscode.PortAttributesProvider): IDisposable;
59 > registerTunnelProvider(provider: vscode.TunnelProvider, information: vscode.TunnelInformation): Promise<IDisposable>;
60 > hasTunnelProvider(): Promise<boolean>;
61 > }
62 >
63 > export const IExtHostTunnelService = createDecorator<IExtHostTunnelService>('IExtHostTunnelService');
64 >
65 > export class ExtHostTunnelService extends Disposable implements IExtHostTunnelService {
66 > readonly _serviceBrand: undefined;
67 > protected readonly _proxy: MainThreadTunnelServiceShape;
68 > private _forwardPortProvider: ((tunnelOptions: TunnelOptions, tunnelCreationOptions: TunnelCreationOptions, token?: vscode.CancellationToken) => Thenable<vscode.Tunnel | undefined> | undefined) | undefined;
69 > private _showCandidatePort: (host: string, port: number, detail: string) => Thenable<boolean> = () => { return Promise.resolve(true); };
70 > private _extensionTunnels: Map<string, Map<number, { tunnel: vscode.Tunnel; disposeListener: IDisposable }>> = new Map();
71 > private _onDidChangeTunnels: Emitter<void> = this._register(new Emitter<void>());
72 > onDidChangeTunnels: vscode.Event<void> = this._onDidChangeTunnels.event;
73 >
74 > private _providerHandleCounter: number = 0;
75 > private _portAttributesProviders: Map<number, { provider: vscode.PortAttributesProvider; selector: PortAttributesSelector }> = new Map();
76 >
77 > constructor(
78 @IExtHostRpcService extHostRpc: IExtHostRpcService,
79 @IExtHostInitDataService initData: IExtHostInitDataService,
83 this._proxy = extHostRpc.getProxy(MainContext.MainThreadTunnelService);
84 }
86 > async openTunnel(extension: IExtensionDescription, forward: TunnelOptions): Promise<vscode.Tunnel | undefined> {
87 this.logService.trace(`ForwardedPorts: (ExtHostTunnelService) ${extension.identifier.value} called openTunnel API for ${forward.remoteAddress.host}:${forward.remoteAddress.port}.`);
88 const tunnel = await this._proxy.$openTunnel(forward, extension.displayName);
96 return undefined;
97 }
99 > async getTunnels(): Promise<vscode.TunnelDescription[]> {
100 return this._proxy.$getTunnels();
101 }
102 > private nextPortAttributesProviderHandle(): number { extHostTunnelService.ts
103 return this._providerHandleCounter++;
104 }
106 > registerPortsAttributesProvider(portSelector: PortAttributesSelector, provider: vscode.PortAttributesProvider): vscode.Disposable {
107 if (portSelector.portRange === undefined && portSelector.commandPattern === undefined) {
108 this.logService.error('PortAttributesProvider must specify either a portRange or a commandPattern');
117 });
118 }
120 > async $providePortAttributes(handles: number[], ports: number[], pid: number | undefined, commandLine: string | undefined, cancellationToken: vscode.CancellationToken): Promise<ProvidedPortAttributes[]> {
121 const providedAttributes: { providedAttributes: vscode.PortAttributes | null | undefined; port: number }[] = [];
122 for (const handle of handles) {
146 }) : [];
147 }
149 > async $registerCandidateFinder(_enable: boolean): Promise<void> { }
150 >
151 > registerTunnelProvider(provider: vscode.TunnelProvider, information: vscode.TunnelInformation): Promise<IDisposable> {
152 if (this._forwardPortProvider) {
153 throw new Error('A tunnel provider has already been registered. Only the first tunnel provider to be registered will be used.');
170 }));
171 }
173 > hasTunnelProvider(): Promise<boolean> {
174 return this._proxy.$hasTunnelProvider();
175 }
177 > /**
178 > * Applies the tunnel metadata and factory found in the remote authority
179 > * resolver to the tunnel system.
180 > *
181 > * `managedRemoteAuthority` should be be passed if the resolver returned on.
182 > * If this is the case, the tunnel cannot be connected to via a websocket from
183 > * the share process, so a synethic tunnel factory is used as a default.
184 > */
185 > async setTunnelFactory(provider: vscode.RemoteAuthorityResolver | undefined, managedRemoteAuthority: vscode.ManagedResolvedAuthority | undefined): Promise<IDisposable> {
186 // Do not wait for any of the proxy promises here.
187 // It will delay startup and there is nothing that needs to be waited for.
229 });
230 }
232 > protected makeManagedTunnelFactory(_authority: vscode.ManagedResolvedAuthority): vscode.RemoteAuthorityResolver['tunnelFactory'] {
233 return undefined; // may be overridden
234 }
236 > async $closeTunnel(remote: { host: string; port: number }, silent?: boolean): Promise<void> {
237 if (this._extensionTunnels.has(remote.host)) {
238 const hostMap = this._extensionTunnels.get(remote.host)!;
246 }
247 }
249 > async $onDidTunnelsChange(): Promise<void> {
250 this._onDidChangeTunnels.fire();
251 }
253 > async $forwardPort(tunnelOptions: TunnelOptions, tunnelCreationOptions: TunnelCreationOptions): Promise<TunnelDto | string | undefined> {
254 if (this._forwardPortProvider) {
255 try {
285 return undefined;
286 }
288 > async $applyCandidateFilter(candidates: CandidatePort[]): Promise<CandidatePort[]> {
289 const filter = await Promise.all(candidates.map(candidate => this._showCandidatePort(candidate.host, candidate.port, candidate.detail ?? '')));
290 const result = candidates.filter((candidate, index) => filter[index]);
src/vs/platform/agentHost/common/meta/agentToolCallMeta.ts 92 covered LOC · 5 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- agentToolCallMeta.ts
2 > * Copyright (c) Microsoft 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 { Mutable } from '../../../../base/common/types.js';
7 >
8 > /** Anything carrying a tool call's `_meta` bag (persisted state or wire actions). */
9 > interface IHasToolCallMeta {
10 > readonly _meta?: Record<string, unknown>;
11 > }
12 >
13 > /**
14 > * Well-known typed view over a tool call's open `_meta` bag. Producers and
15 > * consumers agree on these keys here so the two sides can't drift; always read
16 > * the bag through {@link readToolCallMeta}, which validates each field and drops
17 > * wrong-typed values.
18 > */
19 > export interface IToolCallMeta {
20 > /**
21 > * VS Code rendering hint. `terminal` routes the call to the command/output
22 > * renderer, `subagent` to the subagent UI, `search` to the search renderer;
23 > * everything else falls through to the generic invocation renderer. Set by
24 > * the agent adapter, never matched on raw tool name by the renderer.
25 > */
26 > readonly toolKind?: ToolKind;
27 > /** Shell language for a `terminal` tool call (drives syntax highlighting). */
28 > readonly language?: string;
29 > /** Short task description for a `subagent` tool call (e.g. "Find related files"). */
30 > readonly subagentDescription?: string;
31 > /** Agent name for a `subagent` tool call (e.g. "explore"). */
32 > readonly subagentAgentName?: string;
33 > /** Chat URI of the subagent this tool call spawns, stamped by the host (see {@link buildSubagentChatUri}); the resource may not be registered yet. */
34 > readonly subagentChatUri?: string;
35 > /** Raw, pre-stringified tool arguments captured for display/debugging. */
36 > readonly toolArguments?: unknown;
37 > /** Originating MCP server name, when the call came from an MCP server. */
38 > readonly mcpServerName?: string;
39 > /** Originating MCP tool name, when the call came from an MCP server. */
40 > readonly mcpToolName?: string;
41 > /** MCP App render data, when the call exposes an interactive App surface. */
42 > readonly ui?: IToolCallUiMeta;
43 > /**
44 > * Set by the host's side-effect layer when the call was auto-approved
45 > * because of an `autoApprove` session-config setting (rather than an
46 > * explicit user action), so the client can render it as setting-driven.
47 > */
48 > readonly autoApproveBySetting?: boolean;
49 > /** Transient runtime corpus for the local client tool-search invocation. */
50 > readonly toolSearchCandidates?: readonly IToolSearchCandidate[];
51 > }
52 >
53 > /** Minimal metadata needed to embed and rank a deferred tool. */
54 > export interface IToolSearchCandidate {
55 > readonly name: string;
56 > readonly description: string;
57 > }
58 >
59 > /**
60 > * The set of VS Code-recognized tool-call rendering kinds. Add a new value here
61 > * (and teach the renderer to handle it) rather than matching on tool name.
62 > */
63 > export type ToolKind = 'terminal' | 'subagent' | 'search';
64 >
65 > /**
66 > * MCP App render data carried under {@link IToolCallMeta.ui}. Clients gate
67 > * mounting the App webview on both a `resourceUri` and a `channel` being
68 > * present.
69 > */
70 > export interface IToolCallUiMeta {
71 > /** The MCP App's UI resource URI (an `ui://` resource the App renders). */
72 > readonly resourceUri: string;
73 > /** AHP `mcp://` channel the App's sub-RPCs route back through, when ready. */
74 > readonly channel?: string;
75 > }
76 >
77 function isToolKind(value: unknown): value is ToolKind {
78 return value === 'terminal' || value === 'subagent' || value === 'search';
79 }
81 function readToolCallUiMeta(value: unknown): IToolCallUiMeta | undefined {
82 if (!value || typeof value !== 'object' || Array.isArray(value)) {
93 return result;
94 }
96 function readToolSearchCandidates(value: unknown): readonly IToolSearchCandidate[] | undefined {
97 if (!Array.isArray(value)) {
114 return result;
115 }
117 > /**
118 > * Reads the well-known {@link IToolCallMeta} keys from a tool call's `_meta`
119 > * bag, dropping unknown keys and wrong-typed values.
120 > */
121 > export function readToolCallMeta(source: IHasToolCallMeta): IToolCallMeta {
122 const meta = source._meta;
123 if (!meta) {
140 return result;
141 }
143 > /**
144 > * Serializes a typed {@link IToolCallMeta} into the `_meta` record, dropping
145 > * `undefined` entries and returning `undefined` when empty. Build a tool call's
146 > * `_meta` through this so producers stay in lock-step with
147 > * {@link readToolCallMeta}.
148 > */
149 > export function toToolCallMeta(meta: IToolCallMeta): Record<string, unknown> | undefined {
150 const result: Record<string, unknown> = {};
151 for (const [key, value] of Object.entries(meta)) {
src/vs/base/common/extpath.ts 91 covered LOC · 17 ranges

Open complete file

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

Open complete file

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

Open complete file

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

Open complete file

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

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- defaultAccount.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { ICopilotTokenInfo, IDefaultAccount, IDefaultAccountAuthenticationProvider, IPolicyData } from '../../../base/common/defaultAccount.js';
7 > import { Event } from '../../../base/common/event.js';
8 > import { createDecorator } from '../../instantiation/common/instantiation.js';
9 >
10 > /**
11 > * Well-known GitHub URL paths used with {@link IDefaultAccountService.resolveGitHubUrl}.
12 > */
13 > export const GitHubPaths = {
14 > copilotSettings: 'settings/copilot/features',
15 > billingBudgets: 'settings/copilot/features?utm_source=vscode',
16 > copilotUpgrade: 'github-copilot/upgrade?utm_source=vscode',
17 > } as const;
18 >
19 > /**
20 > * Outcome of the last `/copilot_internal/managed_settings` fetch.
21 > * - A numeric HTTP status code indicates the server responded with that code.
22 > * - `'ok'`: response parsed and adapted successfully (including an empty `{}` body).
23 > * - `'no-url'`: no `managedSettingsUrl` configured in product.json.
24 > * - `'no-response'`: network error, all sessions rejected, or active rate-limit backoff.
25 > * - `'parse-error'`: response received but JSON parsing failed.
26 > * - `null`: never fetched.
27 > */
28 > export type ManagedSettingsFetchStatus = number | 'ok' | 'no-url' | 'no-response' | 'parse-error' | null;
29 >
30 > export interface IDefaultAccountProvider {
31 > readonly defaultAccount: IDefaultAccount | null;
32 > readonly onDidChangeDefaultAccount: Event<IDefaultAccount | null>;
33 > readonly policyData: IPolicyData | null;
34 > readonly onDidChangePolicyData: Event<IPolicyData | null>;
35 > readonly copilotTokenInfo: ICopilotTokenInfo | null;
36 > readonly onDidChangeCopilotTokenInfo: Event<ICopilotTokenInfo | null>;
37 > readonly managedSettingsFetchStatus: ManagedSettingsFetchStatus;
38 > /** Timestamp (ms) of the last managed-settings fetch, or `null` if never fetched. */
39 > readonly managedSettingsFetchedAt: number | null;
40 > /** The raw JSON response from the managed-settings endpoint, for diagnostics. */
41 > readonly managedSettingsRawResponse: unknown;
42 > getDefaultAccountAuthenticationProvider(): IDefaultAccountAuthenticationProvider;
43 >
44 > /**
45 > * Resolves a GitHub URL path to a full URL, using the GitHub Enterprise
46 > * base URL when the user is authenticated via a GHE provider, or
47 > * `https://github.com` otherwise.
48 > *
49 > * @param path The path portion of the URL (e.g. `settings/copilot/features`).
50 > */
51 > resolveGitHubUrl(path: string): string;
52 >
53 > refresh(options?: { forceRefresh?: boolean }): Promise<IDefaultAccount | null>;
54 > signIn(options?: { additionalScopes?: readonly string[];[key: string]: unknown }): Promise<IDefaultAccount | null>;
55 > signOut(): Promise<void>;
56 > }
57 >
58 > export const IDefaultAccountService = createDecorator<IDefaultAccountService>('defaultAccountService');
59 >
60 > export interface IDefaultAccountService {
61 > readonly _serviceBrand: undefined;
62 > readonly onDidChangeDefaultAccount: Event<IDefaultAccount | null>;
63 > readonly onDidChangePolicyData: Event<IPolicyData | null>;
64 > readonly policyData: IPolicyData | null;
65 > readonly currentDefaultAccount: IDefaultAccount | null;
66 > readonly copilotTokenInfo: ICopilotTokenInfo | null;
67 > readonly onDidChangeCopilotTokenInfo: Event<ICopilotTokenInfo | null>;
68 > readonly managedSettingsFetchStatus: ManagedSettingsFetchStatus;
69 > /** Timestamp (ms) of the last managed-settings fetch, or `null` if never fetched. */
70 > readonly managedSettingsFetchedAt: number | null;
71 > /** The raw JSON response from the managed-settings endpoint, for diagnostics. */
72 > readonly managedSettingsRawResponse: unknown;
73 > getDefaultAccount(): Promise<IDefaultAccount | null>;
74 > getDefaultAccountAuthenticationProvider(): IDefaultAccountAuthenticationProvider;
75 > setDefaultAccountProvider(provider: IDefaultAccountProvider): void;
76 > refresh(options?: { forceRefresh?: boolean }): Promise<IDefaultAccount | null>;
77 > signIn(options?: { additionalScopes?: readonly string[];[key: string]: unknown }): Promise<IDefaultAccount | null>;
78 > signOut(): Promise<void>;
79 >
80 > /**
81 > * Resolves a GitHub URL path to a full URL, using the GitHub Enterprise
82 > * base URL when the user is authenticated via a GHE provider, or
83 > * `https://github.com` otherwise.
84 > *
85 > * @param path The path portion of the URL (e.g. `settings/copilot/features`).
86 > */
87 > resolveGitHubUrl(path: string): string;
88 > }
src/vs/workbench/services/policies/common/accountPolicyService.ts 88 covered LOC · 6 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- accountPolicyService.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IStringDictionary } from '../../../../base/common/collections.js';
7 > import { IPolicyData } from '../../../../base/common/defaultAccount.js';
8 > import { Emitter, Event } from '../../../../base/common/event.js';
9 > import { ManagedSettingsData } from '../../../../base/common/policy.js';
10 > import { localize } from '../../../../nls.js';
11 > import { RawContextKey } from '../../../../platform/contextkey/common/contextkey.js';
12 > import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
13 > import { ILogService } from '../../../../platform/log/common/log.js';
14 > import { INativeManagedSettingsService, IFileManagedSettingsService, collectManagedSettingsDefinitions, hasManagedSettingsDefinitions, projectManagedSettings, pickManagedSettings } from '../../../../platform/policy/common/copilotManagedSettings.js';
15 > import { AbstractPolicyService, getRestrictedPolicyValue, IPolicyService, PolicyDefinition, PolicyValue } from '../../../../platform/policy/common/policy.js';
16 > import { IDefaultAccountService } from '../../../../platform/defaultAccount/common/defaultAccount.js';
17 >
18 > /**
19 > * Policy name (declared by `chat.approvedAccountOrganizations`) holding the list of
20 > * GitHub organization logins that satisfy the gate. The token `*` is a wildcard.
21 > */
22 > export const APPROVED_ACCOUNT_ORGANIZATIONS_POLICY_NAME = 'ChatApprovedAccountOrganizations';
23 >
24 > export const enum AccountPolicyGateState {
25 > Inactive = 'inactive',
26 > Satisfied = 'satisfied',
27 > /** Gate active and NOT satisfied — restricted values are applied to all gated policies. */
28 > Restricted = 'restricted',
29 > }
30 >
31 > export const enum AccountPolicyGateUnsatisfiedReason {
32 > NoAccount = 'noAccount',
33 > WrongProvider = 'wrongProvider',
34 > OrgNotApproved = 'orgNotApproved',
35 > PolicyNotResolved = 'policyNotResolved',
36 > }
37 >
38 > export interface IAccountPolicyGateInfo {
39 > readonly state: AccountPolicyGateState;
40 > readonly reason?: AccountPolicyGateUnsatisfiedReason;
41 > readonly approvedOrganizations?: readonly string[];
42 > }
43 >
44 > export const ChatAccountPolicyGateActiveContext = new RawContextKey<boolean>(
45 > 'chatAccountPolicyGateActive',
46 > false,
47 > { type: 'boolean', description: localize('chatAccountPolicyGateActive', "True when the 'Require Approved Account' policy is in effect and the user is not yet signed into an approved GitHub organization, so all AI features are disabled until they sign in.") }
48 > );
49 >
50 > /**
51 > * Read-only accessor for the Account Policy gate state. Backed by the same
52 > * `AccountPolicyService` instance that drives policy enforcement, so UX consumers
53 > * (notifications, context keys, telemetry) cannot drift from the authoritative
54 > * gate decision.
55 > */
56 > export const IAccountPolicyGateService = createDecorator<IAccountPolicyGateService>('accountPolicyGateService');
57 > export interface IAccountPolicyGateService {
58 > readonly _serviceBrand: undefined;
59 > readonly gateInfo: IAccountPolicyGateInfo;
60 > readonly onDidChangeGateInfo: Event<IAccountPolicyGateInfo>;
61 > }
62 >
63 > export class AccountPolicyService extends AbstractPolicyService implements IPolicyService, IAccountPolicyGateService {
64 >
65 > declare readonly _serviceBrand: undefined;
66 >
67 > private _gateInfo: IAccountPolicyGateInfo = { state: AccountPolicyGateState.Inactive };
68 > get gateInfo(): IAccountPolicyGateInfo { return this._gateInfo; }
69 >
70 > private readonly _onDidChangeGateInfo = this._register(new Emitter<IAccountPolicyGateInfo>());
71 > readonly onDidChangeGateInfo = this._onDidChangeGateInfo.event;
72 >
73 > // Read-only — the MultiplexPolicyService owns calling updatePolicyDefinitions.
74 > private readonly managedPolicyReader?: IPolicyService;
75 > private readonly nativeManagedSettingsService?: INativeManagedSettingsService;
76 > private readonly fileManagedSettingsService?: IFileManagedSettingsService;
77 >
78 > constructor(
79 @ILogService private readonly logService: ILogService,
80 @IDefaultAccountService private readonly defaultAccountService: IDefaultAccountService,
121 });
122 }
124 > protected async _updatePolicyDefinitions(policyDefinitions: IStringDictionary<PolicyDefinition>): Promise<void> {
125 this.logService.trace(`AccountPolicyService#_updatePolicyDefinitions: Got ${Object.keys(policyDefinitions).length} policy definitions`);
126 const managedSettings = await this.updateCopilotManagedSettingDefinitions(policyDefinitions);
177 }
178 }
180 > private async updateCopilotManagedSettingDefinitions(policyDefinitions: IStringDictionary<PolicyDefinition>): Promise<ManagedSettingsData | undefined> {
181 if (!this.nativeManagedSettingsService || !hasManagedSettingsDefinitions(policyDefinitions)) {
182 return this.nativeManagedSettingsService?.managedSettings;
185 return this.nativeManagedSettingsService.updatePolicyDefinitions(policyDefinitions);
186 }
188 > private getPolicyData(mdmManagedSettings?: ManagedSettingsData): IPolicyData | undefined {
189 const accountPolicyData = this.defaultAccountService.policyData ?? undefined;
190 const nativeManagedSettings = mdmManagedSettings ?? this.nativeManagedSettingsService?.managedSettings;
212 };
213 }
215 > private computeGateInfo(): IAccountPolicyGateInfo {
216 if (!this.managedPolicyReader) {
217 return { state: AccountPolicyGateState.Inactive };
252 return { state: AccountPolicyGateState.Satisfied, approvedOrganizations: approvedOrgs };
253 }
255 >
256 function parseApprovedOrganizations(raw: PolicyValue | undefined): string[] {
257 // Array-typed policies are delivered as JSON-stringified arrays — see
src/vs/base/common/decorators/cancelPreviousCalls.ts 87 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- cancelPreviousCalls.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { assertDefined } from '../types.js';
7 > import { Disposable, DisposableMap } from '../lifecycle.js';
8 > import { CancellationTokenSource, CancellationToken } from '../cancellation.js';
9 >
10 > /**
11 > * Helper type that represents a function that has an optional {@linkcode CancellationToken}
12 > * argument argument at the end of the arguments list.
13 > *
14 > * @typeparam `TFunction` - Type of the function arguments list of which will be extended
15 > * with an optional {@linkcode CancellationToken} argument.
16 > */
17 > type TWithOptionalCancellationToken<TFunction extends Function> = TFunction extends (...args: infer TArgs) => infer TReturn
18 > ? (...args: [...TArgs, cancellatioNToken?: CancellationToken]) => TReturn
19 > : never;
20 >
21 > /**
22 > * Decorator that provides a mechanism to cancel previous calls of the decorated method
23 > * by providing a `cancellation token` as the last argument of the method, which gets
24 > * cancelled immediately on subsequent call of the decorated method.
25 > *
26 > * Therefore to use this decorator, the two conditions must be met:
27 > *
28 > * - the decorated method must have an *optional* {@linkcode CancellationToken} argument at
29 > * the end of the arguments list
30 > * - the object that the decorated method belongs to must implement the {@linkcode Disposable};
31 > * this requirement comes from the internal implementation of the decorator that
32 > * creates new resources that need to be eventually disposed by someone
33 > *
34 > * @typeparam `TObject` - Object type that the decorated method belongs to.
35 > * @typeparam `TArgs` - Argument list of the decorated method.
36 > * @typeparam `TReturn` - Return value type of the decorated method.
37 > *
38 > * ### Examples
39 > *
40 > * ```typescript
41 > * // let's say we have a class that implements the `Disposable` interface that we want
42 > * // to use the decorator on
43 > * class Example extends Disposable {
44 > * async doSomethingAsync(arg1: number, arg2: string): Promise<void> {
45 > * // do something async..
46 > * await new Promise(resolve => setTimeout(resolve, 1000));
47 > * }
48 > * }
49 > * ```
50 > *
51 > * ```typescript
52 > * // to do that we need to add the `CancellationToken` argument to the end of args list
53 > * class Example extends Disposable {
54 > * @cancelPreviousCalls
55 > * async doSomethingAsync(arg1: number, arg2: string, cancellationToken?: CancellationToken): Promise<void> {
56 > * console.log(`call with args ${arg1} and ${arg2} initiated`);
57 > *
58 > * // the decorator will create the cancellation token automatically
59 > * assertDefined(
60 > * cancellationToken,
61 > * `The method must now have the `CancellationToken` passed to it.`,
62 > * );
63 > *
64 > * cancellationToken.onCancellationRequested(() => {
65 > * console.log(`call with args ${arg1} and ${arg2} was cancelled`);
66 > * });
67 > *
68 > * // do something async..
69 > * await new Promise(resolve => setTimeout(resolve, 1000));
70 > *
71 > * // check cancellation token state after the async operations
72 > * console.log(
73 > * `call with args ${arg1} and ${arg2} completed, canceled?: ${cancellationToken.isCancellationRequested}`,
74 > * );
75 > * }
76 > * }
77 > *
78 > * const example = new Example();
79 > * // call the decorate method first time
80 > * example.doSomethingAsync(1, 'foo');
81 > * // wait for 500ms which is less than 1000ms of the async operation in the first call
82 > * await new Promise(resolve => setTimeout(resolve, 500));
83 > * // calling the decorate method second time cancels the token passed to the first call
84 > * example.doSomethingAsync(2, 'bar');
85 > * ```
86 > */
87 > export function cancelPreviousCalls<
88 TObject extends Disposable,
89 TArgs extends unknown[],
src/vs/editor/common/model/mirrorTextModel.ts 87 covered LOC · 10 ranges

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- mcpResourceScannerService.ts
2 > * Copyright (c) Microsoft 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 { Queue } from '../../../base/common/async.js';
8 > import { VSBuffer } from '../../../base/common/buffer.js';
9 > import { IStringDictionary } from '../../../base/common/collections.js';
10 > import { parse, ParseError } from '../../../base/common/json.js';
11 > import { Disposable } from '../../../base/common/lifecycle.js';
12 > import { ResourceMap } from '../../../base/common/map.js';
13 > import { Mutable } from '../../../base/common/types.js';
14 > import { URI } from '../../../base/common/uri.js';
15 > import { ConfigurationTarget, ConfigurationTargetToString } from '../../configuration/common/configuration.js';
16 > import { FileOperationResult, IFileService, toFileOperationResult } from '../../files/common/files.js';
17 > import { InstantiationType, registerSingleton } from '../../instantiation/common/extensions.js';
18 > import { createDecorator } from '../../instantiation/common/instantiation.js';
19 > import { IUriIdentityService } from '../../uriIdentity/common/uriIdentity.js';
20 > import { IInstallableMcpServer } from './mcpManagement.js';
21 > import { ICommonMcpServerConfiguration, IMcpSandboxConfiguration, IMcpServerConfiguration, IMcpServerVariable, IMcpStdioServerConfiguration, McpServerType } from './mcpPlatformTypes.js';
22 >
23 > interface IScannedMcpServers {
24 > servers?: IStringDictionary<Mutable<IMcpServerConfiguration>>;
25 > inputs?: IMcpServerVariable[];
26 > sandbox?: IMcpSandboxConfiguration;
27 > }
28 >
29 > interface IOldScannedMcpServer {
30 > id: string;
31 > name: string;
32 > version?: string;
33 > gallery?: boolean;
34 > config: Mutable<IMcpServerConfiguration>;
35 > }
36 >
37 > interface IScannedWorkspaceMcpServers {
38 > settings?: {
39 > mcp?: IScannedMcpServers;
40 > };
41 > }
42 >
43 > export type McpResourceTarget = ConfigurationTarget.USER | ConfigurationTarget.WORKSPACE | ConfigurationTarget.WORKSPACE_FOLDER;
44 >
45 > export const IMcpResourceScannerService = createDecorator<IMcpResourceScannerService>('IMcpResourceScannerService');
46 > export interface IMcpResourceScannerService {
47 > readonly _serviceBrand: undefined;
48 > scanMcpServers(mcpResource: URI, target?: McpResourceTarget): Promise<IScannedMcpServers>;
49 > addMcpServers(servers: IInstallableMcpServer[], mcpResource: URI, target?: McpResourceTarget): Promise<void>;
50 > updateSandboxConfig(updateFn: (data: IScannedMcpServers) => IScannedMcpServers, mcpResource: URI, target?: McpResourceTarget): Promise<void>;
51 > removeMcpServers(serverNames: string[], mcpResource: URI, target?: McpResourceTarget): Promise<void>;
52 > }
53 >
54 > export class McpResourceScannerService extends Disposable implements IMcpResourceScannerService {
55 > readonly _serviceBrand: undefined;
56 >
57 > private readonly resourcesAccessQueueMap = new ResourceMap<Queue<IScannedMcpServers>>();
58 >
59 > constructor(
60 @IFileService private readonly fileService: IFileService,
61 @IUriIdentityService protected readonly uriIdentityService: IUriIdentityService,
63 super();
64 }
66 > async scanMcpServers(mcpResource: URI, target?: McpResourceTarget): Promise<IScannedMcpServers> {
67 return this.withProfileMcpServers(mcpResource, target);
68 }
70 > async addMcpServers(servers: IInstallableMcpServer[], mcpResource: URI, target?: McpResourceTarget): Promise<void> {
71 await this.withProfileMcpServers(mcpResource, target, scannedMcpServers => {
72 let updatedInputs = scannedMcpServers.inputs ?? [];
83 });
84 }
86 > async updateSandboxConfig(updateFn: (data: IScannedMcpServers) => IScannedMcpServers, mcpResource: URI, target?: McpResourceTarget): Promise<void> {
87 await this.withProfileMcpServers(mcpResource, target, updateFn);
88 }
90 > async removeMcpServers(serverNames: string[], mcpResource: URI, target?: McpResourceTarget): Promise<void> {
91 await this.withProfileMcpServers(mcpResource, target, scannedMcpServers => {
92 for (const serverName of serverNames) {
98 });
99 }
101 > private async withProfileMcpServers(mcpResource: URI, target?: McpResourceTarget, updateFn?: (data: IScannedMcpServers) => IScannedMcpServers): Promise<IScannedMcpServers> {
102 return this.getResourceAccessQueue(mcpResource)
103 .queue(async (): Promise<IScannedMcpServers> => {
143 });
144 }
146 > private async writeScannedMcpServers(mcpResource: URI, scannedMcpServers: IScannedMcpServers): Promise<void> {
147 if ((scannedMcpServers.servers && Object.keys(scannedMcpServers.servers).length > 0)
148 || (scannedMcpServers.inputs && scannedMcpServers.inputs.length > 0)
153 }
154 }
156 > private async writeScannedMcpServersToWorkspaceFolder(mcpResource: URI, scannedMcpServers: IScannedMcpServers): Promise<void> {
157 await this.fileService.writeFile(mcpResource, VSBuffer.fromString(JSON.stringify(scannedMcpServers, null, '\t')));
158 }
160 > private async writeScannedMcpServersToWorkspace(mcpResource: URI, scannedMcpServers: IScannedMcpServers): Promise<void> {
161 let scannedWorkspaceMcpServers: IScannedWorkspaceMcpServers | undefined;
162 try {
179 await this.fileService.writeFile(mcpResource, VSBuffer.fromString(JSON.stringify(scannedWorkspaceMcpServers, null, '\t')));
180 }
182 > private fromUserMcpServers(scannedMcpServers: IScannedMcpServers): IScannedMcpServers {
183 const userMcpServers: IScannedMcpServers = {
184 inputs: scannedMcpServers.inputs,
194 return userMcpServers;
195 }
197 > private fromWorkspaceFolderMcpServers(scannedWorkspaceFolderMcpServers: IScannedMcpServers): IScannedMcpServers {
198 const scannedMcpServers: IScannedMcpServers = {
199 inputs: scannedWorkspaceFolderMcpServers.inputs,
210 return scannedMcpServers;
211 }
213 > private sanitizeServer(serverOrConfig: IOldScannedMcpServer | Mutable<IMcpServerConfiguration>): IMcpServerConfiguration {
214 let server: IMcpServerConfiguration;
215 if ((<IOldScannedMcpServer>serverOrConfig).config) {
229 return server;
230 }
232 > private getResourceAccessQueue(file: URI): Queue<IScannedMcpServers> {
233 let resourceQueue = this.resourcesAccessQueueMap.get(file);
234 if (!resourceQueue) {
238 return resourceQueue;
239 }
241 >
242 > registerSingleton(IMcpResourceScannerService, McpResourceScannerService, InstantiationType.Delayed);
src/vs/base/common/performance.ts 84 covered LOC · 6 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- performance.ts
2 > * Copyright (c) Microsoft 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 { INodeProcess } from './platform.js';
7 >
8 > function _definePolyfillMarks(timeOrigin?: number) {
9 > const _data: [string?, number?] = [];
10 > if (typeof timeOrigin === 'number') {
11 > _data.push('code/timeOrigin', timeOrigin);
12 > }
13 >
14 > function mark(name: string, markOptions?: { startTime?: number }) {
15 _data.push(name, markOptions?.startTime ?? Date.now());
16 }
17 > function getMarks() { performance.ts
18 const result = [];
19 for (let i = 0; i < _data.length; i += 2) {
25 return result;
26 }
27 > function clearMarks(name?: string) { performance.ts
28 if (typeof name === 'undefined') {
29 const hasTimeOrigin = _data.length >= 2 && _data[0] === 'code/timeOrigin';
41 }
42 }
43 > return { mark, getMarks, clearMarks }; performance.ts
44 > }
45 >
46 > declare const process: INodeProcess;
47 >
48 > interface IPerformanceEntry {
49 > readonly name: string;
50 > readonly startTime: number;
51 > }
52 >
53 > interface IPerformanceTiming {
54 > readonly navigationStart?: number;
55 > readonly redirectStart?: number;
56 > readonly fetchStart?: number;
57 > }
58 >
59 > interface IPerformance {
60 > mark(name: string, markOptions?: { startTime?: number }): void;
61 > clearMarks(name?: string): void;
62 > getEntriesByType(type: string): IPerformanceEntry[];
63 > readonly timeOrigin: number;
64 > readonly timing: IPerformanceTiming;
65 > readonly nodeTiming?: any;
66 > }
67 >
68 > declare const performance: IPerformance;
69 >
70 > function _define() {
71 >
72 > // Identify browser environment when following property is not present
73 > // https://nodejs.org/dist/latest-v16.x/docs/api/perf_hooks.html#performancenodetiming
74 > // @ts-ignore
75 > if (typeof performance === 'object' && typeof performance.mark === 'function' && !performance.nodeTiming) {
76 // in a browser context, reuse performance-util
77
109 }
110
111 > } else if (typeof process === 'object') { performance.ts
112 > // node.js: use the normal polyfill but add the timeOrigin
113 > // from the node perf_hooks API as very first mark
114 > const timeOrigin = performance?.timeOrigin;
115 > return _definePolyfillMarks(timeOrigin);
116 >
117 > } else {
118 // unknown environment
119 console.trace('perf-util loaded in UNKNOWN environment');
120 return _definePolyfillMarks();
121 }
122 > } performance.ts
123 >
124 > function _factory(sharedObj: any) {
125 > if (!sharedObj.MonacoPerformanceMarks) {
126 > sharedObj.MonacoPerformanceMarks = _define();
127 > }
128 > return sharedObj.MonacoPerformanceMarks;
129 > }
130 >
131 > const perf = _factory(globalThis);
132 >
133 > export const mark: (name: string, markOptions?: { startTime?: number }) => void = perf.mark;
134 >
135 > /**
136 > * Clears performance marks. If a name is given, only marks with that exact
137 > * name are removed. If no name is given, all marks are removed.
138 > */
139 > export const clearMarks: (name?: string) => void = perf.clearMarks;
140 >
141 > export interface PerformanceMark {
142 > readonly name: string;
143 > readonly startTime: number;
144 > }
145 >
146 > /**
147 > * Returns all marks, sorted by `startTime`.
148 > */
149 > export const getMarks: () => PerformanceMark[] = perf.getMarks;
src/vs/workbench/api/common/extHostDocumentData.ts 84 covered LOC · 25 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostDocumentData.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { ok } from '../../../base/common/assert.js';
7 > import { Schemas } from '../../../base/common/network.js';
8 > import { regExpLeadsToEndlessLoop } from '../../../base/common/strings.js';
9 > import { URI, UriComponents } from '../../../base/common/uri.js';
10 > import { MirrorTextModel } from '../../../editor/common/model/mirrorTextModel.js';
11 > import { ensureValidWordDefinition, getWordAtText } from '../../../editor/common/core/wordHelper.js';
12 > import type * as vscode from 'vscode';
13 > import { equals } from '../../../base/common/arrays.js';
14 > import { EndOfLine } from './extHostTypes/textEdit.js';
15 > import { Position } from './extHostTypes/position.js';
16 > import { Range } from './extHostTypes/range.js';
17 >
18 > const _languageId2WordDefinition = new Map<string, RegExp>();
19 > export function setWordDefinitionFor(languageId: string, wordDefinition: RegExp | undefined): void {
20 if (!wordDefinition) {
21 _languageId2WordDefinition.delete(languageId);
24 }
25 }
27 function getWordDefinitionFor(languageId: string): RegExp | undefined {
28 return _languageId2WordDefinition.get(languageId);
29 }
31 > export interface IExtHostDocumentSaveDelegate {
32 > $trySaveDocument(uri: UriComponents): Promise<boolean>;
33 > }
34 >
35 > export class ExtHostDocumentData extends MirrorTextModel {
36 >
37 > private _document?: vscode.TextDocument;
38 > private _isDisposed: boolean = false;
39 >
40 > constructor(
41 private readonly _proxy: IExtHostDocumentSaveDelegate,
42 uri: URI, lines: string[], eol: string, versionId: number,
48 super(uri, lines, eol, versionId);
49 }
51 > // eslint-disable-next-line local/code-must-use-super-dispose
52 > override dispose(): void {
53 // we don't really dispose documents but let
54 // extensions still read from them. some
58 this._isDirty = false;
59 }
61 > equalLines(lines: readonly string[]): boolean {
62 return equals(this._lines, lines);
63 }
65 > get document(): vscode.TextDocument {
66 if (!this._document) {
67 const that = this;
92 return Object.freeze(this._document);
93 }
95 > _acceptLanguageId(newLanguageId: string): void {
96 ok(!this._isDisposed);
97 this._languageId = newLanguageId;
98 }
100 > _acceptIsDirty(isDirty: boolean): void {
101 ok(!this._isDisposed);
102 this._isDirty = isDirty;
103 }
105 > _acceptEncoding(encoding: string): void {
106 ok(!this._isDisposed);
107 this._encoding = encoding;
108 }
110 > private _save(): Promise<boolean> {
111 if (this._isDisposed) {
112 return Promise.reject(new Error('Document has been closed'));
114 return this._proxy.$trySaveDocument(this._uri);
115 }
117 > private _getTextInRange(_range: vscode.Range): string {
118 const range = this._validateRange(_range);
119
139 return resultLines.join(lineEnding);
140 }
142 > private _lineAt(lineOrPosition: number | vscode.Position): vscode.TextLine {
143
144 let line: number | undefined;
157 return new ExtHostDocumentLine(line, this._lines[line], line === this._lines.length - 1);
158 }
160 > private _offsetAt(position: vscode.Position): number {
161 position = this._validatePosition(position);
162 this._ensureLineStarts();
163 return this._lineStarts!.getPrefixSum(position.line - 1) + position.character;
164 }
166 > private _positionAt(offset: number): vscode.Position {
167 offset = Math.floor(offset);
168 offset = Math.max(0, offset);
176 return new Position(out.index, Math.min(out.remainder, lineLength));
177 }
179 > // ---- range math
180 >
181 > private _validateRange(range: vscode.Range): vscode.Range {
182 if (this._strictInstanceofChecks) {
183 if (!(range instanceof Range)) {
198 return new Range(start.line, start.character, end.line, end.character);
199 }
201 > private _validatePosition(position: vscode.Position): vscode.Position {
202 if (this._strictInstanceofChecks) {
203 if (!(position instanceof Position)) {
244 return new Position(line, character);
245 }
247 > private _getWordRangeAtPosition(_position: vscode.Position, regexp?: RegExp): vscode.Range | undefined {
248 const position = this._validatePosition(_position);
249
269 return undefined;
270 }
272 >
273 > export class ExtHostDocumentLine implements vscode.TextLine {
274 >
275 > private readonly _line: number;
276 > private readonly _text: string;
277 > private readonly _isLastLine: boolean;
278 >
279 > constructor(line: number, text: string, isLastLine: boolean) {
280 this._line = line;
281 this._text = text;
282 this._isLastLine = isLastLine;
283 }
285 > public get lineNumber(): number {
286 return this._line;
287 }
289 > public get text(): string {
290 return this._text;
291 }
293 > public get range(): Range {
294 return new Range(this._line, 0, this._line, this._text.length);
295 }
297 > public get rangeIncludingLineBreak(): Range {
298 if (this._isLastLine) {
299 return this.range;
301 return new Range(this._line, 0, this._line + 1, 0);
302 }
304 > public get firstNonWhitespaceCharacterIndex(): number {
305 //TODO@api, rename to 'leadingWhitespaceLength'
306 return /^(\s*)/.exec(this._text)![1].length;
307 }
309 > public get isEmptyOrWhitespace(): boolean {
310 return this.firstNonWhitespaceCharacterIndex === this._text.length;
311 }
src/vs/workbench/api/common/extHostXaaAuthProvider.ts 83 covered LOC · 5 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostXaaAuthProvider.ts
2 > * Copyright (c) Microsoft 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 * as vscode from 'vscode';
7 > import { stringHash } from '../../../base/common/hash.js';
8 > import { buildIdJagExchangeBody, buildResourceRedemptionBody, fetchAuthorizationServerMetadata, getClaimsFromJWT, IAuthorizationJWTClaims, IAuthorizationTokenResponse, isAuthorizationTokenResponse } from '../../../base/common/oauth.js';
9 > import { DynamicAuthProvider } from './extHostAuthentication.js';
10 >
11 > // eslint-disable-next-line @typescript-eslint/no-explicit-any
12 > type Ctor<T> = new (...args: any[]) => T;
13 >
14 > /**
15 > * Scopes used when bootstrapping the IdP session for an XAA flow.
16 > *
17 > * `openid` is required because the ID-JAG token exchange uses the IdP-issued
18 > * `id_token` as `subject_token` (per draft-ietf-oauth-identity-assertion-authz-grant
19 > * section 3.1, the subject token MUST be of type `urn:ietf:params:oauth:token-type:id_token`).
20 > * `offline_access` is requested so we get a refresh token for the IdP session.
21 > */
22 > export const IDP_SCOPES: readonly string[] = ['openid', 'offline_access'];
23 >
24 > interface IResourceCacheEntry {
25 > readonly resource: string;
26 > readonly scopes: readonly string[];
27 > readonly token: IAuthorizationTokenResponse;
28 > /** Fallback identity (the IdP login account) for sessions built from this token, used when the resource token has no id_token of its own. */
29 > readonly account: vscode.AuthenticationSessionAccountInformation;
30 > readonly created_at: number;
31 > }
32 >
33 > /** Cache key for resource-scoped tokens. Exported for testing. */
34 > export function cacheKey(resource: string, scopes: readonly string[]): string {
35 return resource + '|' + [...scopes].sort().join(' ');
36 }
38 > /**
39 > * Returns true if the cached token is past (or within 60s of) its expiry. Pure
40 > * and exported for testing.
41 > *
42 > * Mints fresh ID-JAG assertions are usually short-lived (minutes). We treat tokens as expired
43 > * 60s before their nominal expiry to avoid clock skew and in-flight redemptions racing past
44 > * `exp`. Tokens without `expires_in` defined are treated as never-expiring (cached
45 > * until the process exits); `expires_in: 0` is treated as immediately expired.
46 > */
47 > export function isExpired(entry: { token: { expires_in?: number }; created_at: number }, now: number = Date.now()): boolean {
48 if (entry.token.expires_in === undefined) {
49 return false;
51 return now > entry.created_at + (entry.token.expires_in * 1000) - 60_000;
52 }
54 > /**
55 > * (Preview) Mixin that turns a {@link DynamicAuthProvider} subclass into a
56 > * Cross App Access (XAA) / enterprise-managed authentication provider, per
57 > * `draft-ietf-oauth-identity-assertion-authz-grant`.
58 > *
59 > * The IdP login leg is identical to the base class — Auth Code + PKCE against
60 > * the org-configured issuer, using the pre-registered client credentials. On
61 > * top of that:
62 > *
63 > * 1. `createSession` ensures an IdP session exists (delegated to the base
64 > * class with {@link IDP_SCOPES}).
65 > * 2. It POSTs to the IdP token endpoint with `grant_type=token-exchange`,
66 > * `subject_token=<id_token>`, `subject_token_type=id_token`,
67 > * `requested_token_type=id-jag`, `audience=<resource AS>`,
68 > * `resource=<resource indicator>`, `scope=<requested scopes>` to mint an
69 > * ID-JAG.
70 > * 3. It discovers the resource's authorization server metadata (the audience
71 > * URL) and POSTs the ID-JAG to its token endpoint with
72 > * `grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer`,
73 > * `assertion=<id-jag>`, `resource=<resource indicator>`,
74 > * `scope=<requested scopes>` to obtain a resource-scoped access token.
75 > * 4. The resource-scoped token is cached in-memory per `(resource, scopes)`
76 > * and returned as the session's access token.
77 > *
78 > * The resource indicator is read from `options.resource` (RFC 8707) and the
79 > * resource's authorization server URL from `options.audience` on
80 > * {@link vscode.AuthenticationProviderSessionOptions}.
81 > */
82 > export function XaaifyAuthProvider<TBase extends Ctor<DynamicAuthProvider>>(Base: TBase): TBase {
83 return class XaaAuthenticationProvider extends Base {
84 private readonly _resourceTokens = new Map<string, IResourceCacheEntry>();
365 };
366 }
368 > /**
369 > * Builds a session from a token response. Identity precedence: the token's own `id_token`, then
370 > * `fallbackAccount` (the IdP login identity), then a generic default. Never the `access_token`, which
371 > * for XAA is an opaque resource credential. Exported for testing.
372 > */
373 > export function toSession(token: IAuthorizationTokenResponse, scopes: readonly string[], fallbackAccount?: vscode.AuthenticationSessionAccountInformation): vscode.AuthenticationSession {
374 let account: vscode.AuthenticationSessionAccountInformation | undefined;
375 if (token.id_token) {
src/vs/platform/extensionManagement/common/extensionManagementUtil.ts 82 covered LOC · 17 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extensionManagementUtil.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { compareIgnoreCase } from '../../../base/common/strings.js';
7 > import { IExtensionIdentifier, IGalleryExtension, ILocalExtension, MaliciousExtensionInfo, getTargetPlatform } from './extensionManagement.js';
8 > import { ExtensionIdentifier, IExtension, TargetPlatform, UNDEFINED_PUBLISHER } from '../../extensions/common/extensions.js';
9 > import { IFileService } from '../../files/common/files.js';
10 > import { isLinux, platform } from '../../../base/common/platform.js';
11 > import { URI } from '../../../base/common/uri.js';
12 > import { getErrorMessage } from '../../../base/common/errors.js';
13 > import { ILogService } from '../../log/common/log.js';
14 > import { arch } from '../../../base/common/process.js';
15 > import { TelemetryTrustedValue } from '../../telemetry/common/telemetryUtils.js';
16 > import { isString } from '../../../base/common/types.js';
17 >
18 > export function areSameExtensions(a: IExtensionIdentifier, b: IExtensionIdentifier): boolean {
19 if (a.uuid && b.uuid) {
20 return a.uuid === b.uuid;
25 return compareIgnoreCase(a.id, b.id) === 0;
26 }
28 > const ExtensionKeyRegex = /^([^.]+\..+)-(\d+\.\d+\.\d+)(-(.+))?$/;
29 >
30 > export class ExtensionKey {
31 >
32 > static create(extension: IExtension | IGalleryExtension): ExtensionKey {
33 > const version = (extension as IExtension).manifest ? (extension as IExtension).manifest.version : (extension as IGalleryExtension).version;
34 > const targetPlatform = (extension as IExtension).manifest ? (extension as IExtension).targetPlatform : (extension as IGalleryExtension).properties.targetPlatform;
35 > return new ExtensionKey(extension.identifier, version, targetPlatform);
36 > }
37 >
38 > static parse(key: string): ExtensionKey | null {
39 const matches = ExtensionKeyRegex.exec(key);
40 return matches && matches[1] && matches[2] ? new ExtensionKey({ id: matches[1] }, matches[2], matches[4] as TargetPlatform || undefined) : null;
41 }
43 > readonly id: string;
44 >
45 > constructor(
46 readonly identifier: IExtensionIdentifier,
47 readonly version: string,
50 this.id = identifier.id;
51 }
53 > toString(): string {
54 return `${this.id}-${this.version}${this.targetPlatform !== TargetPlatform.UNDEFINED ? `-${this.targetPlatform}` : ''}`;
55 }
57 > equals(o: unknown): boolean {
58 if (!(o instanceof ExtensionKey)) {
59 return false;
61 return areSameExtensions(this, o) && this.version === o.version && this.targetPlatform === o.targetPlatform;
62 }
64 >
65 > const EXTENSION_IDENTIFIER_WITH_VERSION_REGEX = /^([^.]+\..+)@((prerelease)|(\d+\.\d+\.\d+(-.*)?))$/;
66 > export function getIdAndVersion(id: string): [string, string | undefined] {
67 const matches = EXTENSION_IDENTIFIER_WITH_VERSION_REGEX.exec(id);
68 if (matches && matches[1]) {
71 return [adoptToGalleryExtensionId(id), undefined];
72 }
74 > export function getExtensionId(publisher: string, name: string): string {
75 return `${publisher}.${name}`;
76 }
78 > export function adoptToGalleryExtensionId(id: string): string {
79 return id.toLowerCase();
80 }
82 > export function getGalleryExtensionId(publisher: string | undefined, name: string): string {
83 return adoptToGalleryExtensionId(getExtensionId(publisher ?? UNDEFINED_PUBLISHER, name));
84 }
86 > export function groupByExtension<T>(extensions: T[], getExtensionIdentifier: (t: T) => IExtensionIdentifier): T[][] {
87 const byExtension: T[][] = [];
88 const findGroup = (extension: T) => {
104 return byExtension;
105 }
107 > export function getLocalExtensionTelemetryData(extension: ILocalExtension) {
108 return {
109 id: extension.identifier.id,
116 };
117 }
119 >
120 > /* __GDPR__FRAGMENT__
121 > "GalleryExtensionTelemetryData" : {
122 > "id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
123 > "name": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
124 > "extensionVersion": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
125 > "galleryId": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
126 > "publisherId": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
127 > "publisherName": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
128 > "publisherDisplayName": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
129 > "isPreReleaseVersion": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
130 > "dependencies": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
131 > "isSigned": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
132 > "${include}": [
133 > "${GalleryExtensionTelemetryData2}"
134 > ]
135 > }
136 > */
137 > export function getGalleryExtensionTelemetryData(extension: IGalleryExtension) {
138 return {
139 id: new TelemetryTrustedValue(extension.identifier.id),
150 };
151 }
153 > export const BetterMergeId = new ExtensionIdentifier('pprice.better-merge');
154 >
155 > export function getExtensionDependencies(installedExtensions: ReadonlyArray<IExtension>, extension: IExtension): IExtension[] {
156 const dependencies: IExtension[] = [];
157 const extensions = extension.manifest.extensionDependencies?.slice(0) ?? [];
171 return dependencies;
172 }
174 async function isAlpineLinux(fileService: IFileService, logService: ILogService): Promise<boolean> {
175 if (!isLinux) {
191 return !!content && (content.match(/^ID=([^\u001b\r\n]*)/m) || [])[1] === 'alpine';
192 }
194 export async function computeTargetPlatform(fileService: IFileService, logService: ILogService): Promise<TargetPlatform> {
195 const alpineLinux = await isAlpineLinux(fileService, logService);
198 return targetPlatform;
199 }
201 > export function isMalicious(identifier: IExtensionIdentifier, malicious: ReadonlyArray<MaliciousExtensionInfo>): boolean {
202 return findMatchingMaliciousEntry(identifier, malicious) !== undefined;
203 }
205 > export function findMatchingMaliciousEntry(identifier: IExtensionIdentifier, malicious: ReadonlyArray<MaliciousExtensionInfo>): MaliciousExtensionInfo | undefined {
206 return malicious.find(({ extensionOrPublisher }) => {
207 if (isString(extensionOrPublisher)) {
src/vs/platform/mcp/common/mcpPlatformTypes.ts 81 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- mcpPlatformTypes.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IStringDictionary } from '../../../base/common/collections.js';
7 >
8 > export interface IMcpDevModeConfig {
9 > /** Pattern or list of glob patterns to watch relative to the workspace folder. */
10 > watch?: string | string[];
11 > /** Whether to debug the MCP server when it's started. */
12 > debug?: { type: 'node' } | { type: 'debugpy'; debugpyPath?: string };
13 > }
14 >
15 > export interface IMcpSandboxConfiguration {
16 > network?: {
17 > allowedDomains?: string[];
18 > deniedDomains?: string[];
19 > };
20 > filesystem?: {
21 > denyRead?: string[];
22 > allowWrite?: string[];
23 > denyWrite?: string[];
24 > };
25 > }
26 >
27 > export const enum McpServerVariableType {
28 > PROMPT = 'promptString',
29 > PICK = 'pickString',
30 > }
31 >
32 > export interface IMcpServerVariable {
33 > readonly id: string;
34 > readonly type: McpServerVariableType;
35 > readonly description: string;
36 > readonly password: boolean;
37 > readonly default?: string;
38 > readonly options?: readonly string[];
39 > readonly serverName?: string;
40 > }
41 >
42 > export const enum McpServerType {
43 > LOCAL = 'stdio',
44 > REMOTE = 'http',
45 > }
46 >
47 > export interface ICommonMcpServerConfiguration {
48 > readonly type: McpServerType;
49 > readonly version?: string;
50 > readonly gallery?: boolean | string;
51 > }
52 >
53 > export interface IMcpStdioServerConfiguration extends ICommonMcpServerConfiguration {
54 > readonly type: McpServerType.LOCAL;
55 > readonly command: string;
56 > readonly args?: readonly string[];
57 > readonly env?: Record<string, string | number | null>;
58 > readonly envFile?: string;
59 > readonly cwd?: string;
60 > readonly sandboxEnabled?: boolean;
61 > readonly dev?: IMcpDevModeConfig;
62 > }
63 >
64 > export interface IMcpRemoteServerOAuthConfiguration {
65 > readonly clientId?: string;
66 > }
67 >
68 > export interface IMcpRemoteServerConfiguration extends ICommonMcpServerConfiguration {
69 > readonly type: McpServerType.REMOTE;
70 > readonly url: string;
71 > readonly headers?: Record<string, string>;
72 > readonly oauth?: IMcpRemoteServerOAuthConfiguration;
73 > readonly dev?: IMcpDevModeConfig;
74 > }
75 >
76 > export type IMcpServerConfiguration = IMcpStdioServerConfiguration | IMcpRemoteServerConfiguration;
77 >
78 > export interface IMcpServersConfiguration {
79 > servers?: IStringDictionary<IMcpServerConfiguration>;
80 > inputs?: IMcpServerVariable[];
81 > }
src/vs/workbench/services/extensions/common/proxyIdentifier.ts 81 covered LOC · 7 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- proxyIdentifier.ts
2 > * Copyright (c) Microsoft 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 { VSBuffer } from '../../../../base/common/buffer.js';
7 > import type { CancellationToken } from '../../../../base/common/cancellation.js';
8 >
9 > export interface IRPCProtocol {
10 > /**
11 > * Returns a proxy to an object addressable/named in the extension host process or in the renderer process.
12 > */
13 > getProxy<T>(identifier: ProxyIdentifier<T>): Proxied<T>;
14 >
15 > /**
16 > * Register manually created instance.
17 > */
18 > set<T, R extends T>(identifier: ProxyIdentifier<T>, instance: R): R;
19 >
20 > /**
21 > * Assert these identifiers are already registered via `.set`.
22 > */
23 > assertRegistered(identifiers: ProxyIdentifier<unknown>[]): void;
24 >
25 > /**
26 > * Wait for the write buffer (if applicable) to become empty.
27 > */
28 > drain(): Promise<void>;
29 >
30 > dispose(): void;
31 > }
32 >
33 > export class ProxyIdentifier<T> {
34 > public static count = 0;
35 > _proxyIdentifierBrand: void = undefined;
36 >
37 > public readonly sid: string;
38 > public readonly nid: number;
39 >
40 > constructor(sid: string) {
41 > this.sid = sid; proxyIdentifier.ts
42 > this.nid = (++ProxyIdentifier.count);
43 > }
45 >
46 > const identifiers: ProxyIdentifier<unknown>[] = [];
47 >
48 > export function createProxyIdentifier<T>(identifier: string): ProxyIdentifier<T> {
49 > const result = new ProxyIdentifier<T>(identifier); proxyIdentifier.ts
50 > identifiers[result.nid] = result;
51 > return result;
52 > }
54 > /**
55 > * Mapped-type that replaces all JSONable-types with their toJSON-result type
56 > */
57 > export type Dto<T> = T extends { toJSON(): infer U }
58 > ? U
59 > : T extends VSBuffer // VSBuffer is understood by rpc-logic
60 > ? T
61 > : T extends CancellationToken // CancellationToken is understood by rpc-logic
62 > ? T
63 > : T extends Function // functions are dropped during JSON-stringify
64 > ? never
65 > : T extends object // recurse
66 > ? { [k in keyof T]: Dto<T[k]>; }
67 > : T;
68 >
69 > export type Proxied<T> = { [K in keyof T]: T[K] extends (...args: infer A) => infer R
70 > ? (...args: { [K in keyof A]: Dto<A[K]> }) => Promise<Dto<Awaited<R>>>
71 > : never
72 > };
73 >
74 > export function getStringIdentifierForProxy(nid: number): string {
75 return identifiers[nid].sid;
76 }
78 > /**
79 > * Marks the object as containing buffers that should be serialized more efficiently.
80 > */
81 > export class SerializableObjectWithBuffers<T> {
82 > constructor(
83 public readonly value: T
84 ) { }
src/vs/base/common/observableInternal/reactions/autorunImpl.ts 78 covered LOC · 18 ranges

Open complete file

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

Open complete file

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

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- prefixTree.ts
2 > * Copyright (c) Microsoft 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 './iterator.js';
7 >
8 > const unset = Symbol('unset');
9 >
10 > export interface IPrefixTreeNode<T> {
11 > /** Possible children of the node. */
12 > children?: ReadonlyMap<string, Node<T>>;
13 >
14 > /** The value if data exists for this node in the tree. Mutable. */
15 > value: T | undefined;
16 > }
17 >
18 > /**
19 > * A simple prefix tree implementation where a value is stored based on
20 > * well-defined prefix segments.
21 > */
22 > export class WellDefinedPrefixTree<V> {
23 public readonly root = new Node<V>();
24 private _size = 0;
26 > /** Tree size, not including the root. */
27 > public get size() {
28 return this._size;
29 }
31 > /** Gets the top-level nodes of the tree */
32 > public get nodes(): Iterable<IPrefixTreeNode<V>> {
33 return this.root.children?.values() || Iterable.empty();
34 }
36 > /** Gets the top-level nodes of the tree */
37 > public get entries(): Iterable<[string, IPrefixTreeNode<V>]> {
38 return this.root.children?.entries() || Iterable.empty();
39 }
41 > /**
42 > * Inserts a new value in the prefix tree.
43 > * @param onNode - called for each node as we descend to the insertion point,
44 > * including the insertion point itself.
45 > */
46 > insert(key: Iterable<string>, value: V, onNode?: (n: IPrefixTreeNode<V>) => void): void {
47 this.opNode(key, n => n._value = value, onNode);
48 }
50 > /** Mutates a value in the prefix tree. */
51 > mutate(key: Iterable<string>, mutate: (value?: V) => V): void {
52 this.opNode(key, n => n._value = mutate(n._value === unset ? undefined : n._value));
53 }
55 > /** Mutates nodes along the path in the prefix tree. */
56 > mutatePath(key: Iterable<string>, mutate: (node: IPrefixTreeNode<V>) => void): void {
57 this.opNode(key, () => { }, n => mutate(n));
58 }
60 > /** Deletes a node from the prefix tree, returning the value it contained. */
61 > delete(key: Iterable<string>): V | undefined {
62 const path = this.getPathToKey(key);
63 if (!path) {
85 return value;
86 }
88 > /** Deletes a subtree from the prefix tree, returning the values they contained. */
89 > *deleteRecursive(key: Iterable<string>): Iterable<V> {
90 const path = this.getPathToKey(key);
91 if (!path) {
118 }
119 }
121 > /** Gets a value from the tree. */
122 > find(key: Iterable<string>): V | undefined {
123 let node = this.root;
124 for (const segment of key) {
133 return node._value === unset ? undefined : node._value;
134 }
136 > /** Gets whether the tree has the key, or a parent of the key, already inserted. */
137 > hasKeyOrParent(key: Iterable<string>): boolean {
138 let node = this.root;
139 for (const segment of key) {
151 return false;
152 }
154 > /** Gets whether the tree has the given key or any children. */
155 > hasKeyOrChildren(key: Iterable<string>): boolean {
156 let node = this.root;
157 for (const segment of key) {
166 return true;
167 }
169 > /** Gets whether the tree has the given key. */
170 > hasKey(key: Iterable<string>): boolean {
171 let node = this.root;
172 for (const segment of key) {
181 return node._value !== unset;
182 }
184 > private getPathToKey(key: Iterable<string>) {
185 const path = [{ part: '', node: this.root }];
186 let i = 0;
197 return path;
198 }
200 > private opNode(key: Iterable<string>, fn: (node: Node<V>) => void, onDescend?: (node: Node<V>) => void): void {
201 let node = this.root;
202 for (const part of key) {
220 this._size += sizeAfter - sizeBefore;
221 }
223 > /** Returns an iterable of the tree values in no defined order. */
224 > *values() {
225 for (const { _value } of bfsIterate(this.root)) {
226 if (_value !== unset) {
229 }
230 }
231 > } prefixTree.ts
232 >
233 function* bfsIterate<T>(root: Node<T>): Iterable<Node<T>> {
234 const stack = [root];
244 }
245 }
247 class Node<T> implements IPrefixTreeNode<T> {
248 public children?: Map<string, Node<T>>;
257
258 public _value: T | typeof unset = unset;
259 > } prefixTree.ts
src/vs/base/common/themables.ts 73 covered LOC · 16 ranges

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- state.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > // allow-any-unicode-comment-file
7 > // DO NOT EDIT -- auto-generated by scripts/sync-agent-host-protocol.ts
8 >
9 > import type { URI } from '../common/state.js';
10 >
11 > // ─── Resource Watch Types ────────────────────────────────────────────────────
12 >
13 > /**
14 > * Full state for a single resource watch, returned when a client subscribes
15 > * to an `ahp-resource-watch:` URI.
16 > *
17 > * Watches are otherwise stateless: the watcher exists to deliver
18 > * {@link ResourceWatchChangedAction} events. The state carries only the
19 > * descriptor of what is being watched so a re-subscribing client can
20 > * recover the watch configuration after reconnecting.
21 > *
22 > * @category Resource Watch Types
23 > */
24 > export interface ResourceWatchState {
25 > /**
26 > * The URI being watched. For recursive watches this is the root of the
27 > * subtree; for non-recursive watches this is the single file or
28 > * directory.
29 > */
30 > root: URI;
31 > /**
32 > * `true` if the watcher reports changes for descendants of `root`;
33 > * `false` if it only reports changes to `root` itself (and, when
34 > * `root` is a directory, its direct children).
35 > */
36 > recursive: boolean;
37 > /**
38 > * Optional glob patterns or paths relative to `root` to exclude from
39 > * change reporting.
40 > */
41 > excludes?: { items: string[] };
42 > /**
43 > * Optional glob patterns or paths relative to `root` to restrict
44 > * change reporting to. Omit to report every change under `root`
45 > * subject to `excludes`.
46 > */
47 > includes?: { items: string[] };
48 > }
49 >
50 > // ─── Resource Change ─────────────────────────────────────────────────────────
51 >
52 > /**
53 > * Discriminant for {@link ResourceChange.type}.
54 > *
55 > * @category Resource Watch Types
56 > */
57 > export const enum ResourceChangeType {
58 > Added = 'added',
59 > Updated = 'updated',
60 > Deleted = 'deleted',
61 > }
62 >
63 > /**
64 > * A single change observed by a resource watcher.
65 > *
66 > * @category Resource Watch Types
67 > */
68 > export interface ResourceChange {
69 > /** The URI of the resource that changed. */
70 > uri: URI;
71 > /** The kind of change observed. */
72 > type: ResourceChangeType;
73 > }
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/workbench/api/common/extHostTestItem.ts 70 covered LOC · 11 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostTestItem.ts
2 > * Copyright (c) Microsoft 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 * as vscode from 'vscode';
7 > import { URI } from '../../../base/common/uri.js';
8 > import * as editorRange from '../../../editor/common/core/range.js';
9 > import { TestId, TestIdPathParts } from '../../contrib/testing/common/testId.js';
10 > import { createTestItemChildren, ExtHostTestItemEvent, ITestChildrenLike, ITestItemApi, ITestItemChildren, TestItemCollection, TestItemEventOp } from '../../contrib/testing/common/testItemCollection.js';
11 > import { denamespaceTestTag, ITestItem, ITestItemContext } from '../../contrib/testing/common/testTypes.js';
12 > import { ExtHostDocumentsAndEditors } from './extHostDocumentsAndEditors.js';
13 > import { createPrivateApiFor, getPrivateApiFor, IExtHostTestItemApi } from './extHostTestingPrivateApi.js';
14 > import * as Convert from './extHostTypeConverters.js';
15 >
16 > const testItemPropAccessor = <K extends keyof vscode.TestItem>(
17 api: IExtHostTestItemApi,
18 defaultValue: vscode.TestItem[K],
36 };
37 };
39 > type WritableProps = Pick<vscode.TestItem, 'range' | 'label' | 'description' | 'sortText' | 'canResolveChildren' | 'busy' | 'error' | 'tags'>;
40 >
41 > const strictEqualComparator = <T>(a: T, b: T) => a === b;
42 >
43 > const propComparators: { [K in keyof Required<WritableProps>]: (a: vscode.TestItem[K], b: vscode.TestItem[K]) => boolean } = {
44 > range: (a, b) => {
45 if (a === b) { return true; }
46 if (!a || !b) { return false; }
47 return a.isEqual(b);
48 },
49 > label: strictEqualComparator, extHostTestItem.ts
50 > description: strictEqualComparator,
51 > sortText: strictEqualComparator,
52 > busy: strictEqualComparator,
53 > error: strictEqualComparator,
54 > canResolveChildren: strictEqualComparator,
55 > tags: (a, b) => {
56 if (a.length !== b.length) {
57 return false;
64 return true;
65 },
67 >
68 > const evSetProps = <T>(fn: (newValue: T) => Partial<ITestItem>): (newValue: T) => ExtHostTestItemEvent =>
69 v => ({ op: TestItemEventOp.SetProp, update: fn(v) });
71 > const makePropDescriptors = (api: IExtHostTestItemApi, label: string): { [K in keyof Required<WritableProps>]: PropertyDescriptor } => ({
72 range: (() => {
73 let value: vscode.Range | undefined;
103 })),
104 });
106 > const toItemFromPlain = (item: ITestItem.Serialized): TestItemImpl => {
107 const testId = TestId.fromString(item.extId);
108 const testItem = new TestItemImpl(testId.controllerId, testId.localId, item.label, URI.revive(item.uri) || undefined);
113 return testItem;
114 };
116 > export const toItemFromContext = (context: ITestItemContext): TestItemImpl => {
117 let node: TestItemImpl | undefined;
118 for (const test of context.tests) {
124 return node!;
125 };
127 > export class TestItemImpl implements vscode.TestItem {
128 > public readonly id!: string;
129 > public readonly uri!: vscode.Uri | undefined;
130 > public readonly children!: ITestItemChildren<vscode.TestItem>;
131 > public readonly parent!: TestItemImpl | undefined;
132 >
133 > public range!: vscode.Range | undefined;
134 > public description!: string | undefined;
135 > public sortText!: string | undefined;
136 > public label!: string;
137 > public error!: string | vscode.MarkdownString;
138 > public busy!: boolean;
139 > public canResolveChildren!: boolean;
140 > public tags!: readonly vscode.TestTag[];
141 >
142 > /**
143 > * Note that data is deprecated and here for back-compat only
144 > */
145 > constructor(controllerId: string, id: string, label: string, uri: vscode.Uri | undefined) {
146 if (id.includes(TestIdPathParts.Delimiter)) {
147 throw new Error(`Test IDs may not include the ${JSON.stringify(id)} symbol`);
174 });
175 }
177 >
178 > export class TestItemRootImpl extends TestItemImpl {
179 > public readonly _isRoot = true;
180 >
181 > constructor(controllerId: string, label: string) {
182 super(controllerId, controllerId, label, undefined);
183 }
185 >
186 > export class ExtHostTestItemCollection extends TestItemCollection<TestItemImpl> {
187 > constructor(controllerId: string, controllerLabel: string, editors: ExtHostDocumentsAndEditors) {
188 super({
189 controllerId,
src/vs/workbench/api/common/extHostDocumentsAndEditors.ts 69 covered LOC · 11 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostDocumentsAndEditors.ts
2 > * Copyright (c) Microsoft 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 vscode from 'vscode';
8 > import { Emitter, Event } from '../../../base/common/event.js';
9 > import { dispose } from '../../../base/common/lifecycle.js';
10 > import { URI } from '../../../base/common/uri.js';
11 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
12 > import { ExtHostDocumentsAndEditorsShape, IDocumentsAndEditorsDelta, MainContext } from './extHost.protocol.js';
13 > import { ExtHostDocumentData } from './extHostDocumentData.js';
14 > import { IExtHostRpcService } from './extHostRpcService.js';
15 > import { ExtHostTextEditor } from './extHostTextEditor.js';
16 > import * as typeConverters from './extHostTypeConverters.js';
17 > import { ILogService } from '../../../platform/log/common/log.js';
18 > import { ResourceMap } from '../../../base/common/map.js';
19 > import { Schemas } from '../../../base/common/network.js';
20 > import { Iterable } from '../../../base/common/iterator.js';
21 > import { Lazy } from '../../../base/common/lazy.js';
22 >
23 > class Reference<T> {
24 > private _count = 0;
25 > constructor(readonly value: T) { }
26 > ref() {
27 this._count++;
28 }
30 return --this._count === 0;
31 }
33 >
34 > export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsShape {
35 >
36 > readonly _serviceBrand: undefined;
37 >
38 > private _activeEditorId: string | null = null;
39 >
40 > private readonly _editors = new Map<string, ExtHostTextEditor>();
41 > private readonly _documents = new ResourceMap<Reference<ExtHostDocumentData>>();
42 >
43 > private readonly _onDidAddDocuments = new Emitter<readonly ExtHostDocumentData[]>();
44 > private readonly _onDidRemoveDocuments = new Emitter<readonly ExtHostDocumentData[]>();
45 > private readonly _onDidChangeVisibleTextEditors = new Emitter<readonly vscode.TextEditor[]>();
46 > private readonly _onDidChangeActiveTextEditor = new Emitter<vscode.TextEditor | undefined>();
47 >
48 > readonly onDidAddDocuments: Event<readonly ExtHostDocumentData[]> = this._onDidAddDocuments.event;
49 > readonly onDidRemoveDocuments: Event<readonly ExtHostDocumentData[]> = this._onDidRemoveDocuments.event;
50 > readonly onDidChangeVisibleTextEditors: Event<readonly vscode.TextEditor[]> = this._onDidChangeVisibleTextEditors.event;
51 > readonly onDidChangeActiveTextEditor: Event<vscode.TextEditor | undefined> = this._onDidChangeActiveTextEditor.event;
52 >
53 > constructor(
54 @IExtHostRpcService private readonly _extHostRpc: IExtHostRpcService,
55 @ILogService private readonly _logService: ILogService
56 ) { }
58 > $acceptDocumentsAndEditorsDelta(delta: IDocumentsAndEditorsDelta): void {
59 this.acceptDocumentsAndEditorsDelta(delta);
60 }
62 > acceptDocumentsAndEditorsDelta(delta: IDocumentsAndEditorsDelta): void {
63
64 const removedDocuments: ExtHostDocumentData[] = [];
162 }
163 }
165 > getDocument(uri: URI): ExtHostDocumentData | undefined {
166 return this._documents.get(uri)?.value;
167 }
169 > allDocuments(): Iterable<ExtHostDocumentData> {
170 return Iterable.map(this._documents.values(), ref => ref.value);
171 }
173 > getEditor(id: string): ExtHostTextEditor | undefined {
174 return this._editors.get(id);
175 }
177 > activeEditor(): vscode.TextEditor | undefined;
178 > activeEditor(internal: true): ExtHostTextEditor | undefined;
179 > activeEditor(internal?: true): vscode.TextEditor | ExtHostTextEditor | undefined {
180 if (!this._activeEditorId) {
181 return undefined;
188 }
189 }
191 > allEditors(): ExtHostTextEditor[] {
192 return [...this._editors.values()];
193 }
195 >
196 > export interface IExtHostDocumentsAndEditors extends ExtHostDocumentsAndEditors { }
197 > export const IExtHostDocumentsAndEditors = createDecorator<IExtHostDocumentsAndEditors>('IExtHostDocumentsAndEditors');
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/platform/mcp/common/mcpManagementIpc.ts 67 covered LOC · 15 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- mcpManagementIpc.ts
2 > * Copyright (c) Microsoft 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 { cloneAndChange } from '../../../base/common/objects.js';
8 > import { URI, UriComponents } from '../../../base/common/uri.js';
9 > import { DefaultURITransformer, IURITransformer, transformAndReviveIncomingURIs } from '../../../base/common/uriIpc.js';
10 > import { IChannel, IServerChannel } from '../../../base/parts/ipc/common/ipc.js';
11 > import { ILogService } from '../../log/common/log.js';
12 > import { RemoteAgentConnectionContext } from '../../remote/common/remoteAgentEnvironment.js';
13 > import { DidUninstallMcpServerEvent, IGalleryMcpServer, ILocalMcpServer, IMcpManagementService, IInstallableMcpServer, InstallMcpServerEvent, InstallMcpServerResult, InstallOptions, UninstallMcpServerEvent, UninstallOptions, IAllowedMcpServersService } from './mcpManagement.js';
14 > import { AbstractMcpManagementService } from './mcpManagementService.js';
15 >
16 > function transformIncomingURI(uri: UriComponents, transformer: IURITransformer | null): URI;
17 > function transformIncomingURI(uri: UriComponents | undefined, transformer: IURITransformer | null): URI | undefined;
18 function transformIncomingURI(uri: UriComponents | undefined, transformer: IURITransformer | null): URI | undefined {
19 return uri ? URI.revive(transformer ? transformer.transformIncoming(uri) : uri) : undefined;
20 }
22 function transformIncomingServer(mcpServer: ILocalMcpServer, transformer: IURITransformer | null): ILocalMcpServer {
23 transformer = transformer ? transformer : DefaultURITransformer;
26 return { ...transformed, ...{ manifest } };
27 }
29 function transformIncomingOptions<O extends { mcpResource?: UriComponents }>(options: O | undefined, transformer: IURITransformer | null): O | undefined {
30 return options?.mcpResource ? transformAndReviveIncomingURIs(options, transformer ?? DefaultURITransformer) : options;
31 }
33 function transformOutgoingExtension(extension: ILocalMcpServer, transformer: IURITransformer | null): ILocalMcpServer {
34 return transformer ? cloneAndChange(extension, value => value instanceof URI ? transformer.transformOutgoingURI(value) : undefined) : extension;
35 }
37 function transformOutgoingURI(uri: URI, transformer: IURITransformer | null): URI {
38 return transformer ? transformer.transformOutgoingURI(uri) : uri;
39 }
41 > export class McpManagementChannel<TContext = RemoteAgentConnectionContext | string> implements IServerChannel<TContext> {
42 > readonly onInstallMcpServer: Event<InstallMcpServerEvent>;
43 > readonly onDidInstallMcpServers: Event<readonly InstallMcpServerResult[]>;
44 > readonly onDidUpdateMcpServers: Event<readonly InstallMcpServerResult[]>;
45 > readonly onUninstallMcpServer: Event<UninstallMcpServerEvent>;
46 > readonly onDidUninstallMcpServer: Event<DidUninstallMcpServerEvent>;
47 >
48 > constructor(private service: IMcpManagementService, private getUriTransformer: (requestContext: TContext) => IURITransformer | null) {
49 this.onInstallMcpServer = Event.buffer(service.onInstallMcpServer, 'onInstallMcpServer', true);
50 this.onDidInstallMcpServers = Event.buffer(service.onDidInstallMcpServers, 'onDidInstallMcpServers', true);
53 this.onDidUninstallMcpServer = Event.buffer(service.onDidUninstallMcpServer, 'onDidUninstallMcpServer', true);
54 }
56 > listen<T>(context: TContext, event: string): Event<T> {
57 const uriTransformer = this.getUriTransformer(context);
58 switch (event) {
92 throw new Error('Invalid listen');
93 }
95 > async call<T>(context: TContext, command: string, args?: unknown): Promise<T> {
96 const uriTransformer: IURITransformer | null = this.getUriTransformer(context);
97 const argsArray = Array.isArray(args) ? args : [];
117 throw new Error('Invalid call');
118 }
120 >
121 > export class McpManagementChannelClient extends AbstractMcpManagementService implements IMcpManagementService {
122 >
123 > declare readonly _serviceBrand: undefined;
124 >
125 > private readonly _onInstallMcpServer = this._register(new Emitter<InstallMcpServerEvent>());
126 > get onInstallMcpServer() { return this._onInstallMcpServer.event; }
127 >
128 > private readonly _onDidInstallMcpServers = this._register(new Emitter<readonly InstallMcpServerResult[]>());
129 > get onDidInstallMcpServers() { return this._onDidInstallMcpServers.event; }
130 >
131 > private readonly _onUninstallMcpServer = this._register(new Emitter<UninstallMcpServerEvent>());
132 > get onUninstallMcpServer() { return this._onUninstallMcpServer.event; }
133 >
134 > private readonly _onDidUninstallMcpServer = this._register(new Emitter<DidUninstallMcpServerEvent>());
135 > get onDidUninstallMcpServer() { return this._onDidUninstallMcpServer.event; }
136 >
137 > private readonly _onDidUpdateMcpServers = this._register(new Emitter<InstallMcpServerResult[]>());
138 > get onDidUpdateMcpServers() { return this._onDidUpdateMcpServers.event; }
139 >
140 > constructor(
141 private readonly channel: IChannel,
142 @IAllowedMcpServersService allowedMcpServersService: IAllowedMcpServersService,
150 this._register(this.channel.listen<DidUninstallMcpServerEvent>('onDidUninstallMcpServer')(e => this._onDidUninstallMcpServer.fire(({ ...e, mcpResource: transformIncomingURI(e.mcpResource, null) }))));
151 }
153 > install(server: IInstallableMcpServer, options?: InstallOptions): Promise<ILocalMcpServer> {
154 return Promise.resolve(this.channel.call<ILocalMcpServer>('install', [server, options])).then(local => transformIncomingServer(local, null));
155 }
157 > installFromGallery(extension: IGalleryMcpServer, installOptions?: InstallOptions): Promise<ILocalMcpServer> {
158 return Promise.resolve(this.channel.call<ILocalMcpServer>('installFromGallery', [extension, installOptions])).then(local => transformIncomingServer(local, null));
159 }
161 > uninstall(extension: ILocalMcpServer, options?: UninstallOptions): Promise<void> {
162 return Promise.resolve(this.channel.call<void>('uninstall', [extension, options]));
163 }
165 > getInstalled(mcpResource?: URI): Promise<ILocalMcpServer[]> {
166 return Promise.resolve(this.channel.call<ILocalMcpServer[]>('getInstalled', [mcpResource]))
167 .then(servers => servers.map(server => transformIncomingServer(server, null)));
168 }
170 > updateMetadata(local: ILocalMcpServer, gallery: IGalleryMcpServer, mcpResource?: URI): Promise<ILocalMcpServer> {
171 return Promise.resolve(this.channel.call<ILocalMcpServer>('updateMetadata', [local, gallery, mcpResource])).then(local => transformIncomingServer(local, null));
172 }
src/vs/workbench/api/common/extHostVariableResolverService.ts 66 covered LOC · 5 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostVariableResolverService.ts
2 > * Copyright (c) Microsoft 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 '../../../base/common/lazy.js';
7 > import { Disposable } from '../../../base/common/lifecycle.js';
8 > import * as path from '../../../base/common/path.js';
9 > import * as process from '../../../base/common/process.js';
10 > import { URI } from '../../../base/common/uri.js';
11 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
12 > import { IExtHostDocumentsAndEditors } from './extHostDocumentsAndEditors.js';
13 > import { IExtHostEditorTabs } from './extHostEditorTabs.js';
14 > import { IExtHostExtensionService } from './extHostExtensionService.js';
15 > import { CustomEditorTabInput, NotebookDiffEditorTabInput, NotebookEditorTabInput, TextDiffTabInput, TextTabInput } from './extHostTypes.js';
16 > import { IExtHostWorkspace } from './extHostWorkspace.js';
17 > import { IConfigurationResolverService } from '../../services/configurationResolver/common/configurationResolver.js';
18 > import { AbstractVariableResolverService } from '../../services/configurationResolver/common/variableResolver.js';
19 > import * as vscode from 'vscode';
20 > import { ExtHostConfigProvider, IExtHostConfiguration } from './extHostConfiguration.js';
21 >
22 > export interface IExtHostVariableResolverProvider {
23 > readonly _serviceBrand: undefined;
24 > getResolver(): Promise<IConfigurationResolverService>;
25 > }
26 >
27 > export const IExtHostVariableResolverProvider = createDecorator<IExtHostVariableResolverProvider>('IExtHostVariableResolverProvider');
28 >
29 > interface DynamicContext {
30 > folders: vscode.WorkspaceFolder[];
31 > }
32 >
33 > class ExtHostVariableResolverService extends AbstractVariableResolverService {
34 >
35 > constructor(
36 extensionService: IExtHostExtensionService,
37 workspaceService: IExtHostWorkspace,
132 }, undefined, homeDir ? Promise.resolve(homeDir) : undefined, Promise.resolve(process.env));
133 }
135 >
136 > export class ExtHostVariableResolverProviderService extends Disposable implements IExtHostVariableResolverProvider {
137 > declare readonly _serviceBrand: undefined;
138 >
139 > private _resolver = new Lazy(async () => {
140 > const configProvider = await this.configurationService.getConfigProvider();
141 > const folders = await this.workspaceService.getWorkspaceFolders2() || [];
142 >
143 > const dynamic: DynamicContext = { folders };
144 > this._register(this.workspaceService.onDidChangeWorkspace(async e => {
145 > dynamic.folders = await this.workspaceService.getWorkspaceFolders2() || [];
146 > }));
147 >
148 > return new ExtHostVariableResolverService(
149 > this.extensionService,
150 > this.workspaceService,
151 > this.editorService,
152 > this.editorTabs,
153 > configProvider,
154 > dynamic,
155 > this.homeDir(),
156 > );
157 > });
158 >
159 > constructor(
160 @IExtHostExtensionService private readonly extensionService: IExtHostExtensionService,
161 @IExtHostWorkspace private readonly workspaceService: IExtHostWorkspace,
src/vs/workbench/services/configurationResolver/common/variableResolver.ts 66 covered LOC · 11 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- variableResolver.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IStringDictionary } from '../../../../base/common/collections.js';
7 > import { normalizeDriveLetter } from '../../../../base/common/labels.js';
8 > import * as paths from '../../../../base/common/path.js';
9 > import { IProcessEnvironment, isWindows } from '../../../../base/common/platform.js';
10 > import * as process from '../../../../base/common/process.js';
11 > import * as types from '../../../../base/common/types.js';
12 > import { URI as uri } from '../../../../base/common/uri.js';
13 > import { localize } from '../../../../nls.js';
14 > import { ILabelService } from '../../../../platform/label/common/label.js';
15 > import { IWorkspaceFolderData } from '../../../../platform/workspace/common/workspace.js';
16 > import { allVariableKinds, IConfigurationResolverService, VariableError, VariableKind } from './configurationResolver.js';
17 > import { ConfigurationResolverExpression, IResolvedValue, Replacement } from './configurationResolverExpression.js';
18 >
19 > interface IVariableResolveContext {
20 > getFolderUri(folderName: string): uri | undefined;
21 > getWorkspaceFolderCount(): number;
22 > getConfigurationValue(folderUri: uri | undefined, section: string): string | undefined;
23 > getAppRoot(): string | undefined;
24 > getExecPath(): string | undefined;
25 > getFilePath(): string | undefined;
26 > getWorkspaceFolderPathForFile?(): string | undefined;
27 > getSelectedText(): string | undefined;
28 > getLineNumber(): string | undefined;
29 > getColumnNumber(): string | undefined;
30 > getExtension(id: string): Promise<{ readonly extensionLocation: uri } | undefined>;
31 > }
32 >
33 > type Environment = { env: IProcessEnvironment | undefined; userHome: string | undefined };
34 >
35 > export abstract class AbstractVariableResolverService implements IConfigurationResolverService {
36 >
37 > declare readonly _serviceBrand: undefined;
38 >
39 > private _context: IVariableResolveContext;
40 > private _labelService?: ILabelService;
41 > private _envVariablesPromise?: Promise<IProcessEnvironment>;
42 > private _userHomePromise?: Promise<string>;
43 > protected _contributedVariables: Map<string, () => Promise<string | undefined>> = new Map();
44 >
45 > public readonly resolvableVariables = new Set<string>(allVariableKinds);
46 >
47 > constructor(_context: IVariableResolveContext, _labelService?: ILabelService, _userHomePromise?: Promise<string>, _envVariablesPromise?: Promise<IProcessEnvironment>) {
48 this._context = _context;
49 this._labelService = _labelService;
55 }
56 }
58 > private prepareEnv(envVariables: IProcessEnvironment): IProcessEnvironment {
59 // windows env variables are case insensitive
60 if (isWindows) {
67 return envVariables;
68 }
70 > public async resolveWithEnvironment(environment: IProcessEnvironment, folder: IWorkspaceFolderData | undefined, value: string): Promise<string> {
71 const expr = ConfigurationResolverExpression.parse(value);
72
80 return expr.toObject();
81 }
83 > public async resolveAsync<T>(folder: IWorkspaceFolderData | undefined, config: T): Promise<T extends ConfigurationResolverExpression<infer R> ? R : T> {
84 const expr = ConfigurationResolverExpression.parse(config);
85
93 return expr.toObject() as (T extends ConfigurationResolverExpression<infer R> ? R : T);
94 }
96 > public resolveWithInteractionReplace(folder: IWorkspaceFolderData | undefined, config: unknown): Promise<unknown> {
97 throw new Error('resolveWithInteractionReplace not implemented.');
98 }
100 > public resolveWithInteraction(folder: IWorkspaceFolderData | undefined, config: unknown): Promise<Map<string, string> | undefined> {
101 throw new Error('resolveWithInteraction not implemented.');
102 }
104 > public contributeVariable(variable: string, resolution: () => Promise<string | undefined>): void {
105 if (this._contributedVariables.has(variable)) {
106 throw new Error('Variable ' + variable + ' is contributed twice.');
110 }
111 }
113 > private fsPath(displayUri: uri): string {
114 return this._labelService ? this._labelService.getUriLabel(displayUri, { noPrefix: true }) : displayUri.fsPath;
115 }
117 > protected async evaluateSingleVariable(replacement: Replacement, folderUri: uri | undefined, processEnvironment?: IProcessEnvironment, commandValueMapping?: IStringDictionary<IResolvedValue>): Promise<IResolvedValue | string | undefined> {
118
119
332 }
333 }
335 > private resolveFromMap(variableKind: VariableKind, match: string, argument: string | undefined, commandValueMapping: IStringDictionary<IResolvedValue> | undefined, prefix: string | undefined): string {
336 if (argument && commandValueMapping) {
337 const v = (prefix === undefined) ? commandValueMapping[argument] : commandValueMapping[prefix + ':' + argument];
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/uriIpc.ts 65 covered LOC · 15 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- uriIpc.ts
2 > * Copyright (c) Microsoft 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 './buffer.js';
7 > import { MarshalledObject } from './marshalling.js';
8 > import { MarshalledId } from './marshallingIds.js';
9 > import { URI, UriComponents } from './uri.js';
10 >
11 > export interface IURITransformer {
12 > transformIncoming(uri: UriComponents): UriComponents;
13 > transformOutgoing(uri: UriComponents): UriComponents;
14 > transformOutgoingURI(uri: URI): URI;
15 > transformOutgoingScheme(scheme: string): string;
16 > }
17 >
18 > export interface UriParts {
19 > scheme: string;
20 > authority?: string;
21 > path?: string;
22 > query?: string;
23 > fragment?: string;
24 > }
25 >
26 > export interface IRawURITransformer {
27 > transformIncoming(uri: UriParts): UriParts;
28 > transformOutgoing(uri: UriParts): UriParts;
29 > transformOutgoingScheme(scheme: string): string;
30 > }
31 >
32 function toJSON(uri: URI): UriComponents {
33 return uri.toJSON();
34 }
35 > uriIpc.ts
36 > export class URITransformer implements IURITransformer {
37 >
38 > private readonly _uriTransformer: IRawURITransformer;
39 >
40 > constructor(uriTransformer: IRawURITransformer) {
41 this._uriTransformer = uriTransformer;
42 }
43 > uriIpc.ts
44 > public transformIncoming(uri: UriComponents): UriComponents {
45 const result = this._uriTransformer.transformIncoming(uri);
46 return (result === uri ? uri : toJSON(URI.from(result)));
47 }
48 > uriIpc.ts
49 > public transformOutgoing(uri: UriComponents): UriComponents {
50 const result = this._uriTransformer.transformOutgoing(uri);
51 return (result === uri ? uri : toJSON(URI.from(result)));
52 }
53 > uriIpc.ts
54 > public transformOutgoingURI(uri: URI): URI {
55 const result = this._uriTransformer.transformOutgoing(uri);
56 return (result === uri ? uri : URI.from(result));
57 }
58 > uriIpc.ts
59 > public transformOutgoingScheme(scheme: string): string {
60 return this._uriTransformer.transformOutgoingScheme(scheme);
61 }
62 > } uriIpc.ts
63 >
64 > export const DefaultURITransformer: IURITransformer = new class {
65 > transformIncoming(uri: UriComponents) {
66 return uri;
67 }
68 > uriIpc.ts
69 > transformOutgoing(uri: UriComponents): UriComponents {
70 return uri;
71 }
72 > uriIpc.ts
73 > transformOutgoingURI(uri: URI): URI {
74 return uri;
75 }
76 > uriIpc.ts
77 > transformOutgoingScheme(scheme: string): string {
78 return scheme;
79 }
80 > }; uriIpc.ts
81 >
82 function _transformOutgoingURIs(obj: any, transformer: IURITransformer, depth: number): any {
83
104 return null;
105 }
106 > uriIpc.ts
107 > export function transformOutgoingURIs<T>(obj: T, transformer: IURITransformer): T {
108 const result = _transformOutgoingURIs(obj, transformer, 0);
109 if (result === null) {
113 return result;
114 }
115 > uriIpc.ts
116 >
117 function _transformIncomingURIs(obj: any, transformer: IURITransformer, revive: boolean, depth: number): any {
118
144 return null;
145 }
146 > uriIpc.ts
147 > export function transformIncomingURIs<T>(obj: T, transformer: IURITransformer): T {
148 const result = _transformIncomingURIs(obj, transformer, false, 0);
149 if (result === null) {
153 return result;
154 }
155 > uriIpc.ts
156 > export function transformAndReviveIncomingURIs<T>(obj: T, transformer: IURITransformer): T {
157 const result = _transformIncomingURIs(obj, transformer, true, 0);
158 if (result === null) {
src/vs/base/common/codicons.ts 64 covered LOC · 2 ranges

Open complete file

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

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- encryptionService.ts
2 > * Copyright (c) Microsoft 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 >
8 > export const IEncryptionService = createDecorator<IEncryptionService>('encryptionService');
9 > export interface IEncryptionService extends ICommonEncryptionService {
10 > setUsePlainTextEncryption(): Promise<void>;
11 > getKeyStorageProvider(): Promise<KnownStorageProvider>;
12 > }
13 >
14 > export const IEncryptionMainService = createDecorator<IEncryptionMainService>('encryptionMainService');
15 > export interface IEncryptionMainService extends IEncryptionService { }
16 >
17 > export interface ICommonEncryptionService {
18 >
19 > readonly _serviceBrand: undefined;
20 >
21 > encrypt(value: string): Promise<string>;
22 >
23 > decrypt(value: string): Promise<string>;
24 >
25 > isEncryptionAvailable(): Promise<boolean>;
26 > }
27 >
28 > // The values provided to the `password-store` command line switch.
29 > // Notice that they are not the same as the values returned by
30 > // `getSelectedStorageBackend` in the `safeStorage` API.
31 > export const enum PasswordStoreCLIOption {
32 > kwallet = 'kwallet',
33 > kwallet5 = 'kwallet5',
34 > gnomeLibsecret = 'gnome-libsecret',
35 > basic = 'basic'
36 > }
37 >
38 > // The values returned by `getSelectedStorageBackend` in the `safeStorage` API.
39 > export const enum KnownStorageProvider {
40 > unknown = 'unknown',
41 > basicText = 'basic_text',
42 >
43 > // Linux
44 > gnomeAny = 'gnome_any',
45 > gnomeLibsecret = 'gnome_libsecret',
46 > gnomeKeyring = 'gnome_keyring',
47 > kwallet = 'kwallet',
48 > kwallet5 = 'kwallet5',
49 > kwallet6 = 'kwallet6',
50 >
51 > // The rest of these are not returned by `getSelectedStorageBackend`
52 > // but these were added for platform completeness.
53 >
54 > // Windows
55 > dplib = 'dpapi',
56 >
57 > // macOS
58 > keychainAccess = 'keychain_access',
59 > }
60 >
61 > export function isKwallet(backend: string): boolean {
62 return backend === KnownStorageProvider.kwallet
63 || backend === KnownStorageProvider.kwallet5
64 || backend === KnownStorageProvider.kwallet6;
65 }
67 > export function isGnome(backend: string): boolean {
68 return backend === KnownStorageProvider.gnomeAny
69 || backend === KnownStorageProvider.gnomeLibsecret
src/vs/editor/common/tokenizationRegistry.ts 62 covered LOC · 14 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- tokenizationRegistry.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { Color } from '../../base/common/color.js';
7 > import { Emitter, Event } from '../../base/common/event.js';
8 > import { Disposable, IDisposable, toDisposable } from '../../base/common/lifecycle.js';
9 > import { ITokenizationRegistry, ITokenizationSupportChangedEvent, ILazyTokenizationSupport } from './languages.js';
10 > import { ColorId } from './encodedTokenAttributes.js';
11 >
12 > export class TokenizationRegistry<TSupport> implements ITokenizationRegistry<TSupport> {
13 >
14 > private readonly _tokenizationSupports = new Map<string, TSupport>();
15 > private readonly _factories = new Map<string, TokenizationSupportFactoryData<TSupport>>();
16 >
17 > private readonly _onDidChange = new Emitter<ITokenizationSupportChangedEvent>();
18 > public readonly onDidChange: Event<ITokenizationSupportChangedEvent> = this._onDidChange.event;
19 >
20 > private _colorMap: Color[] | null;
21 >
22 > constructor() {
23 > this._colorMap = null;
24 > }
25 >
26 > public handleChange(languageIds: string[]): void {
27 this._onDidChange.fire({
28 changedLanguages: languageIds,
30 });
31 }
33 > public register(languageId: string, support: TSupport): IDisposable {
34 this._tokenizationSupports.set(languageId, support);
35 this.handleChange([languageId]);
42 });
43 }
45 > public get(languageId: string): TSupport | null {
46 return this._tokenizationSupports.get(languageId) || null;
47 }
49 > public registerFactory(languageId: string, factory: ILazyTokenizationSupport<TSupport>): IDisposable {
50 this._factories.get(languageId)?.dispose();
51 const myData = new TokenizationSupportFactoryData(this, languageId, factory);
60 });
61 }
63 > public async getOrCreate(languageId: string): Promise<TSupport | null> {
64 // check first if the support is already set
65 const tokenizationSupport = this.get(languageId);
78 return this.get(languageId);
79 }
81 > public isResolved(languageId: string): boolean {
82 const tokenizationSupport = this.get(languageId);
83 if (tokenizationSupport) {
92 return false;
93 }
95 > public setColorMap(colorMap: Color[]): void {
96 this._colorMap = colorMap;
97 this._onDidChange.fire({
100 });
101 }
103 > public getColorMap(): Color[] | null {
104 return this._colorMap;
105 }
107 > public getDefaultBackground(): Color | null {
108 if (this._colorMap && this._colorMap.length > ColorId.DefaultBackground) {
109 return this._colorMap[ColorId.DefaultBackground];
111 return null;
112 }
114 >
115 > class TokenizationSupportFactoryData<TSupport> extends Disposable {
116 >
117 > private _isDisposed: boolean = false;
118 > private _resolvePromise: Promise<void> | null = null;
119 > private _isResolved: boolean = false;
120 >
121 > public get isResolved(): boolean {
122 > return this._isResolved;
123 > }
124 >
125 > constructor(
126 private readonly _registry: TokenizationRegistry<TSupport>,
127 private readonly _languageId: string,
130 super();
131 }
133 > public override dispose(): void {
134 this._isDisposed = true;
135 super.dispose();
136 }
138 > public async resolve(): Promise<void> {
139 if (!this._resolvePromise) {
140 this._resolvePromise = this._create();
142 return this._resolvePromise;
143 }
145 > private async _create(): Promise<void> {
146 const value = await this._factory.tokenizationSupport;
147 this._isResolved = true;
src/vs/base/common/linkedList.ts 61 covered LOC · 18 ranges

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- symbolInformation.ts
2 > * Copyright (c) Microsoft 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 { es5ClassCompat } from './es5ClassCompat.js';
8 > import { Location } from './location.js';
9 > import { Range } from './range.js';
10 >
11 > export enum SymbolKind {
12 > File = 0,
13 > Module = 1,
14 > Namespace = 2,
15 > Package = 3,
16 > Class = 4,
17 > Method = 5,
18 > Property = 6,
19 > Field = 7,
20 > Constructor = 8,
21 > Enum = 9,
22 > Interface = 10,
23 > Function = 11,
24 > Variable = 12,
25 > Constant = 13,
26 > String = 14,
27 > Number = 15,
28 > Boolean = 16,
29 > Array = 17,
30 > Object = 18,
31 > Key = 19,
32 > Null = 20,
33 > EnumMember = 21,
34 > Struct = 22,
35 > Event = 23,
36 > Operator = 24,
37 > TypeParameter = 25
38 > }
39 >
40 > export enum SymbolTag {
41 > Deprecated = 1
42 > }
43 >
44 > @es5ClassCompat
45 > export class SymbolInformation {
46 >
47 > static validate(candidate: SymbolInformation): void {
48 if (!candidate.name) {
49 throw new Error('name must not be falsy');
50 }
51 }
53 > name: string;
54 > location!: Location;
55 > kind: SymbolKind;
56 > tags?: SymbolTag[];
57 > containerName: string | undefined;
58 >
59 > constructor(name: string, kind: SymbolKind, containerName: string | undefined, location: Location);
60 > constructor(name: string, kind: SymbolKind, range: Range, uri?: URI, containerName?: string);
61 > constructor(name: string, kind: SymbolKind, rangeOrContainer: string | undefined | Range, locationOrUri?: Location | URI, containerName?: string) {
62 this.name = name;
63 this.kind = kind;
76 SymbolInformation.validate(this);
77 }
79 > toJSON(): { name: string; kind: string; location: Location; containerName: string | undefined } {
80 return {
81 name: this.name,
src/vs/amdX.ts 59 covered LOC · 8 ranges

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- remoteUserDataProfiles.ts
2 > * Copyright (c) Microsoft 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 { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';
8 > import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
9 > import { DidChangeProfilesEvent, IUserDataProfile, IUserDataProfilesService } from '../../../../platform/userDataProfile/common/userDataProfile.js';
10 > import { IRemoteAgentService } from '../../remote/common/remoteAgentService.js';
11 > import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js';
12 > import { IStringDictionary } from '../../../../base/common/collections.js';
13 > import { ILogService } from '../../../../platform/log/common/log.js';
14 > import { IUserDataProfileService } from './userDataProfile.js';
15 > import { distinct } from '../../../../base/common/arrays.js';
16 > import { IWorkbenchEnvironmentService } from '../../environment/common/environmentService.js';
17 > import { UserDataProfilesService } from '../../../../platform/userDataProfile/common/userDataProfileIpc.js';
18 > import { ErrorNoTelemetry } from '../../../../base/common/errors.js';
19 >
20 > const associatedRemoteProfilesKey = 'associatedRemoteProfiles';
21 >
22 > export const IRemoteUserDataProfilesService = createDecorator<IRemoteUserDataProfilesService>('IRemoteUserDataProfilesService');
23 > export interface IRemoteUserDataProfilesService {
24 > readonly _serviceBrand: undefined;
25 > getRemoteProfiles(): Promise<readonly IUserDataProfile[]>;
26 > getRemoteProfile(localProfile: IUserDataProfile): Promise<IUserDataProfile>;
27 > }
28 >
29 > class RemoteUserDataProfilesService extends Disposable implements IRemoteUserDataProfilesService {
30 >
31 > readonly _serviceBrand: undefined;
32 >
33 > private readonly initPromise: Promise<void>;
34 >
35 > private remoteUserDataProfilesService: IUserDataProfilesService | undefined;
36 >
37 > constructor(
38 @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
39 @IRemoteAgentService private readonly remoteAgentService: IRemoteAgentService,
46 this.initPromise = this.init();
47 }
49 > private async init(): Promise<void> {
50 const connection = this.remoteAgentService.getConnection();
51 if (!connection) {
69 this.cleanUp();
70 }
72 > private async onDidChangeLocalProfiles(e: DidChangeProfilesEvent): Promise<void> {
73 for (const profile of e.removed) {
74 const remoteProfile = this.remoteUserDataProfilesService?.profiles.find(p => p.id === profile.id);
78 }
79 }
81 > async getRemoteProfiles(): Promise<readonly IUserDataProfile[]> {
82 await this.initPromise;
83
88 return this.remoteUserDataProfilesService.profiles;
89 }
91 > async getRemoteProfile(localProfile: IUserDataProfile): Promise<IUserDataProfile> {
92 await this.initPromise;
93
98 return this.getAssociatedRemoteProfile(localProfile, this.remoteUserDataProfilesService);
99 }
101 > private async getAssociatedRemoteProfile(localProfile: IUserDataProfile, remoteUserDataProfilesService: IUserDataProfilesService): Promise<IUserDataProfile> {
102 // If the local profile is the default profile, return the remote default profile
103 if (localProfile.isDefault) {
115 return profile;
116 }
118 > private getAssociatedRemoteProfiles(): string[] {
119 if (this.environmentService.remoteAuthority) {
120 const remotes = this.parseAssociatedRemoteProfiles();
123 return [];
124 }
126 > private setAssociatedRemoteProfiles(profiles: string[]): void {
127 if (this.environmentService.remoteAuthority) {
128 const remotes = this.parseAssociatedRemoteProfiles();
140 }
141 }
143 > private parseAssociatedRemoteProfiles(): IStringDictionary<string[]> {
144 if (this.environmentService.remoteAuthority) {
145 const value = this.storageService.get(associatedRemoteProfilesKey, StorageScope.APPLICATION);
152 return {};
153 }
155 > private async cleanUp(): Promise<void> {
156 const associatedRemoteProfiles: string[] = [];
157 for (const profileId of this.getAssociatedRemoteProfiles()) {
175 this.setAssociatedRemoteProfiles(associatedRemoteProfiles);
176 }
178 > }
179 >
180 > registerSingleton(IRemoteUserDataProfilesService, RemoteUserDataProfilesService, InstantiationType.Delayed);
src/vs/base/common/observableInternal/observables/observableValue.ts 58 covered LOC · 12 ranges

Open complete file

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

Open complete file

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

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostManagedSockets.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { ExtHostManagedSocketsShape, MainContext, MainThreadManagedSocketsShape } from './extHost.protocol.js';
7 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
8 > import * as vscode from 'vscode';
9 > import { Disposable, DisposableStore, toDisposable } from '../../../base/common/lifecycle.js';
10 > import { IExtHostRpcService } from './extHostRpcService.js';
11 > import { VSBuffer } from '../../../base/common/buffer.js';
12 >
13 > export interface IExtHostManagedSockets extends ExtHostManagedSocketsShape {
14 > setFactory(socketFactoryId: number, makeConnection: () => Thenable<vscode.ManagedMessagePassing>): void;
15 > /**
16 > * Opens a managed connection in-process using the currently registered
17 > * factory. Used by consumers that live inside the extension host (e.g. the
18 > * browser tunnel proxy). There is only ever one active remote per window, so
19 > * the latest factory is the correct one to dial; this avoids depending on a
20 > * factory id that can lag connection-data updates by a renderer round-trip.
21 > */
22 > makeConnection(): Promise<vscode.ManagedMessagePassing>;
23 > readonly _serviceBrand: undefined;
24 > }
25 >
26 > export const IExtHostManagedSockets = createDecorator<IExtHostManagedSockets>('IExtHostManagedSockets');
27 >
28 > export class ExtHostManagedSockets implements IExtHostManagedSockets {
29 > declare readonly _serviceBrand: undefined;
30 >
31 > private readonly _proxy: MainThreadManagedSocketsShape;
32 > private _remoteSocketIdCounter = 0;
33 > private _factory: ManagedSocketFactory | null = null;
34 > private readonly _managedRemoteSockets: Map<number, ManagedSocket> = new Map();
35 >
36 > constructor(
37 @IExtHostRpcService extHostRpc: IExtHostRpcService,
38 ) {
39 this._proxy = extHostRpc.getProxy(MainContext.MainThreadManagedSockets);
40 }
42 > setFactory(socketFactoryId: number, makeConnection: () => Thenable<vscode.ManagedMessagePassing>): void {
43 // Terminate all previous sockets
44 for (const socket of this._managedRemoteSockets.values()) {
54 this._proxy.$registerSocketFactory(this._factory.socketFactoryId);
55 }
57 > makeConnection(): Promise<vscode.ManagedMessagePassing> {
58 if (!this._factory) {
59 throw new Error('No managed socket factory registered');
61 return Promise.resolve(this._factory.makeConnection());
62 }
64 > async $openRemoteSocket(socketFactoryId: number): Promise<number> {
65 if (!this._factory || this._factory.socketFactoryId !== socketFactoryId) {
66 throw new Error(`No socket factory with id ${socketFactoryId}`);
85 return id;
86 }
88 > $remoteSocketWrite(socketId: number, buffer: VSBuffer): void {
89 this._managedRemoteSockets.get(socketId)?.actual.send(buffer.buffer);
90 }
92 > $remoteSocketEnd(socketId: number): void {
93 const socket = this._managedRemoteSockets.get(socketId);
94 if (socket) {
97 }
98 }
100 > async $remoteSocketDrain(socketId: number): Promise<void> {
101 await this._managedRemoteSockets.get(socketId)?.actual.drain?.();
102 }
104 >
105 > class ManagedSocketFactory {
106 > constructor(
107 public readonly socketFactoryId: number,
108 public readonly makeConnection: () => Thenable<vscode.ManagedMessagePassing>,
109 ) { }
111 >
112 > class ManagedSocket extends Disposable {
113 > constructor(
114 public readonly socketId: number,
115 public readonly actual: vscode.ManagedMessagePassing,
src/vs/base/test/common/utils.ts 56 covered LOC · 13 ranges

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- policy.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IStringDictionary } from '../../../base/common/collections.js';
7 > import { IPolicyData } from '../../../base/common/defaultAccount.js';
8 > import { Emitter, Event } from '../../../base/common/event.js';
9 > import { Iterable } from '../../../base/common/iterator.js';
10 > import { Disposable } from '../../../base/common/lifecycle.js';
11 > import { IManagedSettingsPolicyDefinitions, PolicyName } from '../../../base/common/policy.js';
12 > import { createDecorator } from '../../instantiation/common/instantiation.js';
13 >
14 > export type PolicyValue = string | number | boolean;
15 > export type PolicyDefinition = {
16 > type: 'string' | 'number' | 'boolean';
17 > value?: (policyData: IPolicyData) => string | number | boolean | undefined;
18 > managedSettings?: IManagedSettingsPolicyDefinitions;
19 > restrictedValue?: PolicyValue;
20 > };
21 >
22 > /** Returns a structured-clone-safe copy of `definition`, dropping the non-cloneable `value` callback. */
23 > export function toSerializablePolicyDefinition(definition: PolicyDefinition): PolicyDefinition {
24 return { type: definition.type, managedSettings: definition.managedSettings, restrictedValue: definition.restrictedValue };
25 }
26 > policy.ts
27 > /**
28 > * Returns the value to apply for `definition` when the account-policy gate is active
29 > * but not satisfied. Uses `definition.restrictedValue` when specified, otherwise falls
30 > * back to a type-driven safe default.
31 > */
32 > export function getRestrictedPolicyValue(definition: PolicyDefinition): PolicyValue {
33 if (definition.restrictedValue !== undefined) {
34 return definition.restrictedValue;
40 }
41 }
42 > policy.ts
43 > export const IPolicyService = createDecorator<IPolicyService>('policy');
44 >
45 > export interface IPolicyService {
46 > readonly _serviceBrand: undefined;
47 >
48 > readonly onDidChange: Event<readonly PolicyName[]>;
49 > updatePolicyDefinitions(policyDefinitions: IStringDictionary<PolicyDefinition>): Promise<IStringDictionary<PolicyValue>>;
50 > getPolicyValue(name: PolicyName): PolicyValue | undefined;
51 > serialize(): IStringDictionary<{ definition: PolicyDefinition; value: PolicyValue }> | undefined;
52 > readonly policyDefinitions: IStringDictionary<PolicyDefinition>;
53 > }
54 >
55 > export abstract class AbstractPolicyService extends Disposable implements IPolicyService {
56 readonly _serviceBrand: undefined;
57
61 protected readonly _onDidChange = this._register(new Emitter<readonly PolicyName[]>());
62 readonly onDidChange = this._onDidChange.event;
63 > policy.ts
64 > async updatePolicyDefinitions(policyDefinitions: IStringDictionary<PolicyDefinition>): Promise<IStringDictionary<PolicyValue>> {
65 // Replace existing definitions; identity comparison avoids redundant watcher churn.
66 let changed = false;
78 return Iterable.reduce(this.policies.entries(), (r, [name, value]) => ({ ...r, [name]: value }), {});
79 }
80 > policy.ts
81 > getPolicyValue(name: PolicyName): PolicyValue | undefined {
82 return this.policies.get(name);
83 }
84 > policy.ts
85 > serialize(): IStringDictionary<{ definition: PolicyDefinition; value: PolicyValue }> {
86 return Iterable.reduce<[PolicyName, PolicyDefinition], IStringDictionary<{ definition: PolicyDefinition; value: PolicyValue }>>(Object.entries(this.policyDefinitions), (r, [name, definition]) => ({ ...r, [name]: { definition: toSerializablePolicyDefinition(definition), value: this.policies.get(name)! } }), {});
87 }
88 > policy.ts
89 > protected abstract _updatePolicyDefinitions(policyDefinitions: IStringDictionary<PolicyDefinition>): Promise<void>;
90 > }
91 >
92 > export class NullPolicyService implements IPolicyService {
93 readonly _serviceBrand: undefined;
94 readonly onDidChange = Event.None;
97 serialize() { return undefined; }
98 policyDefinitions: IStringDictionary<PolicyDefinition> = {};
99 > } policy.ts
src/vs/workbench/services/environment/common/environmentService.ts 56 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- environmentService.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { refineServiceDecorator } from '../../../../platform/instantiation/common/instantiation.js';
7 > import { IPath } from '../../../../platform/window/common/window.js';
8 > import { IEnvironmentService } from '../../../../platform/environment/common/environment.js';
9 > import { URI } from '../../../../base/common/uri.js';
10 >
11 > export const IWorkbenchEnvironmentService = refineServiceDecorator<IEnvironmentService, IWorkbenchEnvironmentService>(IEnvironmentService);
12 >
13 > /**
14 > * A workbench specific environment service that is only present in workbench
15 > * layer.
16 > */
17 > export interface IWorkbenchEnvironmentService extends IEnvironmentService {
18 >
19 > // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
20 > // NOTE: KEEP THIS INTERFACE AS SMALL AS POSSIBLE. AS SUCH:
21 > // PUT NON-WEB PROPERTIES INTO THE NATIVE WORKBENCH
22 > // ENVIRONMENT SERVICE
23 > // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
24 >
25 > // --- Paths
26 > readonly logFile: URI;
27 > readonly windowLogsPath: URI;
28 > readonly extHostLogsPath: URI;
29 >
30 > // --- Extensions
31 > readonly extensionEnabledProposedApi?: string[];
32 >
33 > // --- Config
34 > readonly remoteAuthority?: string;
35 > readonly skipReleaseNotes: boolean;
36 > readonly skipWelcome: boolean;
37 > readonly disableWorkspaceTrust: boolean;
38 > readonly isSessionsWindow: boolean;
39 > readonly webviewExternalEndpoint: string;
40 >
41 > // --- Development
42 > readonly debugRenderer: boolean;
43 > readonly logExtensionHostCommunication?: boolean;
44 > readonly enableSmokeTestDriver?: boolean;
45 > readonly profDurationMarkers?: string[];
46 >
47 > // --- Editors to open
48 > readonly filesToOpenOrCreate?: IPath[] | undefined;
49 > readonly filesToDiff?: IPath[] | undefined;
50 > readonly filesToMerge?: IPath[] | undefined;
51 >
52 > // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
53 > // NOTE: KEEP THIS INTERFACE AS SMALL AS POSSIBLE. AS SUCH:
54 > // - PUT NON-WEB PROPERTIES INTO NATIVE WB ENV SERVICE
55 > // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
56 > }
src/vs/platform/userDataProfile/common/userDataProfileIpc.ts 55 covered LOC · 14 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- userDataProfileIpc.ts
2 > * Copyright (c) Microsoft 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 { IChannel, IServerChannel } from '../../../base/parts/ipc/common/ipc.js';
8 > import { URI, UriDto } from '../../../base/common/uri.js';
9 > import { DidChangeProfilesEvent, IUserDataProfile, IUserDataProfileOptions, IUserDataProfilesService, IUserDataProfileUpdateOptions, reviveProfile } from './userDataProfile.js';
10 > import { IAnyWorkspaceIdentifier } from '../../workspace/common/workspace.js';
11 > import { IURITransformer, transformIncomingURIs, transformOutgoingURIs } from '../../../base/common/uriIpc.js';
12 > import { Disposable } from '../../../base/common/lifecycle.js';
13 >
14 > export class RemoteUserDataProfilesServiceChannel implements IServerChannel {
15 >
16 > constructor(
17 private readonly service: IUserDataProfilesService,
18 private readonly getUriTransformer: (requestContext: any) => IURITransformer
19 ) { }
21 > listen(context: any, event: string): Event<any> {
22 const uriTransformer = this.getUriTransformer(context);
23 switch (event) {
33 throw new Error(`Invalid listen ${event}`);
34 }
36 > async call(context: any, command: string, args?: any): Promise<any> {
37 const uriTransformer = this.getUriTransformer(context);
38 switch (command) {
53 throw new Error(`Invalid call ${command}`);
54 }
56 >
57 > export class UserDataProfilesService extends Disposable implements IUserDataProfilesService {
58 >
59 > readonly _serviceBrand: undefined;
60 >
61 > get defaultProfile(): IUserDataProfile { return this.profiles[0]; }
62 > private _profiles: IUserDataProfile[] = [];
63 > get profiles(): IUserDataProfile[] { return this._profiles; }
64 >
65 > private readonly _onDidChangeProfiles = this._register(new Emitter<DidChangeProfilesEvent>());
66 > readonly onDidChangeProfiles = this._onDidChangeProfiles.event;
67 >
68 > readonly onDidResetWorkspaces: Event<void>;
69 >
70 > constructor(
71 profiles: readonly UriDto<IUserDataProfile>[],
72 readonly profilesHome: URI,
84 this.onDidResetWorkspaces = this.channel.listen<void>('onDidResetWorkspaces');
85 }
87 > async createNamedProfile(name: string, options?: IUserDataProfileOptions, workspaceIdentifier?: IAnyWorkspaceIdentifier): Promise<IUserDataProfile> {
88 const result = await this.channel.call<UriDto<IUserDataProfile>>('createNamedProfile', [name, options, workspaceIdentifier]);
89 return reviveProfile(result, this.profilesHome.scheme);
90 }
92 > async createProfile(id: string, name: string, options?: IUserDataProfileOptions, workspaceIdentifier?: IAnyWorkspaceIdentifier): Promise<IUserDataProfile> {
93 const result = await this.channel.call<UriDto<IUserDataProfile>>('createProfile', [id, name, options, workspaceIdentifier]);
94 return reviveProfile(result, this.profilesHome.scheme);
95 }
97 > async createTransientProfile(workspaceIdentifier?: IAnyWorkspaceIdentifier): Promise<IUserDataProfile> {
98 const result = await this.channel.call<UriDto<IUserDataProfile>>('createTransientProfile', [workspaceIdentifier]);
99 return reviveProfile(result, this.profilesHome.scheme);
100 }
102 > async setProfileForWorkspace(workspaceIdentifier: IAnyWorkspaceIdentifier, profile: IUserDataProfile): Promise<void> {
103 await this.channel.call<UriDto<IUserDataProfile>>('setProfileForWorkspace', [workspaceIdentifier, profile]);
104 }
106 > removeProfile(profile: IUserDataProfile): Promise<void> {
107 return this.channel.call('removeProfile', [profile]);
108 }
110 > async updateProfile(profile: IUserDataProfile, updateOptions: IUserDataProfileUpdateOptions): Promise<IUserDataProfile> {
111 const result = await this.channel.call<UriDto<IUserDataProfile>>('updateProfile', [profile, updateOptions]);
112 return reviveProfile(result, this.profilesHome.scheme);
113 }
115 > resetWorkspaces(): Promise<void> {
116 return this.channel.call('resetWorkspaces');
117 }
119 > cleanUp(): Promise<void> {
120 return this.channel.call('cleanUp');
121 }
123 > cleanUpTransientProfiles(): Promise<void> {
124 return this.channel.call('cleanUpTransientProfiles');
125 }
src/vs/workbench/api/common/extHostTypes/markdownString.ts 55 covered LOC · 17 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- markdownString.ts
2 > * Copyright (c) Microsoft 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 * as vscode from 'vscode';
7 > import { MarkdownString as BaseMarkdownString, MarkdownStringTrustedOptions } from '../../../../base/common/htmlContent.js';
8 > import { es5ClassCompat } from './es5ClassCompat.js';
9 >
10 > @es5ClassCompat
11 > export class MarkdownString implements vscode.MarkdownString {
12 >
13 > readonly #delegate: BaseMarkdownString;
14 >
15 > static isMarkdownString(thing: unknown): thing is vscode.MarkdownString {
16 > if (thing instanceof MarkdownString) {
17 > return true;
18 > }
19 > if (!thing || typeof thing !== 'object') {
20 > return false;
21 > }
22 > return (thing as vscode.MarkdownString).appendCodeblock && (thing as vscode.MarkdownString).appendMarkdown && (thing as vscode.MarkdownString).appendText && ((thing as vscode.MarkdownString).value !== undefined);
23 > }
24 >
25 > constructor(value?: string, supportThemeIcons: boolean = false) {
26 this.#delegate = new BaseMarkdownString(value, { supportThemeIcons });
27 }
29 > get value(): string {
30 return this.#delegate.value;
31 }
32 > set value(value: string) { markdownString.ts
33 this.#delegate.value = value;
34 }
36 > get isTrusted(): boolean | MarkdownStringTrustedOptions | undefined {
37 return this.#delegate.isTrusted;
38 }
40 > set isTrusted(value: boolean | MarkdownStringTrustedOptions | undefined) {
41 this.#delegate.isTrusted = value;
42 }
44 > get supportThemeIcons(): boolean | undefined {
45 return this.#delegate.supportThemeIcons;
46 }
48 > set supportThemeIcons(value: boolean | undefined) {
49 this.#delegate.supportThemeIcons = value;
50 }
52 > get supportHtml(): boolean | undefined {
53 return this.#delegate.supportHtml;
54 }
56 > set supportHtml(value: boolean | undefined) {
57 this.#delegate.supportHtml = value;
58 }
60 > get supportAlertSyntax(): boolean | undefined {
61 return this.#delegate.supportAlertSyntax;
62 }
64 > set supportAlertSyntax(value: boolean | undefined) {
65 this.#delegate.supportAlertSyntax = value;
66 }
68 > get baseUri(): vscode.Uri | undefined {
69 return this.#delegate.baseUri;
70 }
72 > set baseUri(value: vscode.Uri | undefined) {
73 this.#delegate.baseUri = value;
74 }
76 > appendText(value: string): vscode.MarkdownString {
77 this.#delegate.appendText(value);
78 return this;
79 }
81 > appendMarkdown(value: string): vscode.MarkdownString {
82 this.#delegate.appendMarkdown(value);
83 return this;
84 }
86 > appendCodeblock(value: string, language?: string): vscode.MarkdownString {
87 this.#delegate.appendCodeblock(language ?? '', value);
88 return this;
89 }
src/vs/workbench/contrib/chat/common/tools/promptTsxTypes.ts 55 covered LOC · 2 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- promptTsxTypes.ts
2 > * Copyright (c) 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 > * This is a subset of the types export from jsonTypes.d.ts in @vscode/prompt-tsx.
8 > * It's just the types needed to stringify prompt-tsx tool results.
9 > * It should be kept in sync with the types in that file.
10 > *
11 > * Note: do NOT use `declare` with const enums, esbuild doesn't inline them.
12 > * See https://github.com/evanw/esbuild/issues/4394
13 > */
14 >
15 > export const enum PromptNodeType {
16 > Piece = 1,
17 > Text = 2
18 > }
19 > export interface TextJSON {
20 > type: PromptNodeType.Text;
21 > text: string;
22 > lineBreakBefore: boolean | undefined;
23 > }
24 > /**
25 > * Constructor kind of the node represented by {@link PieceJSON}. This is
26 > * less descriptive than the actual constructor, as we only care to preserve
27 > * the element data that the renderer cares about.
28 > */
29 > export const enum PieceCtorKind {
30 > BaseChatMessage = 1,
31 > Other = 2,
32 > ImageChatMessage = 3
33 > }
34 > export interface BasePieceJSON {
35 > type: PromptNodeType.Piece;
36 > ctor: PieceCtorKind.BaseChatMessage | PieceCtorKind.Other;
37 > children: PromptNodeJSON[];
38 > }
39 > export interface ImageChatMessagePieceJSON {
40 > type: PromptNodeType.Piece;
41 > ctor: PieceCtorKind.ImageChatMessage;
42 > children: PromptNodeJSON[];
43 > props: {
44 > src: string;
45 > detail?: 'low' | 'high';
46 > };
47 > }
48 > export type PieceJSON = BasePieceJSON | ImageChatMessagePieceJSON;
49 > export type PromptNodeJSON = PieceJSON | TextJSON;
50 > export interface PromptElementJSON {
51 > node: PieceJSON;
52 > }
53 >
54 > export function stringifyPromptElementJSON(element: PromptElementJSON): string {
55 const strs: string[] = [];
56 stringifyPromptNodeJSON(element.node, strs);
57 return strs.join('');
58 }
60 function stringifyPromptNodeJSON(node: PromptNodeJSON, strs: string[]): void {
61 if (node.type === PromptNodeType.Text) {
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/workbench/api/common/extHostWindow.ts 54 covered LOC · 10 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostWindow.ts
2 > * Copyright (c) Microsoft 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 { Schemas } from '../../../base/common/network.js';
8 > import { isFalsyOrWhitespace } from '../../../base/common/strings.js';
9 > import { URI } from '../../../base/common/uri.js';
10 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
11 > import { IExtHostRpcService } from './extHostRpcService.js';
12 > import { WindowState } from 'vscode';
13 > import { ExtHostWindowShape, IOpenUriOptions, MainContext, MainThreadWindowShape } from './extHost.protocol.js';
14 > import { IExtHostInitDataService } from './extHostInitDataService.js';
15 > import { decodeBase64 } from '../../../base/common/buffer.js';
16 >
17 > export class ExtHostWindow implements ExtHostWindowShape {
18 >
19 > declare _serviceBrand: undefined;
20 >
21 > private static InitialState: WindowState = {
22 > focused: true,
23 > active: true,
24 > };
25 >
26 > private _proxy: MainThreadWindowShape;
27 >
28 > private readonly _onDidChangeWindowState = new Emitter<WindowState>();
29 > readonly onDidChangeWindowState: Event<WindowState> = this._onDidChangeWindowState.event;
30 >
31 > private _nativeHandle: Uint8Array | undefined;
32 > private _state = ExtHostWindow.InitialState;
33 >
34 > getState(): WindowState {
35 // todo@connor4312: this can be changed to just return this._state after proposed api is finalized
36 const state = this._state;
45 };
46 }
48 > constructor(
49 @IExtHostInitDataService initData: IExtHostInitDataService,
50 @IExtHostRpcService extHostRpc: IExtHostRpcService
59 });
60 }
62 > get nativeHandle(): Uint8Array | undefined {
63 return this._nativeHandle;
64 }
66 > $onDidChangeActiveNativeWindowHandle(handle: string | undefined): void {
67 this._nativeHandle = handle ? decodeBase64(handle).buffer : undefined;
68 }
70 > $onDidChangeWindowFocus(value: boolean) {
71 this.onDidChangeWindowProperty('focused', value);
72 }
74 > $onDidChangeWindowActive(value: boolean) {
75 this.onDidChangeWindowProperty('active', value);
76 }
78 > onDidChangeWindowProperty(property: keyof WindowState, value: boolean): void {
79 if (value === this._state[property]) {
80 return;
84 this._onDidChangeWindowState.fire(this._state);
85 }
87 > openUri(stringOrUri: string | URI, options: IOpenUriOptions): Promise<boolean> {
88 let uriAsString: string | undefined;
89 if (typeof stringOrUri === 'string') {
102 return this._proxy.$openUri(stringOrUri, uriAsString, options);
103 }
105 > async asExternalUri(uri: URI, options: IOpenUriOptions): Promise<URI> {
106 if (isFalsyOrWhitespace(uri.scheme)) {
107 return Promise.reject('Invalid scheme - cannot be empty');
111 return URI.from(result);
112 }
114 >
115 > export const IExtHostWindow = createDecorator<IExtHostWindow>('IExtHostWindow');
116 > export interface IExtHostWindow extends ExtHostWindow, ExtHostWindowShape { }
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/workbench/api/common/extHostTypes/diagnostic.ts 53 covered LOC · 7 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- diagnostic.ts
2 > * Copyright (c) Microsoft 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 { URI } from '../../../../base/common/uri.js';
8 > import { es5ClassCompat } from './es5ClassCompat.js';
9 > import { Location } from './location.js';
10 > import { Range } from './range.js';
11 >
12 > export enum DiagnosticTag {
13 > Unnecessary = 1,
14 > Deprecated = 2
15 > }
16 >
17 > export enum DiagnosticSeverity {
18 > Hint = 3,
19 > Information = 2,
20 > Warning = 1,
21 > Error = 0
22 > }
23 >
24 > @es5ClassCompat
25 > export class DiagnosticRelatedInformation {
26 >
27 > static is(thing: unknown): thing is DiagnosticRelatedInformation {
28 if (!thing) {
29 return false;
34 && URI.isUri((<DiagnosticRelatedInformation>thing).location.uri);
35 }
37 > location: Location;
38 > message: string;
39 >
40 > constructor(location: Location, message: string) {
41 this.location = location;
42 this.message = message;
43 }
45 > static isEqual(a: DiagnosticRelatedInformation, b: DiagnosticRelatedInformation): boolean {
46 if (a === b) {
47 return true;
54 && a.location.uri.toString() === b.location.uri.toString();
55 }
56 > } diagnostic.ts
57 >
58 > @es5ClassCompat
59 > export class Diagnostic {
60 >
61 > range: Range;
62 > message: string;
63 > severity: DiagnosticSeverity;
64 > source?: string;
65 > code?: string | number;
66 > relatedInformation?: DiagnosticRelatedInformation[];
67 > tags?: DiagnosticTag[];
68 >
69 > constructor(range: Range, message: string, severity: DiagnosticSeverity = DiagnosticSeverity.Error) {
70 if (!Range.isRange(range)) {
71 throw new TypeError('range must be set');
78 this.severity = severity;
79 }
81 > toJSON(): { severity: string; message: string; range: Range; source?: string; code?: string | number } {
82 return {
83 severity: DiagnosticSeverity[this.severity],
88 };
89 }
91 > static isEqual(a: Diagnostic | undefined, b: Diagnostic | undefined): boolean {
92 if (a === b) {
93 return true;
105 && equals(a.relatedInformation, b.relatedInformation, DiagnosticRelatedInformation.isEqual);
106 }
107 > } diagnostic.ts
src/vs/workbench/api/common/extHostTypes/position.ts 53 covered LOC · 18 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 > import type * as vscode from 'vscode';
7 > import { illegalArgument } from '../../../../base/common/errors.js';
8 > import { es5ClassCompat } from './es5ClassCompat.js';
9 >
10 > @es5ClassCompat
11 > export class Position {
12 >
13 > static Min(...positions: Position[]): Position {
14 if (positions.length === 0) {
15 throw new TypeError();
24 return result;
25 }
27 > static Max(...positions: Position[]): Position {
28 if (positions.length === 0) {
29 throw new TypeError();
38 return result;
39 }
41 > static isPosition(other: unknown): other is Position {
42 if (!other) {
43 return false;
52 return false;
53 }
55 > static of(obj: vscode.Position): Position {
56 if (obj instanceof Position) {
57 return obj;
61 throw new Error('Invalid argument, is NOT a position-like object');
62 }
64 > private _line: number;
65 > private _character: number;
66 >
67 > get line(): number {
68 return this._line;
69 }
71 > get character(): number {
72 return this._character;
73 }
75 > constructor(line: number, character: number) {
76 if (line < 0) {
77 throw illegalArgument('line must be non-negative');
83 this._character = character;
84 }
86 > isBefore(other: Position): boolean {
87 if (this._line < other._line) {
88 return true;
93 return this._character < other._character;
94 }
96 > isBeforeOrEqual(other: Position): boolean {
97 if (this._line < other._line) {
98 return true;
103 return this._character <= other._character;
104 }
105 > position.ts
106 > isAfter(other: Position): boolean {
107 return !this.isBeforeOrEqual(other);
108 }
109 > position.ts
110 > isAfterOrEqual(other: Position): boolean {
111 return !this.isBefore(other);
112 }
113 > position.ts
114 > isEqual(other: Position): boolean {
115 return this._line === other._line && this._character === other._character;
116 }
117 > position.ts
118 > compareTo(other: Position): number {
119 if (this._line < other._line) {
120 return -1;
133 }
134 }
135 > position.ts
136 > translate(change: { lineDelta?: number; characterDelta?: number }): Position;
137 > translate(lineDelta?: number, characterDelta?: number): Position;
138 > translate(lineDeltaOrChange: number | undefined | { lineDelta?: number; characterDelta?: number }, characterDelta: number = 0): Position {
139
140 if (lineDeltaOrChange === null || characterDelta === null) {
157 return new Position(this.line + lineDelta, this.character + characterDelta);
158 }
159 > position.ts
160 > with(change: { line?: number; character?: number }): Position;
161 > with(line?: number, character?: number): Position;
162 > with(lineOrChange: number | undefined | { line?: number; character?: number }, character: number = this.character): Position {
163
164 if (lineOrChange === null || character === null) {
183 return new Position(line, character);
184 }
185 > position.ts
186 > toJSON(): { line: number; character: number } {
187 return { line: this.line, character: this.character };
188 }
189 > position.ts
190 > [Symbol.for('debug.description')]() {
191 return `(${this.line}:${this.character})`;
192 }
193 > } position.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/platform/remote/common/remoteHosts.ts 52 covered LOC · 7 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- remoteHosts.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { Schemas } from '../../../base/common/network.js';
7 > import { URI } from '../../../base/common/uri.js';
8 >
9 > export function getRemoteAuthority(uri: URI): string | undefined {
10 return uri.scheme === Schemas.vscodeRemote ? uri.authority : undefined;
11 }
13 > export function getRemoteName(authority: string): string;
14 > export function getRemoteName(authority: undefined): undefined;
15 > export function getRemoteName(authority: string | undefined): string | undefined;
16 > export function getRemoteName(authority: string | undefined): string | undefined {
17 if (!authority) {
18 return undefined;
25 return authority.substr(0, pos);
26 }
28 > /**
29 > * Returns the suffix part of the authority after the '+' character.
30 > * For remote connections, this is typically the server/tunnel identifier.
31 > * Examples:
32 > * - For tunnels: `tunnel+myTunnel` returns `myTunnel`
33 > * - For SSH: `ssh+myserver` returns `myserver`
34 > * - For localhost: `localhost:8000` returns `undefined`
35 > * @param authority The remote authority string.
36 > * @returns The suffix after the '+' character, or undefined if there is no '+' character.
37 > */
38 > export function getRemoteServerRootPath(authority: string): string | undefined;
39 > export function getRemoteServerRootPath(authority: undefined): undefined;
40 > export function getRemoteServerRootPath(authority: string | undefined): string | undefined;
41 > export function getRemoteServerRootPath(authority: string | undefined): string | undefined {
42 if (!authority) {
43 return undefined;
49 return authority.substring(pos + 1);
50 }
52 > export function parseAuthorityWithPort(authority: string): { host: string; port: number } {
53 const { host, port } = parseAuthority(authority);
54 if (typeof port === 'undefined') {
57 return { host, port };
58 }
60 > export function parseAuthorityWithOptionalPort(authority: string, defaultPort: number): { host: string; port: number } {
61 let { host, port } = parseAuthority(authority);
62 if (typeof port === 'undefined') {
65 return { host, port };
66 }
68 function parseAuthority(authority: string): { host: string; port: number | undefined } {
69 // check for ipv6 with port
88 return { host: authority, port: undefined };
89 }
91 > const loopbackHosts = new Set([
92 > 'localhost',
93 > '127.0.0.1',
94 > '::1',
95 > '[::1]',
96 > '0000:0000:0000:0000:0000:0000:0000:0001',
97 > '[0000:0000:0000:0000:0000:0000:0000:0001]'
98 > ]);
99 >
100 > /**
101 > * Returns whether the given host (as found in a direct `<host>:<port>` remote
102 > * authority) refers to the local loopback interface. The check is intentionally
103 > * strict: only `localhost` and the IPv4/IPv6 loopback literals are considered
104 > * local. Any other host (a routable IP address or a hostname) is treated as a
105 > * connection that leaves the local machine.
106 > */
107 > export function isLoopbackHost(host: string): boolean {
108 return loopbackHosts.has(host.toLowerCase());
109 }
src/vs/workbench/services/notebook/common/notebookDocumentService.ts 52 covered LOC · 10 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- notebookDocumentService.ts
2 > * Copyright (c) Microsoft 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, decodeBase64, encodeBase64 } from '../../../../base/common/buffer.js';
7 > import { ResourceMap } from '../../../../base/common/map.js';
8 > import { Schemas } from '../../../../base/common/network.js';
9 > import { URI } from '../../../../base/common/uri.js';
10 > import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';
11 > import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
12 >
13 > export const INotebookDocumentService = createDecorator<INotebookDocumentService>('notebookDocumentService');
14 >
15 > export interface INotebookDocument {
16 > readonly uri: URI;
17 > getCellIndex(cellUri: URI): number | undefined;
18 > }
19 >
20 > const _lengths = ['W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f'];
21 > const _padRegexp = new RegExp(`^[${_lengths.join('')}]+`);
22 > const _radix = 7;
23 > export function parse(cell: URI): { notebook: URI; handle: number } | undefined {
24 if (cell.scheme !== Schemas.vscodeNotebookCell) {
25 return undefined;
42 };
43 }
45 > export function generate(notebook: URI, handle: number): URI {
46
47 const s = handle.toString(_radix);
51 return notebook.with({ scheme: Schemas.vscodeNotebookCell, fragment });
52 }
54 > export function parseMetadataUri(metadata: URI): URI | undefined {
55 if (metadata.scheme !== Schemas.vscodeNotebookMetadata) {
56 return undefined;
61 return metadata.with({ scheme: _scheme, fragment: null });
62 }
64 > export function generateMetadataUri(notebook: URI): URI {
65 const fragment = `${encodeBase64(VSBuffer.fromString(notebook.scheme), true, true)}`;
66 return notebook.with({ scheme: Schemas.vscodeNotebookMetadata, fragment });
67 }
69 > export function extractCellOutputDetails(uri: URI): { notebook: URI; openIn: string; outputId?: string; cellFragment?: string; outputIndex?: number; cellHandle?: number; cellIndex?: number } | undefined {
70 if (uri.scheme !== Schemas.vscodeNotebookCellOutput) {
71 return;
97 };
98 }
100 >
101 > export interface INotebookDocumentService {
102 > readonly _serviceBrand: undefined;
103 >
104 > getNotebook(uri: URI): INotebookDocument | undefined;
105 > addNotebookDocument(document: INotebookDocument): void;
106 > removeNotebookDocument(document: INotebookDocument): void;
107 > }
108 >
109 > export class NotebookDocumentWorkbenchService implements INotebookDocumentService {
110 declare readonly _serviceBrand: undefined;
111
112 private readonly _documents = new ResourceMap<INotebookDocument>();
114 > getNotebook(uri: URI): INotebookDocument | undefined {
115 if (uri.scheme === Schemas.vscodeNotebookCell) {
116 const cellUri = parse(uri);
134 return this._documents.get(uri);
135 }
137 > addNotebookDocument(document: INotebookDocument) {
138 this._documents.set(document.uri, document);
139 }
141 > removeNotebookDocument(document: INotebookDocument) {
142 this._documents.delete(document.uri);
143 }
145 > }
146 >
147 > registerSingleton(INotebookDocumentService, NotebookDocumentWorkbenchService, InstantiationType.Delayed);
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/platform/agentHost/common/agentHostSessionType.ts 51 covered LOC · 7 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- agentHostSessionType.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { type AgentProvider } from './agentService.js';
7 >
8 > const REMOTE_AGENT_HOST_SESSION_TYPE_PREFIX = 'remote-';
9 >
10 > /**
11 > * Builds the unique per-connection identifier for a remote agent host.
12 > *
13 > * This string is used as the resource URI scheme registered via
14 > * `registerChatSessionContentProvider` and as the language model vendor /
15 > * `targetChatSessionType` published by `AgentHostLanguageModelProvider`.
16 > */
17 > export function remoteAgentHostSessionTypeId(connectionAuthority: string, agentProvider: AgentProvider): string {
18 return `${remoteAgentHostSessionTypeAuthorityPrefix(connectionAuthority)}${agentProvider}`;
19 }
21 > /**
22 > * Builds the authority-specific prefix for remote agent host session types.
23 > */
24 > export function remoteAgentHostSessionTypeAuthorityPrefix(connectionAuthority: string): string {
25 return `${REMOTE_AGENT_HOST_SESSION_TYPE_PREFIX}${connectionAuthority}-`;
26 }
28 > /**
29 > * Returns whether the given session type uses the remote agent host scheme.
30 > */
31 > export function isRemoteAgentHostSessionType(sessionType: string): boolean {
32 return sessionType.startsWith(REMOTE_AGENT_HOST_SESSION_TYPE_PREFIX);
33 }
35 > /**
36 > * Finds the best matching remote agent host authority from a known candidate set.
37 > *
38 > * Remote session types are formatted as `remote-{authority}-{provider}` and
39 > * authorities may contain `-`, so callers should match against the full set of
40 > * known authorities instead of splitting the session type.
41 > */
42 > export function findRemoteAgentHostSessionTypeAuthority(sessionType: string, connectionAuthorities: Iterable<string>): string | undefined {
43 if (!isRemoteAgentHostSessionType(sessionType)) {
44 return undefined;
53 return bestMatch;
54 }
56 function isRemoteAgentHostSessionTypeForAuthority(sessionType: string, connectionAuthority: string): boolean {
57 return !!connectionAuthority && sessionType.startsWith(remoteAgentHostSessionTypeAuthorityPrefix(connectionAuthority));
58 }
60 > /**
61 > * Extracts the harness/provider suffix from a remote agent host session type.
62 > *
63 > * Remote session types are formatted as `remote-{authority}-{provider}`. The
64 > * authority may contain `-`, but provider names do not, so the harness is the
65 > * final `-`-delimited segment. Returns `undefined` for non-remote session types.
66 > */
67 > export function parseRemoteAgentHostHarness(sessionType: string): string | undefined {
68 if (!isRemoteAgentHostSessionType(sessionType)) {
69 return undefined;
73 return harness || undefined;
74 }
76 > /**
77 > * Extracts the connection authority from a remote agent host session type when the provider is known.
78 > */
79 > export function parseRemoteAgentHostSessionTypeAuthority(sessionType: string, agentProvider: AgentProvider): string | undefined {
80 if (!isRemoteAgentHostSessionType(sessionType)) {
81 return undefined;
src/vs/workbench/api/common/extHostTypes/range.ts 51 covered LOC · 15 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 type * as vscode from 'vscode';
7 > import { illegalArgument } from '../../../../base/common/errors.js';
8 > import { es5ClassCompat } from './es5ClassCompat.js';
9 > import { Position } from './position.js';
10 >
11 > @es5ClassCompat
12 > export class Range {
13 >
14 > static isRange(thing: unknown): thing is vscode.Range {
15 if (thing instanceof Range) {
16 return true;
22 && Position.isPosition((<Range>thing).end);
23 }
24 > range.ts
25 > static of(obj: vscode.Range): Range {
26 if (obj instanceof Range) {
27 return obj;
32 throw new Error('Invalid argument, is NOT a range-like object');
33 }
34 > range.ts
35 > protected _start: Position;
36 > protected _end: Position;
37 >
38 > get start(): Position {
39 return this._start;
40 }
41 > range.ts
42 > get end(): Position {
43 return this._end;
44 }
45 > range.ts
46 > constructor(start: vscode.Position, end: vscode.Position);
47 > constructor(start: Position, end: Position);
48 > constructor(startLine: number, startColumn: number, endLine: number, endColumn: number);
49 > constructor(startLineOrStart: number | Position | vscode.Position, startColumnOrEnd: number | Position | vscode.Position, endLine?: number, endColumn?: number) {
50 let start: Position | undefined;
51 let end: Position | undefined;
71 }
72 }
73 > range.ts
74 > contains(positionOrRange: Position | Range): boolean {
75 if (Range.isRange(positionOrRange)) {
76 return this.contains(positionOrRange.start)
88 return false;
89 }
90 > range.ts
91 > isEqual(other: Range): boolean {
92 return this._start.isEqual(other._start) && this._end.isEqual(other._end);
93 }
94 > range.ts
95 > intersection(other: Range): Range | undefined {
96 const start = Position.Max(other.start, this._start);
97 const end = Position.Min(other.end, this._end);
104 return new Range(start, end);
105 }
106 > range.ts
107 > union(other: Range): Range {
108 if (this.contains(other)) {
109 return this;
115 return new Range(start, end);
116 }
117 > range.ts
118 > get isEmpty(): boolean {
119 return this._start.isEqual(this._end);
120 }
121 > range.ts
122 > get isSingleLine(): boolean {
123 return this._start.line === this._end.line;
124 }
125 > range.ts
126 > with(change: { start?: Position; end?: Position }): Range;
127 > with(start?: Position, end?: Position): Range;
128 > with(startOrChange: Position | undefined | { start?: Position; end?: Position }, end: Position = this.end): Range {
129
130 if (startOrChange === null || end === null) {
149 return new Range(start, end);
150 }
151 > range.ts
152 > toJSON(): unknown {
153 return [this.start, this.end];
154 }
155 > range.ts
156 > [Symbol.for('debug.description')]() {
157 return getDebugDescriptionOfRange(this);
158 }
159 > } range.ts
160 >
161 > export function getDebugDescriptionOfRange(range: vscode.Range): string {
162 return range.isEmpty
163 ? `[${range.start.line}:${range.start.character})`
src/vs/base/common/assert.ts 50 covered LOC · 9 ranges

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- mcpGalleryManifest.ts
2 > * Copyright (c) Microsoft 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 { createDecorator } from '../../instantiation/common/instantiation.js';
8 >
9 > export const enum McpGalleryResourceType {
10 > McpServersQueryService = 'McpServersQueryService',
11 > McpServerWebUri = 'McpServerWebUriTemplate',
12 > McpServerVersionUri = 'McpServerVersionUriTemplate',
13 > McpServerIdUri = 'McpServerIdUriTemplate',
14 > McpServerLatestVersionUri = 'McpServerLatestVersionUriTemplate',
15 > McpServerNamedResourceUri = 'McpServerNamedResourceUriTemplate',
16 > PublisherUriTemplate = 'PublisherUriTemplate',
17 > ContactSupportUri = 'ContactSupportUri',
18 > PrivacyPolicyUri = 'PrivacyPolicyUri',
19 > TermsOfServiceUri = 'TermsOfServiceUri',
20 > ReportUri = 'ReportUri',
21 > }
22 >
23 > export type McpGalleryManifestResource = {
24 > readonly id: string;
25 > readonly type: string;
26 > };
27 >
28 > export interface IMcpGalleryManifest {
29 > readonly version: string;
30 > readonly url: string;
31 > readonly resources: readonly McpGalleryManifestResource[];
32 > }
33 >
34 > export const enum McpGalleryManifestStatus {
35 > Available = 'available',
36 > Unavailable = 'unavailable'
37 > }
38 >
39 > export const IMcpGalleryManifestService = createDecorator<IMcpGalleryManifestService>('IMcpGalleryManifestService');
40 >
41 > export interface IMcpGalleryManifestService {
42 > readonly _serviceBrand: undefined;
43 >
44 > readonly mcpGalleryManifestStatus: McpGalleryManifestStatus;
45 > readonly onDidChangeMcpGalleryManifestStatus: Event<McpGalleryManifestStatus>;
46 > readonly onDidChangeMcpGalleryManifest: Event<IMcpGalleryManifest | null>;
47 > getMcpGalleryManifest(): Promise<IMcpGalleryManifest | null>;
48 > }
49 >
50 > export function getMcpGalleryManifestResourceUri(manifest: IMcpGalleryManifest, type: string): string | undefined {
51 const [name, version] = type.split('/');
52 for (const resource of manifest.resources) {
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/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/workbench/contrib/chat/common/model/chatUri.ts 49 covered LOC · 8 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- chatUri.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { encodeBase64, VSBuffer, decodeBase64 } from '../../../../../base/common/buffer.js';
7 > import { Schemas } from '../../../../../base/common/network.js';
8 > import { URI } from '../../../../../base/common/uri.js';
9 > import { localChatSessionType } from '../chatSessionsService.js';
10 >
11 > type ChatSessionIdentifier = {
12 > readonly chatSessionType: string;
13 > readonly sessionId: string;
14 > };
15 >
16 >
17 > export namespace LocalChatSessionUri {
18 >
19 > export const scheme = Schemas.vscodeLocalChatSession;
20 >
21 > export function forSession(sessionId: string): URI {
22 const encodedId = encodeBase64(VSBuffer.wrap(new TextEncoder().encode(sessionId)), false, true);
23 return URI.from({ scheme, authority: localChatSessionType, path: '/' + encodedId });
24 }
25 > chatUri.ts
26 > export function getNewSessionUri(): URI {
27 const handle = Math.floor(Math.random() * 1e9);
28 return forSession(`chat-${handle}`);
29 }
30 > chatUri.ts
31 > export function parseLocalSessionId(resource: URI): string | undefined {
32 const parsed = parse(resource);
33 return parsed?.chatSessionType === localChatSessionType ? parsed.sessionId : undefined;
34 }
35 > chatUri.ts
36 > export function isLocalSession(resource: URI): boolean {
37 return !!parseLocalSessionId(resource);
38 }
39 > chatUri.ts
40 > function parse(resource: URI): ChatSessionIdentifier | undefined {
41 if (resource.scheme !== scheme) {
42 return undefined;
56 return { chatSessionType, sessionId: new TextDecoder().decode(decodedSessionId.buffer) };
57 }
58 > } chatUri.ts
59 >
60 > /**
61 > * Converts a chat session resource URI to a string ID.
62 > *
63 > * This exists mainly for backwards compatibility with existing code that uses string IDs in telemetry and storage.
64 > */
65 > export function chatSessionResourceToId(resource: URI): string {
66 // If we have a local session, prefer using just the id part
67 const localId = LocalChatSessionUri.parseLocalSessionId(resource);
72 return resource.toString();
73 }
74 > chatUri.ts
75 > /**
76 > * Extracts the chat session type from a resource URI.
77 > *
78 > * @param resource - The chat session resource URI
79 > * @returns The session type string. Returns `localChatSessionType` for local sessions
80 > * (vscodeChatEditor and vscodeLocalChatSession schemes), or the scheme/authority
81 > * for contributed sessions.
82 > */
83 > export function getChatSessionType(resource: URI): string {
84 if (resource.scheme === Schemas.vscodeChatEditor) {
85 return localChatSessionType;
92 return resource.scheme;
93 }
94 > chatUri.ts
95 > export function isUntitledChatSession(resource: URI): boolean {
96 return resource.path.startsWith('/untitled-');
97 }
src/vs/base/common/managedSettings.ts 48 covered LOC · 2 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- managedSettings.ts
2 > * Copyright (c) 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 single enterprise-managed marketplace entry, preserving the marketplace
8 > * name (used as `displayLabel`) and the original `source` discriminator.
9 > */
10 > export type IExtraKnownMarketplaceEntry =
11 > | { readonly name: string; readonly source: { readonly source: 'github'; readonly repo: string; readonly ref?: string } }
12 > | { readonly name: string; readonly source: { readonly source: 'git'; readonly url: string; readonly ref?: string } };
13 >
14 > /**
15 > * A single entry in the enterprise-managed `strictKnownMarketplaces` allowlist
16 > * (the `chat.plugins.strictMarketplaces` setting), a discriminated union on
17 > * `source`. Delivered as JSON via managed settings (the server endpoint or
18 > * native MDM) and validated at match time, so the optional fields are only
19 > * meaningful for their corresponding `source`.
20 > */
21 > export interface IStrictMarketplaceSource {
22 > readonly source: 'github' | 'git' | 'url' | 'npm' | 'file' | 'directory' | 'hostPattern' | 'pathPattern';
23 > readonly repo?: string;
24 > readonly url?: string;
25 > readonly ref?: string;
26 > readonly path?: string;
27 > readonly package?: string;
28 > readonly hostPattern?: string;
29 > readonly pathPattern?: string;
30 > readonly headers?: Readonly<Record<string, string>>;
31 > }
32 >
33 > /**
34 > * Converts an {@link IExtraKnownMarketplaceEntry} array into the
35 > * `{ [name]: url-or-shorthand }` dict stored on the `chat.plugins.extraMarketplaces`
36 > * setting (and carried as the canonical JSON value of the `extraKnownMarketplaces`
37 > * managed setting across both the server endpoint and native MDM delivery).
38 > *
39 > * Plain-string entries (allowed by the policy schema but unnamed) are stored with
40 > * the value used as both key and value so they survive the round-trip intact.
41 > *
42 > * Marketplace names come from managed settings (untrusted input) and are written as object keys,
43 > * so `__proto__` / `constructor` / `prototype` keys are skipped to avoid prototype pollution
44 > * (mirroring the guard in the managed-settings normalizer's string-map encoder).
45 > */
46 > export function extraKnownMarketplacesToConfigDict(entries: readonly (string | IExtraKnownMarketplaceEntry)[] | undefined): Record<string, string> | undefined {
47 if (!entries?.length) {
48 return undefined;
66 return obj;
67 }
69 > /** Whether a marketplace name would pollute the prototype chain if used as an object key. */
70 function isUnsafeMarketplaceKey(key: string): boolean {
71 return key === '__proto__' || key === 'constructor' || key === 'prototype';
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/workbench/api/common/extHostMemento.ts 48 covered LOC · 9 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostMemento.ts
2 > * Copyright (c) Microsoft 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 * as vscode from 'vscode';
7 > import { IDisposable } from '../../../base/common/lifecycle.js';
8 > import { ExtHostStorage } from './extHostStorage.js';
9 > import { IExtensionDescription } from '../../../platform/extensions/common/extensions.js';
10 > import { DeferredPromise, RunOnceScheduler } from '../../../base/common/async.js';
11 >
12 > export class ExtensionMemento implements vscode.Memento {
13 >
14 > protected readonly _id: string;
15 > private readonly _shared: boolean;
16 > protected readonly _storage: ExtHostStorage;
17 >
18 > private readonly _init: Promise<ExtensionMemento>;
19 > private _value?: { [n: string]: any };
20 > private readonly _storageListener: IDisposable;
21 >
22 > private _deferredPromises: Map<string, DeferredPromise<void>> = new Map();
23 > private _scheduler: RunOnceScheduler;
24 >
25 > constructor(id: string, global: boolean, storage: ExtHostStorage) {
26 this._id = id;
27 this._shared = global;
56 }, 0);
57 }
59 > keys(): readonly string[] {
60 // Filter out `undefined` values, as they can stick around in the `_value` until the `onDidChangeStorage` event runs
61 return Object.entries(this._value ?? {}).filter(([, value]) => value !== undefined).map(([key]) => key);
62 }
64 > get whenReady(): Promise<ExtensionMemento> {
65 return this._init;
66 }
68 > get<T>(key: string): T | undefined;
69 > get<T>(key: string, defaultValue: T): T;
70 > get<T>(key: string, defaultValue?: T): T {
71 let value = this._value![key];
72 if (typeof value === 'undefined') {
75 return value;
76 }
78 > update(key: string, value: any): Promise<void> {
79 if (value !== null && typeof value === 'object') {
80 // Prevent the value from being as-is for until we have
101 return promise.p;
102 }
104 > dispose(): void {
105 this._storageListener.dispose();
106 }
108 >
109 > export class ExtensionGlobalMemento extends ExtensionMemento {
110 >
111 > private readonly _extension: IExtensionDescription;
112 >
113 > setKeysForSync(keys: string[]): void {
114 this._storage.registerExtensionStorageKeysToSync({ id: this._id, version: this._extension.version }, keys);
115 }
117 > constructor(extensionDescription: IExtensionDescription, storage: ExtHostStorage) {
118 super(extensionDescription.identifier.value, true, storage);
119 this._extension = extensionDescription;
120 }
122 > }
src/vs/workbench/api/common/extHostTypes/textEdit.ts 48 covered LOC · 14 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 { illegalArgument } from '../../../../base/common/errors.js';
7 > import { es5ClassCompat } from './es5ClassCompat.js';
8 > import { Position } from './position.js';
9 > import { Range } from './range.js';
10 >
11 > export enum EndOfLine {
12 > LF = 1,
13 > CRLF = 2
14 > }
15 >
16 > @es5ClassCompat
17 > export class TextEdit {
18 >
19 > static isTextEdit(thing: unknown): thing is TextEdit {
20 if (thing instanceof TextEdit) {
21 return true;
27 && typeof (<TextEdit>thing).newText === 'string';
28 }
30 > static replace(range: Range, newText: string): TextEdit {
31 return new TextEdit(range, newText);
32 }
34 > static insert(position: Position, newText: string): TextEdit {
35 return TextEdit.replace(new Range(position, position), newText);
36 }
38 > static delete(range: Range): TextEdit {
39 return TextEdit.replace(range, '');
40 }
42 > static setEndOfLine(eol: EndOfLine): TextEdit {
43 const ret = new TextEdit(new Range(new Position(0, 0), new Position(0, 0)), '');
44 ret.newEol = eol;
45 return ret;
46 }
48 > protected _range: Range;
49 > protected _newText: string | null;
50 > protected _newEol?: EndOfLine;
51 >
52 > get range(): Range {
53 return this._range;
54 }
56 > set range(value: Range) {
57 if (value && !Range.isRange(value)) {
58 throw illegalArgument('range');
60 this._range = value;
61 }
63 > get newText(): string {
64 return this._newText || '';
65 }
67 > set newText(value: string) {
68 if (value && typeof value !== 'string') {
69 throw illegalArgument('newText');
71 this._newText = value;
72 }
74 > get newEol(): EndOfLine | undefined {
75 return this._newEol;
76 }
78 > set newEol(value: EndOfLine | undefined) {
79 if (value && typeof value !== 'number') {
80 throw illegalArgument('newEol');
82 this._newEol = value;
83 }
85 > constructor(range: Range, newText: string | null) {
86 this._range = range;
87 this._newText = newText;
88 }
90 > toJSON(): { range: Range; newText: string; newEol: EndOfLine | undefined } {
91 return {
92 range: this.range,
src/vs/base/common/iconLabels.ts 47 covered LOC · 6 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- iconLabels.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IMatch, matchesFuzzy } from './filters.js';
7 > import { ltrim } from './strings.js';
8 > import { ThemeIcon } from './themables.js';
9 >
10 > const iconStartMarker = '$(';
11 >
12 > const iconsRegex = new RegExp(`\\$\\(${ThemeIcon.iconNameExpression}(?:${ThemeIcon.iconModifierExpression})?\\)`, 'g'); // no capturing groups
13 >
14 > const escapeIconsRegex = new RegExp(`(\\\\)?${iconsRegex.source}`, 'g');
15 > export function escapeIcons(text: string): string {
16 return text.replace(escapeIconsRegex, (match, escaped) => escaped ? match : `\\${match}`);
17 }
19 > const markdownEscapedIconsRegex = new RegExp(`\\\\${iconsRegex.source}`, 'g');
20 > export function markdownEscapeEscapedIcons(text: string): string {
21 // Need to add an extra \ for escaping in markdown
22 return text.replace(markdownEscapedIconsRegex, match => `\\${match}`);
23 }
25 > const stripIconsRegex = new RegExp(`(\\s)?(\\\\)?${iconsRegex.source}(\\s)?`, 'g');
26 >
27 > /**
28 > * Takes a label with icons (`$(iconId)xyz`) and strips the icons out (`xyz`)
29 > */
30 > export function stripIcons(text: string): string {
31 if (text.indexOf(iconStartMarker) === -1) {
32 return text;
35 return text.replace(stripIconsRegex, (match, preWhitespace, escaped, postWhitespace) => escaped ? match : preWhitespace || postWhitespace || '');
36 }
38 >
39 > /**
40 > * Takes a label with icons (`$(iconId)xyz`), removes the icon syntax adds whitespace so that screen readers can read the text better.
41 > */
42 > export function getCodiconAriaLabel(text: string | undefined) {
43 if (!text) {
44 return '';
47 return text.replace(/\$\((.*?)\)/g, (_match, codiconName) => ` ${codiconName} `).trim();
48 }
50 >
51 > export interface IParsedLabelWithIcons {
52 > readonly text: string;
53 > readonly iconOffsets?: readonly number[];
54 > }
55 >
56 > const _parseIconsRegex = new RegExp(`\\$\\(${ThemeIcon.iconNameCharacter}+\\)`, 'g');
57 >
58 > /**
59 > * Takes a label with icons (`abc $(iconId)xyz`) and returns the text (`abc xyz`) and the offsets of the icons (`[3]`)
60 > */
61 > export function parseLabelWithIcons(input: string): IParsedLabelWithIcons {
62
63 _parseIconsRegex.lastIndex = 0;
86 return { text, iconOffsets };
87 }
89 >
90 > export function matchesFuzzyIconAware(query: string, target: IParsedLabelWithIcons, enableSeparateSubstringMatching = false): IMatch[] | null {
91 const { text, iconOffsets } = target;
92
src/vs/workbench/contrib/chat/common/languageModelsConfiguration.ts 47 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- languageModelsConfiguration.ts
2 > * Copyright (c) Microsoft 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 { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
9 > import { IRange } from '../../../../editor/common/core/range.js';
10 > import { IStringDictionary } from '../../../../base/common/collections.js';
11 >
12 > export const ILanguageModelsConfigurationService = createDecorator<ILanguageModelsConfigurationService>('ILanguageModelsConfigurationService');
13 >
14 > export interface ConfigureLanguageModelsOptions {
15 > group: ILanguageModelsProviderGroup;
16 > snippet?: string;
17 > snippetTarget?: 'group' | 'models';
18 > }
19 >
20 > export interface ILanguageModelsConfigurationService {
21 > readonly _serviceBrand: undefined;
22 >
23 > readonly configurationFile: URI;
24 >
25 > readonly onDidChangeLanguageModelGroups: Event<readonly ILanguageModelsProviderGroup[]>;
26 >
27 > /** Resolves after the first config-file load attempt (success or failure), so callers can distinguish empty from not-yet-loaded. Never rejects. */
28 > readonly whenReady: Promise<void>;
29 >
30 > getLanguageModelsProviderGroups(): readonly ILanguageModelsProviderGroup[];
31 >
32 > addLanguageModelsProviderGroup(languageModelsProviderGroup: ILanguageModelsProviderGroup): Promise<ILanguageModelsProviderGroup>;
33 >
34 > updateLanguageModelsProviderGroup(from: ILanguageModelsProviderGroup, to: ILanguageModelsProviderGroup): Promise<ILanguageModelsProviderGroup>;
35 >
36 > removeLanguageModelsProviderGroup(languageModelGroup: ILanguageModelsProviderGroup): Promise<void>;
37 >
38 > configureLanguageModels(options?: ConfigureLanguageModelsOptions): Promise<void>;
39 > }
40 >
41 > export interface ILanguageModelsProviderGroup extends IStringDictionary<unknown> {
42 > readonly name: string;
43 > readonly vendor: string;
44 > readonly range?: IRange;
45 > readonly modelsRange?: IRange;
46 > readonly settings?: IStringDictionary<IStringDictionary<unknown>>;
47 > }
src/vs/workbench/services/aiSettingsSearch/common/aiSettingsSearch.ts 47 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- aiSettingsSearch.ts
2 > * Copyright (c) Microsoft 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 { IDisposable } from '../../../../base/common/lifecycle.js';
9 > import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
10 >
11 > export const IAiSettingsSearchService = createDecorator<IAiSettingsSearchService>('IAiSettingsSearchService');
12 >
13 > export enum AiSettingsSearchResultKind {
14 > EMBEDDED = 1,
15 > LLM_RANKED = 2,
16 > CANCELED = 3,
17 > }
18 >
19 > export interface AiSettingsSearchResult {
20 > query: string;
21 > kind: AiSettingsSearchResultKind;
22 > settings: string[];
23 > }
24 >
25 > export interface AiSettingsSearchProviderOptions {
26 > limit: number;
27 > embeddingsOnly: boolean;
28 > }
29 >
30 > export interface IAiSettingsSearchService {
31 > readonly _serviceBrand: undefined;
32 > readonly onProviderRegistered: Event<void>;
33 >
34 > // Called from the Settings editor
35 > isEnabled(): boolean;
36 > startSearch(query: string, token: CancellationToken): void;
37 > getEmbeddingsResults(query: string, token: CancellationToken): Promise<string[] | null>;
38 > getLLMRankedResults(query: string, token: CancellationToken): Promise<string[] | null>;
39 >
40 > // Called from the main thread
41 > registerSettingsSearchProvider(provider: IAiSettingsSearchProvider): IDisposable;
42 > handleSearchResult(results: AiSettingsSearchResult): void;
43 > }
44 >
45 > export interface IAiSettingsSearchProvider {
46 > searchSettings(query: string, option: AiSettingsSearchProviderOptions, token: CancellationToken): void;
47 > }
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/platform/uriIdentity/common/uriIdentity.ts 46 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- uriIdentity.ts
2 > * Copyright (c) Microsoft 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 { createDecorator } from '../../instantiation/common/instantiation.js';
8 > import { IExtUri } from '../../../base/common/resources.js';
9 >
10 >
11 > export const IUriIdentityService = createDecorator<IUriIdentityService>('IUriIdentityService');
12 >
13 > export interface IUriIdentityService {
14 >
15 > readonly _serviceBrand: undefined;
16 >
17 > /**
18 > * Uri extensions that are aware of casing.
19 > */
20 > readonly extUri: IExtUri;
21 >
22 > /**
23 > * Returns a canonical uri for the given resource. Different uris can point to the same
24 > * resource. That's because of casing or missing normalization, e.g the following uris
25 > * are different but refer to the same document (because windows paths are not case-sensitive)
26 > *
27 > * ```txt
28 > * file:///c:/foo/bar.txt
29 > * file:///c:/FOO/BAR.txt
30 > * ```
31 > *
32 > * This function should be invoked when feeding uris into the system that represent the truth,
33 > * e.g document uris or marker-to-document associations etc. This function should NOT be called
34 > * to pretty print a label nor to sanitize a uri.
35 > *
36 > * Samples:
37 > *
38 > * | in | out | |
39 > * |---|---|---|
40 > * | `file:///foo/bar/../bar` | `file:///foo/bar` | n/a |
41 > * | `file:///foo/bar/../bar#frag` | `file:///foo/bar#frag` | keep fragment |
42 > * | `file:///foo/BAR` | `file:///foo/bar` | assume ignore case |
43 > * | `file:///foo/bar/../BAR?q=2` | `file:///foo/BAR?q=2` | query makes it a different document |
44 > */
45 > asCanonicalUri(uri: URI): URI;
46 > }
src/vs/workbench/api/common/extHostProgress.ts 46 covered LOC · 9 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostProgress.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { ProgressOptions } from 'vscode';
7 > import { MainThreadProgressShape, ExtHostProgressShape, MainContext } from './extHost.protocol.js';
8 > import { ProgressLocation } from './extHostTypeConverters.js';
9 > import { Progress, IProgressStep } from '../../../platform/progress/common/progress.js';
10 > import { CancellationTokenSource, CancellationToken } from '../../../base/common/cancellation.js';
11 > import { throttle } from '../../../base/common/decorators.js';
12 > import { IExtensionDescription } from '../../../platform/extensions/common/extensions.js';
13 > import { onUnexpectedExternalError } from '../../../base/common/errors.js';
14 > import { INotificationSource } from '../../../platform/notification/common/notification.js';
15 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
16 > import { IExtHostRpcService } from './extHostRpcService.js';
17 >
18 > export interface IExtHostProgress extends ExtHostProgress { }
19 > export const IExtHostProgress = createDecorator<IExtHostProgress>('IExtHostProgress');
20 >
21 > export class ExtHostProgress implements ExtHostProgressShape {
22 >
23 > declare readonly _serviceBrand: undefined;
24 >
25 > private _proxy: MainThreadProgressShape;
26 > private _handles: number = 0;
27 > private _mapHandleToCancellationSource: Map<number, CancellationTokenSource> = new Map();
28 >
29 > constructor(@IExtHostRpcService extHostRpc: IExtHostRpcService) {
30 this._proxy = extHostRpc.getProxy(MainContext.MainThreadProgress);
31 }
33 > async withProgress<R>(extension: IExtensionDescription, options: ProgressOptions, task: (progress: Progress<IProgressStep>, token: CancellationToken) => Thenable<R>): Promise<R> {
34 const handle = this._handles++;
35 const { title, location, cancellable } = options;
39 return this._withProgress(handle, task, !!cancellable);
40 }
42 > async withProgressFromSource<R>(source: string | INotificationSource, options: ProgressOptions, task: (progress: Progress<IProgressStep>, token: CancellationToken) => Thenable<R>): Promise<R> {
43 const handle = this._handles++;
44 const { title, location, cancellable } = options;
47 return this._withProgress(handle, task, !!cancellable);
48 }
50 > private _withProgress<R>(handle: number, task: (progress: Progress<IProgressStep>, token: CancellationToken) => Thenable<R>, cancellable: boolean): Thenable<R> {
51 let source: CancellationTokenSource | undefined;
52 if (cancellable) {
73 return p;
74 }
76 > public $acceptProgressCanceled(handle: number): void {
77 const source = this._mapHandleToCancellationSource.get(handle);
78 if (source) {
81 }
82 }
84 >
85 function mergeProgress(result: IProgressStep, currentValue: IProgressStep): IProgressStep {
86 result.message = currentValue.message;
95 return result;
96 }
98 > class ProgressCallback extends Progress<IProgressStep> {
99 > constructor(private _proxy: MainThreadProgressShape, private _handle: number) {
100 super(p => this.throttledReport(p));
101 }
103 > @throttle(100, (result: IProgressStep, currentValue: IProgressStep) => mergeProgress(result, currentValue), () => Object.create(null))
104 > throttledReport(p: IProgressStep): void {
105 this._proxy.$progressReport(this._handle, p);
106 }
src/vs/workbench/api/common/extHostTypes/codeActionKind.ts 46 covered LOC · 3 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- codeActionKind.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { es5ClassCompat } from './es5ClassCompat.js';
7 >
8 > @es5ClassCompat
9 > export class CodeActionKind {
10 > private static readonly sep = '.';
11 >
12 > public static Empty: CodeActionKind;
13 > public static QuickFix: CodeActionKind;
14 > public static Refactor: CodeActionKind;
15 > public static RefactorExtract: CodeActionKind;
16 > public static RefactorInline: CodeActionKind;
17 > public static RefactorMove: CodeActionKind;
18 > public static RefactorRewrite: CodeActionKind;
19 > public static Source: CodeActionKind;
20 > public static SourceOrganizeImports: CodeActionKind;
21 > public static SourceFixAll: CodeActionKind;
22 > public static Notebook: CodeActionKind;
23 >
24 > constructor(
25 > public readonly value: string
26 > ) { }
27 >
28 > public append(parts: string): CodeActionKind {
29 > return new CodeActionKind(this.value ? this.value + CodeActionKind.sep + parts : parts);
30 > }
31 >
32 > public intersects(other: CodeActionKind): boolean {
33 return this.contains(other) || other.contains(this);
34 }
36 > public contains(other: CodeActionKind): boolean {
37 return this.value === other.value || other.value.startsWith(this.value + CodeActionKind.sep);
38 }
40 > CodeActionKind.Empty = new CodeActionKind('');
41 > CodeActionKind.QuickFix = CodeActionKind.Empty.append('quickfix');
42 > CodeActionKind.Refactor = CodeActionKind.Empty.append('refactor');
43 > CodeActionKind.RefactorExtract = CodeActionKind.Refactor.append('extract');
44 > CodeActionKind.RefactorInline = CodeActionKind.Refactor.append('inline');
45 > CodeActionKind.RefactorMove = CodeActionKind.Refactor.append('move');
46 > CodeActionKind.RefactorRewrite = CodeActionKind.Refactor.append('rewrite');
47 > CodeActionKind.Source = CodeActionKind.Empty.append('source');
48 > CodeActionKind.SourceOrganizeImports = CodeActionKind.Source.append('organizeImports');
49 > CodeActionKind.SourceFixAll = CodeActionKind.Source.append('fixAll');
50 > CodeActionKind.Notebook = CodeActionKind.Empty.append('notebook');
src/vs/workbench/api/common/extHostFileSystemConsumer.ts 45 covered LOC · 6 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostFileSystemConsumer.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { MainContext, MainThreadFileSystemShape } from './extHost.protocol.js';
7 > import type * as vscode from 'vscode';
8 > import * as files from '../../../platform/files/common/files.js';
9 > import { FileSystemError } from './extHostTypes.js';
10 > import { VSBuffer } from '../../../base/common/buffer.js';
11 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
12 > import { IExtHostRpcService } from './extHostRpcService.js';
13 > import { IExtHostFileSystemInfo } from './extHostFileSystemInfo.js';
14 > import { IDisposable, toDisposable } from '../../../base/common/lifecycle.js';
15 > import { ResourceQueue } from '../../../base/common/async.js';
16 > import { IExtUri, extUri, extUriIgnorePathCase } from '../../../base/common/resources.js';
17 > import { Schemas } from '../../../base/common/network.js';
18 > import { IMarkdownString } from '../../../base/common/htmlContent.js';
19 >
20 > export class ExtHostConsumerFileSystem {
21 >
22 > readonly _serviceBrand: undefined;
23 >
24 > readonly value: vscode.FileSystem;
25 >
26 > private readonly _proxy: MainThreadFileSystemShape;
27 > private readonly _fileSystemProvider = new Map<string, { impl: vscode.FileSystemProvider; extUri: IExtUri; isReadonly: boolean }>();
28 >
29 > private readonly _writeQueue = new ResourceQueue();
30 >
31 > constructor(
32 @IExtHostRpcService extHostRpc: IExtHostRpcService,
33 @IExtHostFileSystemInfo fileSystemInfo: IExtHostFileSystemInfo,
158 });
159 }
161 > private async mkdirp(provider: vscode.FileSystemProvider, providerExtUri: IExtUri, directory: vscode.Uri): Promise<void> {
162 const directoriesToCreate: string[] = [];
163
201 }
202 }
204 > private static _handleError(err: any): never {
205 // desired error type
206 if (err instanceof FileSystemError) {
244 }
245 }
247 > // ---
248 >
249 > addFileSystemProvider(scheme: string, provider: vscode.FileSystemProvider, options?: { isCaseSensitive?: boolean; isReadonly?: boolean | IMarkdownString }): IDisposable {
250 this._fileSystemProvider.set(scheme, { impl: provider, extUri: options?.isCaseSensitive ? extUri : extUriIgnorePathCase, isReadonly: !!options?.isReadonly });
251 return toDisposable(() => this._fileSystemProvider.delete(scheme));
252 }
254 > getFileSystemProviderExtUri(scheme: string) {
255 return this._fileSystemProvider.get(scheme)?.extUri ?? extUri;
256 }
258 >
259 > export interface IExtHostConsumerFileSystem extends ExtHostConsumerFileSystem { }
260 > export const IExtHostConsumerFileSystem = createDecorator<IExtHostConsumerFileSystem>('IExtHostConsumerFileSystem');
src/vs/workbench/api/common/extHostStoragePaths.ts 45 covered LOC · 7 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostStoragePaths.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IExtensionDescription } from '../../../platform/extensions/common/extensions.js';
7 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
8 > import { IExtHostInitDataService } from './extHostInitDataService.js';
9 > import { ILogService } from '../../../platform/log/common/log.js';
10 > import { IEnvironment, IStaticWorkspaceData } from '../../services/extensions/common/extensionHostProtocol.js';
11 > import { IExtHostConsumerFileSystem } from './extHostFileSystemConsumer.js';
12 > import { URI } from '../../../base/common/uri.js';
13 >
14 > export const IExtensionStoragePaths = createDecorator<IExtensionStoragePaths>('IExtensionStoragePaths');
15 >
16 > export interface IExtensionStoragePaths {
17 > readonly _serviceBrand: undefined;
18 > whenReady: Promise<any>;
19 > workspaceValue(extension: IExtensionDescription): URI | undefined;
20 > globalValue(extension: IExtensionDescription): URI;
21 > onWillDeactivateAll(): void;
22 > }
23 >
24 > export class ExtensionStoragePaths implements IExtensionStoragePaths {
25 >
26 > readonly _serviceBrand: undefined;
27 >
28 > private readonly _workspace?: IStaticWorkspaceData;
29 > protected readonly _environment: IEnvironment;
30 >
31 > readonly whenReady: Promise<URI | undefined>;
32 > private _value?: URI;
33 >
34 > constructor(
35 @IExtHostInitDataService initData: IExtHostInitDataService,
36 @ILogService protected readonly _logService: ILogService,
41 this.whenReady = this._getOrCreateWorkspaceStoragePath().then(value => this._value = value);
42 }
44 > protected async _getWorkspaceStorageURI(storageName: string): Promise<URI> {
45 return URI.joinPath(this._environment.workspaceStorageHome, storageName);
46 }
48 > private async _getOrCreateWorkspaceStoragePath(): Promise<URI | undefined> {
49 if (!this._workspace) {
50 return Promise.resolve(undefined);
79 }
80 }
82 > workspaceValue(extension: IExtensionDescription): URI | undefined {
83 if (this._value) {
84 return URI.joinPath(this._value, extension.identifier.value);
src/vs/editor/common/core/wordCharacterClassifier.ts 44 covered LOC · 7 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- wordCharacterClassifier.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { CharCode } from '../../../base/common/charCode.js';
7 > import { safeIntl } from '../../../base/common/date.js';
8 > import { Lazy } from '../../../base/common/lazy.js';
9 > import { LRUCache } from '../../../base/common/map.js';
10 > import { CharacterClassifier } from './characterClassifier.js';
11 >
12 > export const enum WordCharacterClass {
13 > Regular = 0,
14 > Whitespace = 1,
15 > WordSeparator = 2
16 > }
17 >
18 > export class WordCharacterClassifier extends CharacterClassifier<WordCharacterClass> {
19 >
20 > public readonly intlSegmenterLocales: Intl.UnicodeBCP47LocaleIdentifier[];
21 > private readonly _segmenter: Lazy<Intl.Segmenter> | null = null;
22 > private _cachedLine: string | null = null;
23 > private _cachedSegments: IntlWordSegmentData[] = [];
24 >
25 > constructor(wordSeparators: string, intlSegmenterLocales: Intl.UnicodeBCP47LocaleIdentifier[]) {
26 super(WordCharacterClass.Regular);
27 this.intlSegmenterLocales = intlSegmenterLocales;
39 this.set(CharCode.Tab, WordCharacterClass.Whitespace);
40 }
42 > public findPrevIntlWordBeforeOrAtOffset(line: string, offset: number): IntlWordSegmentData | null {
43 let candidate: IntlWordSegmentData | null = null;
44 for (const segment of this._getIntlSegmenterWordsOnLine(line)) {
50 return candidate;
51 }
53 > public findNextIntlWordAtOrAfterOffset(lineContent: string, offset: number): IntlWordSegmentData | null {
54 for (const segment of this._getIntlSegmenterWordsOnLine(lineContent)) {
55 if (segment.index < offset) {
60 return null;
61 }
63 > private _getIntlSegmenterWordsOnLine(line: string): IntlWordSegmentData[] {
64 if (!this._segmenter) {
65 return [];
77 return this._cachedSegments;
78 }
80 > private _filterWordSegments(segments: Intl.Segments): IntlWordSegmentData[] {
81 const result: IntlWordSegmentData[] = [];
82 for (const segment of segments) {
87 return result;
88 }
90 > private _isWordLike(segment: Intl.SegmentData): segment is IntlWordSegmentData {
91 if (segment.isWordLike) {
92 return true;
94 return false;
95 }
97 >
98 > export interface IntlWordSegmentData extends Intl.SegmentData {
99 > isWordLike: true;
100 > }
101 >
102 > const wordClassifierCache = new LRUCache<string, WordCharacterClassifier>(10);
103 >
104 > export function getMapForWordSeparators(wordSeparators: string, intlSegmenterLocales: Intl.UnicodeBCP47LocaleIdentifier[]): WordCharacterClassifier {
105 const key = `${wordSeparators}/${intlSegmenterLocales.join(',')}`;
106 let result = wordClassifierCache.get(key)!;
src/vs/base/common/uint.ts 43 covered LOC · 2 ranges

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- mcpAppDefaults.ts
2 > * Copyright (c) Microsoft 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 { AhpMcpUiHostCapabilities, McpServerCustomizationApps } from './channels-session/state.js';
7 >
8 > /**
9 > * MCP App capabilities the agent host proxies for every MCP server it
10 > * advertises over the `mcp://` side-channel.
11 > *
12 > * - `serverTools.listChanged` is `true`: we forward
13 > * `notifications/tools/list_changed` whenever the SDK signals that the
14 > * tool inventory has refreshed (see `CopilotAgentSession`).
15 > * - `serverResources` is advertised as an empty object: we serve the
16 > * `resources/*` methods over the channel but do not promise
17 > * `notifications/resources/list_changed` forwarding (no `listChanged`).
18 > * - `sampling` is advertised as an empty object: we serve
19 > * `sampling/createMessage` requests from the App over the `mcp://`
20 > * channel (the agent host handler forwards them to
21 > * `session.rpc.mcp.executeSampling`). The SEP-1577 `tools`
22 > * sub-flag is NOT set — we don't pass through tool content blocks.
23 > *
24 > * Per the AHP spec, `mcpApp` is a static capability declaration —
25 > * "SHOULD be present whenever the server can host Apps" — so this
26 > * constant is set on every MCP customization at construction time,
27 > * regardless of the server's current lifecycle state.
28 > */
29 > export const DEFAULT_MCP_APP_CAPABILITIES: AhpMcpUiHostCapabilities = {
30 > serverTools: { listChanged: true },
31 > serverResources: {},
32 > sampling: {},
33 > };
34 >
35 > /**
36 > * The full `mcpApp` shape applied to a {@link McpServerCustomization}.
37 > * Wraps {@link DEFAULT_MCP_APP_CAPABILITIES} so callers can drop it in
38 > * directly without re-allocating the same wrapper object at every call
39 > * site.
40 > */
41 > export const DEFAULT_MCP_APP: McpServerCustomizationApps = {
42 > capabilities: DEFAULT_MCP_APP_CAPABILITIES,
43 > };
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/workbench/api/common/extHostStorage.ts 42 covered LOC · 7 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostStorage.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { MainContext, MainThreadStorageShape, ExtHostStorageShape } from './extHost.protocol.js';
7 > import { Emitter } from '../../../base/common/event.js';
8 > import { IExtHostRpcService } from './extHostRpcService.js';
9 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
10 > import { IExtensionIdWithVersion } from '../../../platform/extensionManagement/common/extensionStorage.js';
11 > import { ILogService } from '../../../platform/log/common/log.js';
12 >
13 > export interface IStorageChangeEvent {
14 > shared: boolean;
15 > key: string;
16 > value: object;
17 > }
18 >
19 > export class ExtHostStorage implements ExtHostStorageShape {
20 >
21 > readonly _serviceBrand: undefined;
22 >
23 > private _proxy: MainThreadStorageShape;
24 >
25 > private readonly _onDidChangeStorage = new Emitter<IStorageChangeEvent>();
26 > readonly onDidChangeStorage = this._onDidChangeStorage.event;
27 >
28 > constructor(
29 mainContext: IExtHostRpcService,
30 private readonly _logService: ILogService
32 this._proxy = mainContext.getProxy(MainContext.MainThreadStorage);
33 }
35 > registerExtensionStorageKeysToSync(extension: IExtensionIdWithVersion, keys: string[]): void {
36 this._proxy.$registerExtensionStorageKeysToSync(extension, keys);
37 }
39 > async initializeExtensionStorage(shared: boolean, key: string, defaultValue?: object): Promise<object | undefined> {
40 const value = await this._proxy.$initializeExtensionStorage(shared, key);
41
47 return parsedValue || defaultValue;
48 }
50 > setValue(shared: boolean, key: string, value: object): Promise<void> {
51 return this._proxy.$setValue(shared, key, value);
52 }
54 > $acceptValue(shared: boolean, key: string, value: string): void {
55 const parsedValue = this.safeParseValue(shared, key, value);
56 if (parsedValue) {
58 }
59 }
61 > private safeParseValue(shared: boolean, key: string, value: string): object | undefined {
62 try {
63 return JSON.parse(value);
70 return undefined;
71 }
73 >
74 > export interface IExtHostStorage extends ExtHostStorage { }
75 > export const IExtHostStorage = createDecorator<IExtHostStorage>('IExtHostStorage');
src/vs/base/common/decorators.ts 41 covered LOC · 10 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- decorators.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > function createDecorator(mapFn: (fn: Function, key: string) => Function): MethodDecorator { decorators.ts
7 > return (_target: Object, key: string | symbol, descriptor: TypedPropertyDescriptor<any>) => {
8 > let fnKey: 'value' | 'get' | null = null;
9 > let fn: Function | null = null;
10 >
11 > if (typeof descriptor.value === 'function') {
12 > fnKey = 'value';
13 > fn = descriptor.value;
14 > } else if (typeof descriptor.get === 'function') {
15 fnKey = 'get';
16 fn = descriptor.get;
17 }
19 > if (!fn || typeof key === 'symbol') {
20 throw new Error('not supported');
21 }
23 > descriptor[fnKey!] = mapFn(fn, key);
24 > };
25 > }
27 > export function memoize(_target: Object, key: string, descriptor: PropertyDescriptor) {
28 let fnKey: 'value' | 'get' | null = null;
29 let fn: Function | null = null;
58 };
59 }
61 > export interface IDebounceReducer<T> {
62 > (previousValue: T, ...args: any[]): T;
63 > }
64 >
65 > export function debounce<T>(delay: number, reducer?: IDebounceReducer<T>, initialValueProvider?: () => T) {
66 return createDecorator((fn, key) => {
67 const timerKey = `$debounce$${key}`;
87 });
88 }
90 > export function throttle<T>(delay: number, reducer?: IDebounceReducer<T>, initialValueProvider?: () => T) {
91 > return createDecorator((fn, key) => { decorators.ts
92 > const timerKey = `$throttle$timer$${key}`;
93 > const resultKey = `$throttle$result$${key}`;
94 > const lastRunKey = `$throttle$lastRun$${key}`;
95 > const pendingKey = `$throttle$pending$${key}`;
96 >
97 > return function (this: any, ...args: any[]) {
98 if (!this[resultKey]) {
99 this[resultKey] = initialValueProvider ? initialValueProvider() : undefined;
126 }
127 };
128 > }); decorators.ts
129 > }
131 > export { cancelPreviousCalls } from './decorators/cancelPreviousCalls.js';
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/workbench/api/common/extHostLocalizationService.ts 39 covered LOC · 7 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostLocalizationService.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { LANGUAGE_DEFAULT } from '../../../base/common/platform.js';
7 > import { format2 } from '../../../base/common/strings.js';
8 > import { URI } from '../../../base/common/uri.js';
9 > import { IExtensionDescription } from '../../../platform/extensions/common/extensions.js';
10 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
11 > import { ILogService } from '../../../platform/log/common/log.js';
12 > import { ExtHostLocalizationShape, IStringDetails, MainContext, MainThreadLocalizationShape } from './extHost.protocol.js';
13 > import { IExtHostInitDataService } from './extHostInitDataService.js';
14 > import { IExtHostRpcService } from './extHostRpcService.js';
15 >
16 > export class ExtHostLocalizationService implements ExtHostLocalizationShape {
17 > readonly _serviceBrand: undefined;
18 >
19 > private readonly _proxy: MainThreadLocalizationShape;
20 > private readonly currentLanguage: string;
21 > private readonly isDefaultLanguage: boolean;
22 >
23 > private readonly bundleCache: Map<string, { contents: { [key: string]: string }; uri: URI }> = new Map();
24 >
25 > constructor(
26 @IExtHostInitDataService initData: IExtHostInitDataService,
27 @IExtHostRpcService rpc: IExtHostRpcService,
32 this.isDefaultLanguage = this.currentLanguage === LANGUAGE_DEFAULT;
33 }
35 > getMessage(extensionId: string, details: IStringDetails): string {
36 const { message, args, comment } = details;
37 if (this.isDefaultLanguage) {
49 return format2(str ?? message, (args ?? {}));
50 }
52 > getBundle(extensionId: string): { [key: string]: string } | undefined {
53 return this.bundleCache.get(extensionId)?.contents;
54 }
56 > getBundleUri(extensionId: string): URI | undefined {
57 return this.bundleCache.get(extensionId)?.uri;
58 }
60 > async initializeLocalizedMessages(extension: IExtensionDescription): Promise<void> {
61 if (this.isDefaultLanguage
62 || (!extension.l10n && !extension.isBuiltin)
93 }
94 }
96 > private async getBundleLocation(extension: IExtensionDescription): Promise<URI | undefined> {
97 if (extension.isBuiltin) {
98 const uri = await this._proxy.$fetchBuiltInBundleUri(extension.identifier.value, this.currentLanguage);
104 : undefined;
105 }
107 >
108 > export const IExtHostLocalizationService = createDecorator<IExtHostLocalizationService>('IExtHostLocalizationService');
109 > export interface IExtHostLocalizationService extends ExtHostLocalizationService { }
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/platform/extensionManagement/common/implicitActivationEvents.ts 38 covered LOC · 6 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- implicitActivationEvents.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IStringDictionary } from '../../../base/common/collections.js';
7 > import { onUnexpectedError } from '../../../base/common/errors.js';
8 > import { ExtensionIdentifier, IExtensionDescription } from '../../extensions/common/extensions.js';
9 >
10 > export interface IActivationEventsGenerator<T> {
11 > (contributions: readonly T[]): Iterable<string>;
12 > }
13 >
14 > export class ImplicitActivationEventsImpl {
15 >
16 > private readonly _generators = new Map<string, IActivationEventsGenerator<unknown>>();
17 > private readonly _cache = new WeakMap<IExtensionDescription, string[]>();
18 >
19 > public register<T>(extensionPointName: string, generator: IActivationEventsGenerator<T>): void {
20 > this._generators.set(extensionPointName, generator as IActivationEventsGenerator<unknown>); implicitActivationEvents.ts
21 > }
23 > /**
24 > * This can run correctly only on the renderer process because that is the only place
25 > * where all extension points and all implicit activation events generators are known.
26 > */
27 > public readActivationEvents(extensionDescription: IExtensionDescription): string[] {
28 if (!this._cache.has(extensionDescription)) {
29 this._cache.set(extensionDescription, this._readActivationEvents(extensionDescription));
31 return this._cache.get(extensionDescription)!;
32 }
34 > /**
35 > * This can run correctly only on the renderer process because that is the only place
36 > * where all extension points and all implicit activation events generators are known.
37 > */
38 > public createActivationEventsMap(extensionDescriptions: IExtensionDescription[]): { [extensionId: string]: string[] } {
39 const result: { [extensionId: string]: string[] } = Object.create(null);
40 for (const extensionDescription of extensionDescriptions) {
46 return result;
47 }
49 > private _readActivationEvents(desc: IExtensionDescription): string[] {
50 if (typeof desc.main === 'undefined' && typeof desc.browser === 'undefined') {
51 return [];
83 return activationEvents;
84 }
86 >
87 > export const ImplicitActivationEvents: ImplicitActivationEventsImpl = new ImplicitActivationEventsImpl();
src/vs/workbench/api/common/extHostTypes/snippetString.ts 38 covered LOC · 8 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- snippetString.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { es5ClassCompat } from './es5ClassCompat.js';
7 >
8 > @es5ClassCompat
9 > export class SnippetString {
10 >
11 > static isSnippetString(thing: unknown): thing is SnippetString {
12 > if (thing instanceof SnippetString) {
13 > return true;
14 > }
15 > if (!thing || typeof thing !== 'object') {
16 > return false;
17 > }
18 > return typeof (<SnippetString>thing).value === 'string';
19 > }
20 >
21 > private static _escape(value: string): string {
22 return value.replace(/\$|}|\\/g, '\\$&');
23 }
25 > private _tabstop: number = 1;
26 >
27 > value: string;
28 >
29 > constructor(value?: string) {
30 this.value = value || '';
31 }
33 > appendText(string: string): SnippetString {
34 this.value += SnippetString._escape(string);
35 return this;
36 }
38 > appendTabstop(number: number = this._tabstop++): SnippetString {
39 this.value += '$';
40 this.value += number;
41 return this;
42 }
44 > appendPlaceholder(value: string | ((snippet: SnippetString) => unknown), number: number = this._tabstop++): SnippetString {
45
46 if (typeof value === 'function') {
62 return this;
63 }
65 > appendChoice(values: string[], number: number = this._tabstop++): SnippetString {
66 const value = values.map(s => s.replaceAll(/[|\\,]/g, '\\$&')).join(',');
67
74 return this;
75 }
77 > appendVariable(name: string, defaultValue?: string | ((snippet: SnippetString) => unknown)): SnippetString {
78
79 if (typeof defaultValue === 'function') {
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/workbench/services/extensions/common/workspaceContains.ts 37 covered LOC · 4 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- workspaceContains.ts
2 > * Copyright (c) Microsoft 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 resources from '../../../../base/common/resources.js';
7 > import { URI, UriComponents } from '../../../../base/common/uri.js';
8 > import { CancellationTokenSource, CancellationToken } from '../../../../base/common/cancellation.js';
9 > import * as errors from '../../../../base/common/errors.js';
10 > import { ExtensionIdentifier, IExtensionDescription } from '../../../../platform/extensions/common/extensions.js';
11 > import { IInstantiationService, ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js';
12 > import { QueryBuilder } from '../../search/common/queryBuilder.js';
13 > import { ISearchService } from '../../search/common/search.js';
14 > import { toWorkspaceFolder } from '../../../../platform/workspace/common/workspace.js';
15 > import { ILogService } from '../../../../platform/log/common/log.js';
16 > import { promiseWithResolvers } from '../../../../base/common/async.js';
17 >
18 > const WORKSPACE_CONTAINS_TIMEOUT = 7000;
19 >
20 > export interface IExtensionActivationHost {
21 > readonly logService: ILogService;
22 > readonly folders: readonly UriComponents[];
23 > readonly forceUsingSearch: boolean;
24 >
25 > exists(uri: URI): Promise<boolean>;
26 > checkExists(folders: readonly UriComponents[], includes: string[], token: CancellationToken): Promise<boolean>;
27 > }
28 >
29 > export interface IExtensionActivationResult {
30 > activationEvent: string;
31 > }
32 >
33 > export function checkActivateWorkspaceContainsExtension(host: IExtensionActivationHost, desc: IExtensionDescription): Promise<IExtensionActivationResult | undefined> {
34 const activationEvents = desc.activationEvents;
35 if (!activationEvents) {
68 return promise;
69 }
71 async function _activateIfFileName(host: IExtensionActivationHost, fileName: string, activate: (activationEvent: string) => void): Promise<void> {
72 // find exact path
79 }
80 }
82 async function _activateIfGlobPatterns(host: IExtensionActivationHost, extensionId: ExtensionIdentifier, globPatterns: string[], activate: (activationEvent: string) => void): Promise<void> {
83 if (globPatterns.length === 0) {
110 }
111 }
113 > export function checkGlobFileExists(
114 accessor: ServicesAccessor,
115 folders: readonly UriComponents[],
src/vs/workbench/api/common/extHostTypes/selection.ts 36 covered LOC · 8 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 type * as vscode from 'vscode';
7 > import { es5ClassCompat } from './es5ClassCompat.js';
8 > import { Position } from './position.js';
9 > import { getDebugDescriptionOfRange, Range } from './range.js';
10 >
11 > @es5ClassCompat
12 > export class Selection extends Range {
13 >
14 > static isSelection(thing: unknown): thing is Selection {
15 if (thing instanceof Selection) {
16 return true;
24 && typeof (<Selection>thing).isReversed === 'boolean';
25 }
27 > private _anchor: Position;
28 >
29 > public get anchor(): Position {
30 return this._anchor;
31 }
33 > private _active: Position;
34 >
35 > public get active(): Position {
36 return this._active;
37 }
39 > constructor(anchor: Position, active: Position);
40 > constructor(anchorLine: number, anchorColumn: number, activeLine: number, activeColumn: number);
41 > constructor(anchorLineOrAnchor: number | Position, anchorColumnOrActive: number | Position, activeLine?: number, activeColumn?: number) {
42 let anchor: Position | undefined;
43 let active: Position | undefined;
60 this._active = active;
61 }
63 > get isReversed(): boolean {
64 return this._anchor === this._end;
65 }
67 > override toJSON() {
68 return {
69 start: this.start,
73 };
74 }
76 >
77 > [Symbol.for('debug.description')]() {
78 return getDebugDescriptionOfSelection(this);
79 }
80 > } selection.ts
81 >
82 > export function getDebugDescriptionOfSelection(selection: vscode.Selection): string {
83 let rangeStr = getDebugDescriptionOfRange(selection);
84 if (!selection.isEmpty) {
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/workbench/api/common/extHostUrls.ts 35 covered LOC · 5 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostUrls.ts
2 > * Copyright (c) Microsoft 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 * as vscode from 'vscode';
7 > import { MainContext, ExtHostUrlsShape, MainThreadUrlsShape } from './extHost.protocol.js';
8 > import { URI, UriComponents } from '../../../base/common/uri.js';
9 > import { toDisposable } from '../../../base/common/lifecycle.js';
10 > import { onUnexpectedError } from '../../../base/common/errors.js';
11 > import { ExtensionIdentifierSet, IExtensionDescription } from '../../../platform/extensions/common/extensions.js';
12 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
13 > import { IExtHostRpcService } from './extHostRpcService.js';
14 >
15 > export class ExtHostUrls implements ExtHostUrlsShape {
16 >
17 > declare _serviceBrand: undefined;
18 >
19 > private static HandlePool = 0;
20 > private readonly _proxy: MainThreadUrlsShape;
21 >
22 > private handles = new ExtensionIdentifierSet();
23 > private handlers = new Map<number, vscode.UriHandler>();
24 >
25 > constructor(
26 @IExtHostRpcService extHostRpc: IExtHostRpcService
27 ) {
28 this._proxy = extHostRpc.getProxy(MainContext.MainThreadUrls);
29 }
31 > registerUriHandler(extension: IExtensionDescription, handler: vscode.UriHandler): vscode.Disposable {
32 const extensionId = extension.identifier;
33 if (this.handles.has(extensionId)) {
46 });
47 }
49 > $handleExternalUri(handle: number, uri: UriComponents): Promise<void> {
50 const handler = this.handlers.get(handle);
51
61 return Promise.resolve(undefined);
62 }
64 > async createAppUri(uri: URI): Promise<vscode.Uri> {
65 return URI.revive(await this._proxy.$createAppUri(uri));
66 }
68 >
69 > export interface IExtHostUrlsService extends ExtHostUrls { }
70 > export const IExtHostUrlsService = createDecorator<IExtHostUrlsService>('IExtHostUrlsService');
src/vs/workbench/api/common/extHostFileSystemInfo.ts 34 covered LOC · 5 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostFileSystemInfo.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { Schemas } from '../../../base/common/network.js';
7 > import { ExtUri, IExtUri } from '../../../base/common/resources.js';
8 > import { UriComponents } from '../../../base/common/uri.js';
9 > import { FileSystemProviderCapabilities } from '../../../platform/files/common/files.js';
10 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
11 > import { ExtHostFileSystemInfoShape } from './extHost.protocol.js';
12 >
13 > export class ExtHostFileSystemInfo implements ExtHostFileSystemInfoShape {
14 >
15 > declare readonly _serviceBrand: undefined;
16 >
17 > private readonly _systemSchemes = new Set(Object.keys(Schemas));
18 > private readonly _providerInfo = new Map<string, number>();
19 >
20 > readonly extUri: IExtUri;
21 >
22 > constructor() {
23 this.extUri = new ExtUri(uri => {
24 const capabilities = this._providerInfo.get(uri.scheme);
34 });
35 }
37 > $acceptProviderInfos(uri: UriComponents, capabilities: number | null): void {
38 if (capabilities === null) {
39 this._providerInfo.delete(uri.scheme);
42 }
43 }
45 > isFreeScheme(scheme: string): boolean {
46 return !this._providerInfo.has(scheme) && !this._systemSchemes.has(scheme);
47 }
49 > getCapabilities(scheme: string): number | undefined {
50 return this._providerInfo.get(scheme);
51 }
53 >
54 > export interface IExtHostFileSystemInfo extends ExtHostFileSystemInfo {
55 > readonly extUri: IExtUri;
56 > }
57 > export const IExtHostFileSystemInfo = createDecorator<IExtHostFileSystemInfo>('IExtHostFileSystemInfo');
src/vs/base/common/marshallingIds.ts 33 covered LOC · 1 range

Open complete file

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

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostSecrets.ts
2 > * Copyright (c) Microsoft 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 * as vscode from 'vscode';
7 >
8 > import { ExtHostSecretState } from './extHostSecretState.js';
9 > import { ExtensionIdentifier, IExtensionDescription } from '../../../platform/extensions/common/extensions.js';
10 > import { Event } from '../../../base/common/event.js';
11 > import { DisposableStore } from '../../../base/common/lifecycle.js';
12 >
13 > export class ExtensionSecrets implements vscode.SecretStorage {
14 >
15 > protected readonly _id: string;
16 > readonly #secretState: ExtHostSecretState;
17 >
18 > readonly onDidChange: Event<vscode.SecretStorageChangeEvent>;
19 > readonly disposables = new DisposableStore();
20 >
21 > constructor(extensionDescription: IExtensionDescription, secretState: ExtHostSecretState) {
22 this._id = ExtensionIdentifier.toKey(extensionDescription.identifier);
23 this.#secretState = secretState;
29 );
30 }
32 > dispose() {
33 this.disposables.dispose();
34 }
36 > get(key: string): Promise<string | undefined> {
37 return this.#secretState.get(this._id, key);
38 }
40 > store(key: string, value: string): Promise<void> {
41 return this.#secretState.store(this._id, key, value);
42 }
44 > delete(key: string): Promise<void> {
45 return this.#secretState.delete(this._id, key);
46 }
48 > keys(): Promise<string[]> {
49 return this.#secretState.keys(this._id) || [];
50 }
src/vs/workbench/api/common/extHostSecretState.ts 30 covered LOC · 7 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostSecretState.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { ExtHostSecretStateShape, MainContext, MainThreadSecretStateShape } from './extHost.protocol.js';
7 > import { Emitter } from '../../../base/common/event.js';
8 > import { IExtHostRpcService } from './extHostRpcService.js';
9 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
10 >
11 > export class ExtHostSecretState implements ExtHostSecretStateShape {
12 > private _proxy: MainThreadSecretStateShape;
13 > private _onDidChangePassword = new Emitter<{ extensionId: string; key: string }>();
14 > readonly onDidChangePassword = this._onDidChangePassword.event;
15 >
16 > constructor(mainContext: IExtHostRpcService) {
17 this._proxy = mainContext.getProxy(MainContext.MainThreadSecretState);
18 }
20 > async $onDidChangePassword(e: { extensionId: string; key: string }): Promise<void> {
21 this._onDidChangePassword.fire(e);
22 }
24 > get(extensionId: string, key: string): Promise<string | undefined> {
25 return this._proxy.$getPassword(extensionId, key);
26 }
28 > store(extensionId: string, key: string, value: string): Promise<void> {
29 return this._proxy.$setPassword(extensionId, key, value);
30 }
32 > delete(extensionId: string, key: string): Promise<void> {
33 return this._proxy.$deletePassword(extensionId, key);
34 }
36 > keys(extensionId: string): Promise<string[]> {
37 return this._proxy.$getKeys(extensionId);
38 }
40 >
41 > export interface IExtHostSecretState extends ExtHostSecretState { }
42 > export const IExtHostSecretState = createDecorator<IExtHostSecretState>('IExtHostSecretState');
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/base/common/marshalling.ts 28 covered LOC · 4 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- marshalling.ts
2 > * Copyright (c) Microsoft 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 './buffer.js';
7 > import { URI, UriComponents } from './uri.js';
8 > import { MarshalledId } from './marshallingIds.js';
9 >
10 > export function stringify(obj: unknown): string {
11 return JSON.stringify(obj, replacer);
12 }
14 > export function parse(text: string): any {
15 let data = JSON.parse(text);
16 data = revive(data);
17 return data;
18 }
20 > export interface MarshalledObject {
21 > $mid: MarshalledId;
22 > }
23 >
24 function replacer(key: string, value: any): any {
25 // URI is done via toJSON-member
33 return value;
34 }
36 >
37 > type Deserialize<T> = T extends UriComponents ? URI
38 > : T extends VSBuffer ? VSBuffer
39 > : T extends object
40 > ? Revived<T>
41 > : T;
42 >
43 > export type Revived<T> = { [K in keyof T]: Deserialize<T[K]> };
44 >
45 > export function revive<T = any>(obj: any, depth = 0): Revived<T> {
46 if (!obj || depth > 200) {
47 return obj;
src/vs/platform/terminal/common/terminalDataBuffering.ts 28 covered LOC · 6 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- terminalDataBuffering.ts
2 > * Copyright (c) Microsoft 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 { isString } from '../../../base/common/types.js';
9 > import { IProcessDataEvent } from './terminal.js';
10 >
11 > interface TerminalDataBuffer extends IDisposable {
12 > data: string[];
13 > timeoutId: Timeout;
14 > }
15 >
16 > export class TerminalDataBufferer implements IDisposable {
17 > private readonly _terminalBufferMap = new Map<number, TerminalDataBuffer>();
18 >
19 > constructor(private readonly _callback: (id: number, data: string) => void) {
20 }
22 > dispose() {
23 for (const buffer of this._terminalBufferMap.values()) {
24 buffer.dispose();
25 }
26 }
28 > startBuffering(id: number, event: Event<string | IProcessDataEvent>, throttleBy: number = 5): IDisposable {
29
30 const disposable = event((e: string | IProcessDataEvent) => {
50 return disposable;
51 }
53 > stopBuffering(id: number) {
54 const buffer = this._terminalBufferMap.get(id);
55 buffer?.dispose();
56 }
58 > flushBuffer(id: number): void {
59 const buffer = this._terminalBufferMap.get(id);
60 if (buffer) {
src/vs/base/common/normalization.ts 27 covered LOC · 5 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- normalization.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { LRUCache } from './map.js';
7 >
8 > const nfcCache = new LRUCache<string, string>(10000); // bounded to 10000 elements
9 > export function normalizeNFC(str: string): string {
10 return normalize(str, 'NFC', nfcCache);
11 }
13 > const nfdCache = new LRUCache<string, string>(10000); // bounded to 10000 elements
14 > export function normalizeNFD(str: string): string {
15 return normalize(str, 'NFD', nfdCache);
16 }
18 > const nonAsciiCharactersPattern = /[^\u0000-\u0080]/;
19 function normalize(str: string, form: string, normalizedCache: LRUCache<string, string>): string {
20 if (!str) {
39 return res;
40 }
42 > /**
43 > * Attempts to normalize the string to Unicode base format (NFD -> remove accents -> lower case).
44 > * When original string contains accent characters directly, only lower casing will be performed.
45 > * This is done so as to keep the string length the same and not affect indices.
46 > *
47 > * @see https://stackoverflow.com/questions/990904/remove-accents-diacritics-in-a-string-in-javascript/37511463#37511463
48 > */
49 > export const tryNormalizeToBase: (str: string) => string = function () {
50 > const cache = new LRUCache<string, string>(10000); // bounded to 10000 elements
51 > const accentsRegex = /[\u0300-\u036f]/g;
52 > return function (str: string): string {
53 const cached = cache.get(str);
54 if (cached) {
src/vs/base/common/codiconsUtil.ts 26 covered LOC · 3 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; codiconsUtil.ts
28 > }
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/platform/agentPlugins/common/agentPluginParser.ts 26 covered LOC · 5 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- agentPluginParser.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { parse as parseJSONC } from '../../../base/common/json.js';
7 > import { joinPath } from '../../../base/common/resources.js';
8 > import { URI } from '../../../base/common/uri.js';
9 > import { IFileService } from '../../files/common/files.js';
10 >
11 > export const AGENT_PLUGIN_SCHEMA = 'https://agent-plugins.org/schemas/1.0.0/plugin.schema.json';
12 > export const AGENT_PLUGIN_MCP_SCHEMA = 'https://agent-plugins.org/schemas/1.0.0/mcp.schema.json';
13 >
14 > const agentPluginSchemaPrefix = 'https://agent-plugins.org/schemas/';
15 >
16 > export interface IAgentPluginManifest {
17 > readonly $schema: string;
18 > readonly name?: string;
19 > readonly version?: string;
20 > readonly description?: string;
21 > }
22 >
23 export async function readAgentPluginManifest(pluginUri: URI, fileService: IFileService): Promise<IAgentPluginManifest | undefined> {
24 const manifestUri = joinPath(pluginUri, 'plugin.json');
49 };
50 }
52 function isAgentPluginSchema(value: unknown): value is string {
53 return typeof value === 'string'
55 && value.endsWith('/plugin.schema.json');
56 }
58 function asString(value: unknown): string | undefined {
59 return typeof value === 'string' ? value : undefined;
60 }
62 function asNonEmptyString(value: unknown): string | undefined {
63 return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;
64 }
66 function isRecord(value: unknown): value is Record<string, unknown> {
67 return typeof value === 'object' && value !== null && !Array.isArray(value);
src/vs/workbench/api/common/extHostTypes/snippetTextEdit.ts 26 covered LOC · 5 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- snippetTextEdit.ts
2 > * Copyright (c) Microsoft 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 * as vscode from 'vscode';
7 > import { SnippetString } from './snippetString.js';
8 > import { Position } from './position.js';
9 > import { Range } from './range.js';
10 >
11 > export class SnippetTextEdit implements vscode.SnippetTextEdit {
12 >
13 > static isSnippetTextEdit(thing: unknown): thing is SnippetTextEdit {
14 if (thing instanceof SnippetTextEdit) {
15 return true;
21 && SnippetString.isSnippetString((<SnippetTextEdit>thing).snippet);
22 }
24 > static replace(range: Range, snippet: SnippetString): SnippetTextEdit {
25 return new SnippetTextEdit(range, snippet);
26 }
28 > static insert(position: Position, snippet: SnippetString): SnippetTextEdit {
29 return SnippetTextEdit.replace(new Range(position, position), snippet);
30 }
32 > range: Range;
33 >
34 > snippet: SnippetString;
35 >
36 > keepWhitespace?: boolean;
37 >
38 > constructor(range: Range, snippet: SnippetString) {
39 this.range = range;
40 this.snippet = snippet;
41 }
src/vs/base/common/stopwatch.ts 25 covered LOC · 6 ranges

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostRpcService.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { ProxyIdentifier, IRPCProtocol, Proxied } from '../../services/extensions/common/proxyIdentifier.js';
7 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
8 >
9 > export const IExtHostRpcService = createDecorator<IExtHostRpcService>('IExtHostRpcService');
10 >
11 > export interface IExtHostRpcService extends IRPCProtocol {
12 > readonly _serviceBrand: undefined;
13 > }
14 >
15 > export class ExtHostRpcService implements IExtHostRpcService {
16 > readonly _serviceBrand: undefined;
17 >
18 > readonly getProxy: <T>(identifier: ProxyIdentifier<T>) => Proxied<T>;
19 > readonly set: <T, R extends T> (identifier: ProxyIdentifier<T>, instance: R) => R;
20 > readonly dispose: () => void;
21 > readonly assertRegistered: (identifiers: ProxyIdentifier<any>[]) => void;
22 > readonly drain: () => Promise<void>;
23 >
24 > constructor(rpcProtocol: IRPCProtocol) {
25 this.getProxy = rpcProtocol.getProxy.bind(rpcProtocol);
26 this.set = rpcProtocol.set.bind(rpcProtocol);
src/vs/workbench/api/common/extHostUriTransformerService.ts 25 covered LOC · 2 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostUriTransformerService.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IURITransformer } from '../../../base/common/uriIpc.js';
7 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
8 > import { URI, UriComponents } from '../../../base/common/uri.js';
9 >
10 > export interface IURITransformerService extends IURITransformer {
11 > readonly _serviceBrand: undefined;
12 > }
13 >
14 > export const IURITransformerService = createDecorator<IURITransformerService>('IURITransformerService');
15 >
16 > export class URITransformerService implements IURITransformerService {
17 > declare readonly _serviceBrand: undefined;
18 >
19 > transformIncoming: (uri: UriComponents) => UriComponents;
20 > transformOutgoing: (uri: UriComponents) => UriComponents;
21 > transformOutgoingURI: (uri: URI) => URI;
22 > transformOutgoingScheme: (scheme: string) => string;
23 >
24 > constructor(delegate: IURITransformer | null) {
25 if (!delegate) {
26 this.transformIncoming = arg => arg;
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/workbench/api/common/extHostTestingPrivateApi.ts 24 covered LOC · 2 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostTestingPrivateApi.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { ExtHostTestItemEvent, InvalidTestItemError } from '../../contrib/testing/common/testItemCollection.js';
7 > import * as vscode from 'vscode';
8 >
9 > export interface IExtHostTestItemApi {
10 > controllerId: string;
11 > parent?: vscode.TestItem;
12 > listener?: (evt: ExtHostTestItemEvent) => void;
13 > }
14 >
15 > const eventPrivateApis = new WeakMap<vscode.TestItem, IExtHostTestItemApi>();
16 >
17 > export const createPrivateApiFor = (impl: vscode.TestItem, controllerId: string) => {
18 const api: IExtHostTestItemApi = { controllerId };
19 eventPrivateApis.set(impl, api);
20 return api;
21 };
23 > /**
24 > * Gets the private API for a test item implementation. This implementation
25 > * is a managed object, but we keep a weakmap to avoid exposing any of the
26 > * internals to extensions.
27 > */
28 > export const getPrivateApiFor = (impl: vscode.TestItem) => {
29 const api = eventPrivateApis.get(impl);
30 if (!api) {
src/vs/platform/contextkey/common/contextkeys.ts 23 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- contextkeys.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { isIOS, isLinux, isMacintosh, isMobile, isWeb, isWindows } from '../../../base/common/platform.js';
7 > import { localize } from '../../../nls.js';
8 > import { RawContextKey } from './contextkey.js';
9 >
10 > export const IsMacContext = new RawContextKey<boolean>('isMac', isMacintosh, localize('isMac', "Whether the operating system is macOS"));
11 > export const IsLinuxContext = new RawContextKey<boolean>('isLinux', isLinux, localize('isLinux', "Whether the operating system is Linux"));
12 > export const IsWindowsContext = new RawContextKey<boolean>('isWindows', isWindows, localize('isWindows', "Whether the operating system is Windows"));
13 >
14 > export const IsWebContext = new RawContextKey<boolean>('isWeb', isWeb, localize('isWeb', "Whether the platform is a web browser"));
15 > export const IsMacNativeContext = new RawContextKey<boolean>('isMacNative', isMacintosh && !isWeb, localize('isMacNative', "Whether the operating system is macOS on a non-browser platform"));
16 > export const IsIOSContext = new RawContextKey<boolean>('isIOS', isIOS, localize('isIOS', "Whether the operating system is iOS"));
17 > export const IsMobileContext = new RawContextKey<boolean>('isMobile', isMobile, localize('isMobile', "Whether the platform is a mobile web browser"));
18 >
19 > export const IsDevelopmentContext = new RawContextKey<boolean>('isDevelopment', false, true);
20 > export const ProductQualityContext = new RawContextKey<string>('productQualityType', '', localize('productQualityType', "Quality type of VS Code"));
21 >
22 > export const InputFocusedContextKey = 'inputFocus';
23 > export const InputFocusedContext = new RawContextKey<boolean>(InputFocusedContextKey, false, localize('inputFocus', "Whether keyboard focus is inside an input box"));
src/vs/workbench/api/common/extHostTypes/location.ts 23 covered LOC · 4 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- location.ts
2 > * Copyright (c) Microsoft 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 * as vscode from 'vscode';
7 > import { URI } from '../../../../base/common/uri.js';
8 > import { es5ClassCompat } from './es5ClassCompat.js';
9 > import { Position } from './position.js';
10 > import { Range } from './range.js';
11 >
12 > @es5ClassCompat
13 > export class Location {
14 >
15 > static isLocation(thing: unknown): thing is vscode.Location {
16 if (thing instanceof Location) {
17 return true;
23 && URI.isUri((<Location>thing).uri);
24 }
26 > uri: URI;
27 > range!: Range;
28 >
29 > constructor(uri: URI, rangeOrPosition: Range | Position) {
30 this.uri = uri;
31
40 }
41 }
43 > toJSON(): any {
44 return {
45 uri: this.uri,
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/platform/terminal/common/environmentVariableShared.ts 20 covered LOC · 6 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- environmentVariableShared.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IEnvironmentVariableCollectionDescription, IEnvironmentVariableCollection, IEnvironmentVariableMutator, ISerializableEnvironmentDescriptionMap, ISerializableEnvironmentVariableCollection, ISerializableEnvironmentVariableCollections } from './environmentVariable.js';
7 >
8 > // This file is shared between the renderer and extension host
9 >
10 > export function serializeEnvironmentVariableCollection(collection: ReadonlyMap<string, IEnvironmentVariableMutator>): ISerializableEnvironmentVariableCollection {
11 return [...collection.entries()];
12 }
14 > export function serializeEnvironmentDescriptionMap(descriptionMap: ReadonlyMap<string, IEnvironmentVariableCollectionDescription> | undefined): ISerializableEnvironmentDescriptionMap {
15 return descriptionMap ? [...descriptionMap.entries()] : [];
16 }
18 > export function deserializeEnvironmentVariableCollection(
19 serializedCollection: ISerializableEnvironmentVariableCollection
20 ): Map<string, IEnvironmentVariableMutator> {
21 return new Map<string, IEnvironmentVariableMutator>(serializedCollection);
22 }
24 > export function deserializeEnvironmentDescriptionMap(
25 serializableEnvironmentDescription: ISerializableEnvironmentDescriptionMap | undefined
26 ): Map<string, IEnvironmentVariableCollectionDescription> {
27 return new Map<string, IEnvironmentVariableCollectionDescription>(serializableEnvironmentDescription ?? []);
28 }
30 > export function serializeEnvironmentVariableCollections(collections: ReadonlyMap<string, IEnvironmentVariableCollection>): ISerializableEnvironmentVariableCollections {
31 return Array.from(collections.entries()).map(e => {
32 return [e[0], serializeEnvironmentVariableCollection(e[1].map), serializeEnvironmentDescriptionMap(e[1].descriptionMap)];
33 });
34 }
36 > export function deserializeEnvironmentVariableCollections(
37 serializedCollection: ISerializableEnvironmentVariableCollections
38 ): Map<string, IEnvironmentVariableCollection> {
src/vs/base/common/idGenerator.ts 19 covered LOC · 2 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- idGenerator.ts
2 > * Copyright (c) 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 IdGenerator {
7 >
8 > private _prefix: string;
9 > private _lastId: number;
10 >
11 > constructor(prefix: string) {
12 > this._prefix = prefix;
13 > this._lastId = 0;
14 > }
15 >
16 > public nextId(): string {
17 return this._prefix + (++this._lastId);
18 }
20 >
21 > export const defaultGenerator = new IdGenerator('id#');
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/workbench/contrib/chat/common/chatSessionTypePreference.ts 19 covered LOC · 5 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- chatSessionTypePreference.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js';
7 >
8 > export const CHAT_USER_SELECTED_SESSION_TYPE_STORAGE_KEY = 'chat.userSelectedSessionType';
9 > const CHAT_PREFERRED_COPILOT_HARNESS_STORAGE_KEY = 'chat.preferredCopilotHarness';
10 >
11 > export function getRememberedSessionType(storageService: IStorageService): string | undefined {
12 return storageService.get(CHAT_USER_SELECTED_SESSION_TYPE_STORAGE_KEY, StorageScope.PROFILE);
13 }
15 > export function storeUserSelectedSessionType(storageService: IStorageService, sessionType: string): void {
16 storageService.store(CHAT_USER_SELECTED_SESSION_TYPE_STORAGE_KEY, sessionType, StorageScope.PROFILE, StorageTarget.MACHINE);
17 }
19 > export function clearUserSelectedSessionType(storageService: IStorageService): void {
20 storageService.remove(CHAT_USER_SELECTED_SESSION_TYPE_STORAGE_KEY, StorageScope.PROFILE);
21 }
23 > export function hasPreferredCopilotHarness(storageService: IStorageService): boolean {
24 return storageService.getBoolean(CHAT_PREFERRED_COPILOT_HARNESS_STORAGE_KEY, StorageScope.PROFILE, false);
25 }
27 > export function markPreferredCopilotHarness(storageService: IStorageService): void {
28 storageService.store(CHAT_PREFERRED_COPILOT_HARNESS_STORAGE_KEY, true, StorageScope.PROFILE, StorageTarget.MACHINE);
29 }
src/vs/platform/workspace/common/virtualWorkspace.ts 18 covered LOC · 5 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- virtualWorkspace.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { Schemas } from '../../../base/common/network.js';
7 > import { URI } from '../../../base/common/uri.js';
8 > import { IWorkspace } from './workspace.js';
9 >
10 > export function isVirtualResource(resource: URI) {
11 return resource.scheme !== Schemas.file && resource.scheme !== Schemas.vscodeRemote;
12 }
14 > export function getVirtualWorkspaceLocation(workspace: IWorkspace): { scheme: string; authority: string } | undefined {
15 if (workspace.folders.length) {
16 return workspace.folders.every(f => isVirtualResource(f.uri)) ? workspace.folders[0].uri : undefined;
20 return undefined;
21 }
23 > export function getVirtualWorkspaceScheme(workspace: IWorkspace): string | undefined {
24 return getVirtualWorkspaceLocation(workspace)?.scheme;
25 }
27 > export function getVirtualWorkspaceAuthority(workspace: IWorkspace): string | undefined {
28 return getVirtualWorkspaceLocation(workspace)?.authority;
29 }
31 > export function isVirtualWorkspace(workspace: IWorkspace): boolean {
32 return getVirtualWorkspaceLocation(workspace) !== undefined;
33 }
src/vs/workbench/api/common/extHostTypes/es5ClassCompat.ts 18 covered LOC · 3 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- es5ClassCompat.ts
2 > * Copyright (c) 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 > * @deprecated
8 > *
9 > * This utility ensures that old JS code that uses functions for classes still works. Existing usages cannot be removed
10 > * but new ones must not be added
11 > */
12 > export function es5ClassCompat(target: Function): any {
13 > const interceptFunctions = {
14 > apply: function (...args: any[]): any {
15 if (args.length === 0) {
16 return Reflect.construct(target, []);
20 }
21 },
22 > call: function (...args: any[]): any { es5ClassCompat.ts
23 if (args.length === 0) {
24 return Reflect.construct(target, []);
28 }
29 }
31 > return Object.assign(target, interceptFunctions);
32 > }
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/platform/agentHost/common/state/protocol/state.ts 17 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- state.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > // allow-any-unicode-comment-file
7 > // DO NOT EDIT -- auto-generated by scripts/sync-agent-host-protocol.ts
8 >
9 > export * from './common/state.js';
10 > export * from './channels-root/state.js';
11 > export * from './channels-session/state.js';
12 > export * from './channels-chat/state.js';
13 > export * from './channels-terminal/state.js';
14 > export * from './channels-changeset/state.js';
15 > export * from './channels-annotations/state.js';
16 > export * from './channels-otlp/state.js';
17 > export * from './channels-resource-watch/state.js';
src/vs/platform/product/common/productService.ts 17 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- productService.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IProductConfiguration } from '../../../base/common/product.js';
7 > import { createDecorator } from '../../instantiation/common/instantiation.js';
8 >
9 > export const IProductService = createDecorator<IProductService>('productService');
10 >
11 > export interface IProductService extends Readonly<IProductConfiguration> {
12 >
13 > readonly _serviceBrand: undefined;
14 >
15 > }
16 >
17 > export const productSchemaId = 'vscode://schemas/vscode-product';
src/vs/platform/agentHost/common/state/protocol/commands.ts 15 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- commands.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > // allow-any-unicode-comment-file
7 > // DO NOT EDIT -- auto-generated by scripts/sync-agent-host-protocol.ts
8 >
9 > export * from './common/commands.js';
10 > export * from './channels-root/commands.js';
11 > export * from './channels-session/commands.js';
12 > export * from './channels-chat/commands.js';
13 > export * from './channels-terminal/commands.js';
14 > export * from './channels-changeset/commands.js';
15 > export * from './channels-resource-watch/commands.js';
src/vs/platform/telemetry/common/commonProperties.ts 14 covered LOC · 3 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- commonProperties.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { isLinuxSnap, platform, Platform, PlatformToString } from '../../../base/common/platform.js';
7 > import { env, platform as nodePlatform } from '../../../base/common/process.js';
8 > import { generateUuid } from '../../../base/common/uuid.js';
9 > import { ICommonProperties } from './telemetry.js';
10 >
11 function getPlatformDetail(hostname: string): string | undefined {
12 if (platform === Platform.Linux && /^penguin(\.|$)/i.test(hostname)) {
16 return undefined;
17 }
19 > export function resolveCommonProperties(
20 release: string,
21 hostname: string,
97 return result;
98 }
100 > export function verifyMicrosoftInternalDomain(domainList: readonly string[]): boolean {
101 const userDnsDomain = env['USERDNSDOMAIN'];
102 if (!userDnsDomain) {
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/workbench/api/common/extHostInitDataService.ts 13 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extHostInitDataService.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IExtensionHostInitData } from '../../services/extensions/common/extensionHostProtocol.js';
7 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
8 >
9 > export const IExtHostInitDataService = createDecorator<IExtHostInitDataService>('IExtHostInitDataService');
10 >
11 > export interface IExtHostInitDataService extends Readonly<IExtensionHostInitData> {
12 > readonly _serviceBrand: undefined;
13 > }
14
src/vs/base/common/observableInternal/commonFacade/deps.ts 10 covered LOC · 1 range

Open complete file

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

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- modelContextProtocol.ts
2 > * Copyright (c) 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 { MCP } from '../../../../platform/mcp/common/modelContextProtocol.js';