-
Notifications
You must be signed in to change notification settings - Fork 37.3k
add streaming for the terminal inlined in chat #278888
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
14e4eed
2e2448a
1e9135a
b3a58a2
130d862
6ec21ef
8bd0bac
d93fa22
ef9ea67
201015e
3a84c57
928d333
8beee67
11893d6
db19c94
0dcf9db
0d2609f
49c7df4
fea49d0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,268 @@ | ||||||||
| /*--------------------------------------------------------------------------------------------- | ||||||||
| * Copyright (c) Microsoft Corporation. All rights reserved. | ||||||||
| * Licensed under the MIT License. See License.txt in the project root for license information. | ||||||||
| *--------------------------------------------------------------------------------------------*/ | ||||||||
|
|
||||||||
| import { Disposable, DisposableStore, ImmortalReference } from '../../../../base/common/lifecycle.js'; | ||||||||
| import { Emitter, Event } from '../../../../base/common/event.js'; | ||||||||
| import type { ITerminalCommand } from '../../../../platform/terminal/common/capabilities/capabilities.js'; | ||||||||
| import { ITerminalInstance, ITerminalService, type IDetachedTerminalInstance } from './terminal.js'; | ||||||||
| import { DetachedProcessInfo } from './detachedTerminal.js'; | ||||||||
| import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; | ||||||||
| import { TerminalInstanceColorProvider } from './terminalInstance.js'; | ||||||||
| import { TerminalLocation } from '../../../../platform/terminal/common/terminal.js'; | ||||||||
| import type { Terminal as RawXtermTerminal } from '@xterm/xterm'; | ||||||||
| import { ICurrentPartialCommand } from '../../../../platform/terminal/common/capabilities/commandDetection/terminalCommand.js'; | ||||||||
|
|
||||||||
| interface IDetachedTerminalCommandMirror { | ||||||||
| attach(container: HTMLElement): Promise<void>; | ||||||||
| renderCommand(): Promise<{ lineCount?: number } | undefined>; | ||||||||
| } | ||||||||
|
|
||||||||
| /** | ||||||||
| * Mirrors a terminal command's output into a detached terminal instance. | ||||||||
| * Used in the chat terminal tool progress part to show command output for example. | ||||||||
| */ | ||||||||
| export class DetachedTerminalCommandMirror extends Disposable implements IDetachedTerminalCommandMirror { | ||||||||
| private _detachedTerminal?: IDetachedTerminalInstance; | ||||||||
| private _attachedContainer?: HTMLElement; | ||||||||
| private readonly _streamingDisposables = this._register(new DisposableStore()); | ||||||||
| private readonly _onDidUpdateEmitter = this._register(new Emitter<number>()); | ||||||||
| public readonly onDidUpdate: Event<number> = this._onDidUpdateEmitter.event; | ||||||||
|
|
||||||||
| private _lastVT = ''; | ||||||||
| private _lineCount = 0; | ||||||||
| private _lastUpToDateCursorY: number | undefined; | ||||||||
| private _lowestDirtyCursorY: number | undefined; | ||||||||
| private _highestDirtyCursorY: number | undefined; | ||||||||
|
||||||||
| private _flushPromise: Promise<void> | undefined; | ||||||||
| private _dirtyScheduled = false; | ||||||||
| private _hasInitialized = false; | ||||||||
| private _isStreaming = false; | ||||||||
| private _sourceRaw: RawXtermTerminal | undefined; | ||||||||
|
|
||||||||
| constructor( | ||||||||
| private readonly _terminalInstance: ITerminalInstance, | ||||||||
| private readonly _command: ITerminalCommand, | ||||||||
| @ITerminalService private readonly _terminalService: ITerminalService, | ||||||||
| @IInstantiationService private readonly _instantationService: IInstantiationService | ||||||||
|
||||||||
| @IInstantiationService private readonly _instantationService: IInstantiationService | |
| @IInstantiationService private readonly _instantiationService: IInstantiationService |
Copilot
AI
Nov 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Empty catch block silently swallows errors. Consider logging the error or at least adding a comment explaining why it's safe to ignore errors here.
| } catch { | |
| } catch (error) { | |
| console.error('Error in renderCommand _getCommandOutputAsVT:', error); |
Copilot
AI
Nov 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo in variable name: _instantationService should be _instantiationService (missing 'i').
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -46,6 +46,7 @@ import { equals } from '../../../../../base/common/objects.js'; | |||
| import type { IProgressState } from '@xterm/addon-progress'; | ||||
| import type { CommandDetectionCapability } from '../../../../../platform/terminal/common/capabilities/commandDetectionCapability.js'; | ||||
| import { URI } from '../../../../../base/common/uri.js'; | ||||
| import { assert } from '../../../../../base/common/assert.js'; | ||||
|
|
||||
| const enum RenderConstants { | ||||
| SmoothScrollDuration = 125 | ||||
|
|
@@ -891,6 +892,27 @@ export class XtermTerminal extends Disposable implements IXtermTerminal, IDetach | |||
| this._onDidRequestRefreshDimensions.fire(); | ||||
| } | ||||
|
|
||||
| async getRangeAsVT(startMarker: IXtermMarker, endMarker?: IXtermMarker, skipLastLine?: boolean): Promise<string> { | ||||
| if (!this._serializeAddon) { | ||||
| const Addon = await this._xtermAddonLoader.importAddon('serialize'); | ||||
| this._serializeAddon = new Addon(); | ||||
| this.raw.loadAddon(this._serializeAddon); | ||||
| } | ||||
|
|
||||
| assert(startMarker.line !== -1); | ||||
| let end = endMarker?.line ?? this.raw.buffer.active.length - 1; | ||||
| if (skipLastLine) { | ||||
| end = end - 1; | ||||
| } | ||||
| return this._serializeAddon.serialize({ | ||||
| range: { | ||||
| start: startMarker.line, | ||||
| end: end | ||||
| } | ||||
| }); | ||||
| } | ||||
|
|
||||
|
|
||||
|
||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The
IDetachedTerminalCommandMirrorinterface is incomplete - it's missing theonDidUpdateevent which is a public member ofDetachedTerminalCommandMirror. Since the interface is not exported and only used internally, consider either:onDidUpdateto the interface for completenessThis ensures the interface accurately represents the public API of the class.