@@ -56,7 +56,7 @@ class WebSocketTerminal implements vscode.Pseudoterminal {
56
56
/** The number of characters on the line that the user can't delete */
57
57
private _margin = 0 ;
58
58
59
- /** The text writted by the user since the last prompt/read */
59
+ /** The text written by the user since the last prompt/read */
60
60
private _input = "" ;
61
61
62
62
/** The position of the cursor within the line */
@@ -98,6 +98,7 @@ class WebSocketTerminal implements vscode.Pseudoterminal {
98
98
99
99
constructor (
100
100
private readonly _targetUri : vscode . Uri ,
101
+ private readonly _nonce : string ,
101
102
private readonly _nsOverride ?: string
102
103
) { }
103
104
@@ -224,7 +225,7 @@ class WebSocketTerminal implements vscode.Pseudoterminal {
224
225
this . _hideCursorWrite ( "\x1b]633;P;HasRichCommandDetection=True\x07" ) ;
225
226
// Print the opening message
226
227
this . _hideCursorWrite (
227
- `\x1b[32mConnected to \x1b[0m\x1b[4m${ api . config . host } :${ api . config . port } ${ api . config . pathPrefix } \x1b[0m\x1b[32m as \x1b[0m\x1b[3m${ api . config . username } \x1b[0m\r\n\r\n `
228
+ `\x1b[32mConnected to \x1b[0m\x1b[4m${ api . config . host } :${ api . config . port } ${ api . config . pathPrefix } \x1b[0m\x1b[32m as \x1b[0m\x1b[3m${ api . config . username } \x1b[0m\r\n`
228
229
) ;
229
230
// Add event handlers to the socket
230
231
this . _socket
@@ -273,9 +274,7 @@ class WebSocketTerminal implements vscode.Pseudoterminal {
273
274
if ( message . type == "prompt" ) {
274
275
// Write the prompt to the terminal
275
276
this . _hideCursorWrite (
276
- `\x1b]633;D${ this . _promptExitCode } \x07${ this . _margin ? "\r\n" : "" } \x1b]633;A\x07${
277
- message . text
278
- } \x1b]633;B\x07`
277
+ `\x1b]633;D${ this . _promptExitCode } \x07\r\n\x1b]633;A\x07${ message . text } \x1b]633;B\x07`
279
278
) ;
280
279
this . _margin = this . _cursorCol = message . text . replace ( this . _colorsRegex , "" ) . length ;
281
280
this . _prompt = message . text ;
@@ -366,13 +365,14 @@ class WebSocketTerminal implements vscode.Pseudoterminal {
366
365
// Send the input to the server for processing
367
366
this . _socket . send ( JSON . stringify ( { type : this . _state , input : this . _input } ) ) ;
368
367
if ( this . _state == "prompt" ) {
369
- this . _hideCursorWrite ( `\x1b]633;E;${ this . _inputEscaped ( ) } \x07\x1b]633;C\x07\r\n ` ) ;
368
+ this . _hideCursorWrite ( `\x1b]633;E;${ this . _inputEscaped ( ) } ; ${ this . _nonce } \x07\r\n\ x1b]633;C\x07` ) ;
370
369
if ( this . _input == "" ) {
371
370
this . _promptExitCode = "" ;
372
371
}
373
372
}
374
373
this . _input = "" ;
375
374
this . _state = "eval" ;
375
+ this . _margin = this . _cursorCol = 0 ;
376
376
return ;
377
377
}
378
378
case keys . ctrlH :
@@ -561,7 +561,7 @@ class WebSocketTerminal implements vscode.Pseudoterminal {
561
561
if ( this . _cursorCol == this . _margin + inputArr [ inputArr . length - 1 ] . length ) {
562
562
// Move the cursor to the beginning of the input
563
563
this . _moveCursor ( this . _margin - this . _cursorCol ) ;
564
- // Erase everyhting to the right of the cursor
564
+ // Erase everything to the right of the cursor
565
565
this . _hideCursorWrite ( "\x1b[0J" ) ;
566
566
inputArr [ inputArr . length - 1 ] = "" ;
567
567
this . _input = inputArr . join ( "\r\n" ) ;
@@ -588,10 +588,16 @@ class WebSocketTerminal implements vscode.Pseudoterminal {
588
588
// Submit the input after processing
589
589
// This should only happen due to VS Code's shell integration
590
590
submit = true ;
591
- char = char . slice ( 0 , - 1 ) ;
592
- }
593
- // Replace all single \r with \r\n (prompt) or space (read)
594
- char = char . replace ( / \r / g, this . _state == "prompt" ? "\r\n" : " " ) ;
591
+ // Need to remove any multi-line prompts that are in the command lines
592
+ // Workaround for https://github.com/microsoft/vscode/issues/258457
593
+ char = char
594
+ . slice ( 0 , - 1 )
595
+ . split ( "\r" )
596
+ . map ( ( l ) => ( l . startsWith ( this . _multiLinePrompt ) ? l . slice ( this . _multiLinePrompt . length ) : l ) )
597
+ . join ( "\r" ) ;
598
+ }
599
+ // Replace all single \r with \r\n
600
+ char = char . replace ( / \r (? ! \n ) / g, "\r\n" ) ;
595
601
const inputArr = this . _input . split ( "\r\n" ) ;
596
602
let eraseAfterCursor = "" ,
597
603
trailingText = "" ;
@@ -613,8 +619,10 @@ class WebSocketTerminal implements vscode.Pseudoterminal {
613
619
const originalCol = this . _cursorCol ;
614
620
let newRow : number ;
615
621
if ( char . includes ( "\r\n" ) ) {
616
- char = char . replace ( / \r \n / g, `\r\n${ this . _multiLinePrompt } ` ) ;
617
- this . _margin = this . _multiLinePrompt . length ;
622
+ if ( this . _state == "prompt" ) {
623
+ char = char . replaceAll ( "\r\n" , `\r\n${ this . _multiLinePrompt } ` ) ;
624
+ this . _margin = this . _multiLinePrompt . length ;
625
+ }
618
626
const charLines = char . split ( "\r\n" ) ;
619
627
newRow =
620
628
charLines . reduce (
@@ -632,21 +640,24 @@ class WebSocketTerminal implements vscode.Pseudoterminal {
632
640
const colStr = colDelta ? ( colDelta > 0 ? `\x1b[${ colDelta } C` : `\x1b[${ Math . abs ( colDelta ) } D` ) : "" ;
633
641
char += trailingText ;
634
642
const spaceOnCurrentLine = this . _cols - ( originalCol % this . _cols ) ;
635
- if ( this . _state == "read" && char . length >= spaceOnCurrentLine ) {
643
+ if ( this . _state == "read" && ( char . includes ( "\r\n" ) || char . length >= spaceOnCurrentLine ) ) {
636
644
// There's no auto-line wrapping when in read mode, so we must move the cursor manually
645
+ const charLines = char . split ( "\r\n" ) ;
637
646
// Extract all the characters that fit on the cursor's line
638
- const firstLine = char . slice ( 0 , spaceOnCurrentLine ) ;
639
- const otherLines = char . slice ( spaceOnCurrentLine ) ;
640
- const lines : string [ ] = [ ] ;
641
- if ( otherLines . length ) {
642
- // Split the rest into an array of lines that fit in the viewport
643
- for ( let line = 0 , i = 0 ; line < Math . ceil ( otherLines . length / this . _cols ) ; line ++ , i += this . _cols ) {
644
- lines [ line ] = otherLines . slice ( i , i + this . _cols ) ;
647
+ const firstLine = charLines [ 0 ] . slice ( 0 , spaceOnCurrentLine ) ;
648
+ charLines [ 0 ] = charLines [ 0 ] . slice ( spaceOnCurrentLine ) ;
649
+ // Split the rest into an array of lines that fit in the viewport
650
+ const lines = charLines . flatMap ( ( line , idx ) => {
651
+ if ( idx == charLines . length - 1 && line == "" ) {
652
+ // Add a blank " line" to move the cursor to the next viewport row
653
+ return [ "" ] ;
645
654
}
646
- } else {
647
- // Add a blank "line" to move the cursor to the next viewport row
648
- lines . push ( "" ) ;
649
- }
655
+ const chunks = [ ] ;
656
+ for ( let i = 0 ; i < line . length ; i += this . _cols ) {
657
+ chunks . push ( line . slice ( i , i + this . _cols ) ) ;
658
+ }
659
+ return chunks ;
660
+ } ) ;
650
661
// Join the lines with the cursor escape code
651
662
lines . unshift ( firstLine ) ;
652
663
char = lines . join ( "\r\n" ) ;
@@ -678,13 +689,14 @@ class WebSocketTerminal implements vscode.Pseudoterminal {
678
689
// Send the input to the server for processing
679
690
this . _socket . send ( JSON . stringify ( { type : this . _state , input : this . _input } ) ) ;
680
691
if ( this . _state == "prompt" ) {
681
- this . _hideCursorWrite ( `\x1b]633;E;${ this . _inputEscaped ( ) } \x07\x1b]633;C\x07\r\n ` ) ;
692
+ this . _hideCursorWrite ( `\x1b]633;E;${ this . _inputEscaped ( ) } ; ${ this . _nonce } \x07\r\n\ x1b]633;C\x07` ) ;
682
693
if ( this . _input == "" ) {
683
694
this . _promptExitCode = "" ;
684
695
}
685
696
}
686
697
this . _input = "" ;
687
698
this . _state = "eval" ;
699
+ this . _margin = this . _cursorCol = 0 ;
688
700
} else if ( this . _input != "" && this . _state == "prompt" && this . _syntaxColoringEnabled ( ) ) {
689
701
// Syntax color input
690
702
this . _socket . send ( JSON . stringify ( { type : "color" , input : this . _input } ) ) ;
@@ -747,6 +759,7 @@ function terminalConfigForUri(
747
759
}
748
760
749
761
sendLiteTerminalTelemetryEvent ( throwErrors ? "profile" : "command" ) ;
762
+ const nonce = crypto . randomUUID ( ) ;
750
763
return {
751
764
name : api . config . serverName && api . config . serverName != "" ? api . config . serverName : "iris" ,
752
765
location :
@@ -756,9 +769,10 @@ function terminalConfigForUri(
756
769
vscode . window . terminals . length > 0
757
770
? vscode . TerminalLocation . Editor
758
771
: vscode . TerminalLocation . Panel ,
759
- pty : new WebSocketTerminal ( targetUri , nsOverride ) ,
772
+ pty : new WebSocketTerminal ( targetUri , nonce , nsOverride ) ,
760
773
isTransient : true ,
761
774
iconPath : iscIcon ,
775
+ shellIntegrationNonce : nonce ,
762
776
} ;
763
777
}
764
778
0 commit comments