From f309affafedddf754fa4ae422de45fab1da513bf Mon Sep 17 00:00:00 2001 From: meganrogge Date: Tue, 13 Jun 2023 10:45:51 -0500 Subject: [PATCH 01/69] work on looping cue --- .../standalone/browser/standaloneServices.ts | 3 +++ .../audioCues/browser/audioCueService.ts | 20 ++++++++++++++++++- .../contrib/chat/browser/chatWidget.ts | 4 ++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/standalone/browser/standaloneServices.ts b/src/vs/editor/standalone/browser/standaloneServices.ts index 63ade6f2143..04be9018f8b 100644 --- a/src/vs/editor/standalone/browser/standaloneServices.ts +++ b/src/vs/editor/standalone/browser/standaloneServices.ts @@ -1055,6 +1055,9 @@ class StandaloneAudioService implements IAudioCueService { async playSound(cue: Sound, allowManyInParallel?: boolean | undefined): Promise { } + playAudioCueLoop(cue: AudioCue): IDisposable { + return toDisposable(() => { }); + } } export interface IEditorOverrideServices { diff --git a/src/vs/platform/audioCues/browser/audioCueService.ts b/src/vs/platform/audioCues/browser/audioCueService.ts index 90a707db13a..e9486c80517 100644 --- a/src/vs/platform/audioCues/browser/audioCueService.ts +++ b/src/vs/platform/audioCues/browser/audioCueService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Disposable } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { FileAccess } from 'vs/base/common/network'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -22,6 +22,7 @@ export interface IAudioCueService { onEnabledChanged(cue: AudioCue): Event; playSound(cue: Sound, allowManyInParallel?: boolean): Promise; + playAudioCueLoop(cue: AudioCue): IDisposable; } export class AudioCueService extends Disposable implements IAudioCueService { @@ -87,6 +88,23 @@ export class AudioCueService extends Disposable implements IAudioCueService { } } + public playAudioCueLoop(cue: AudioCue): IDisposable { + let playing = true; + const playSound = () => { + if (playing) { + this.playSound(cue.sound, true).finally(() => { + if (playing) { + playSound(); + } + }); + } + }; + playSound(); + return toDisposable(() => { + playing = false; + }); + } + private readonly obsoleteAudioCuesEnabled = observableFromEvent( Event.filter(this.configurationService.onDidChangeConfiguration, (e) => e.affectsConfiguration('audioCues.enabled') diff --git a/src/vs/workbench/contrib/chat/browser/chatWidget.ts b/src/vs/workbench/contrib/chat/browser/chatWidget.ts index 0956e550ac8..73f36ae572f 100644 --- a/src/vs/workbench/contrib/chat/browser/chatWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/chatWidget.ts @@ -16,6 +16,7 @@ import 'vs/css!./media/chat'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { localize } from 'vs/nls'; import { MenuId } from 'vs/platform/actions/common/actions'; +import { AudioCue, IAudioCueService } from 'vs/platform/audioCues/browser/audioCueService'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -115,6 +116,7 @@ export class ChatWidget extends Disposable implements IChatWidget { @IChatService private readonly chatService: IChatService, @IChatWidgetService chatWidgetService: IChatWidgetService, @IContextMenuService private readonly contextMenuService: IContextMenuService, + @IAudioCueService private readonly audioCueService: IAudioCueService ) { super(); CONTEXT_IN_CHAT_SESSION.bindTo(contextKeyService).set(true); @@ -390,8 +392,10 @@ export class ChatWidget extends Disposable implements IChatWidget { } const input = query ?? editorValue; + const cue = this.audioCueService.playAudioCueLoop(AudioCue.break); const result = await this.chatService.sendRequest(this.viewModel.sessionId, input); if (result) { + cue.dispose(); this.inputPart.acceptInput(query); result.responseCompletePromise.then(() => { const responses = this.viewModel?.getItems().filter(isResponseVM); From 26415018352370814d97ebf41253ae07637d7af9 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Tue, 13 Jun 2023 11:20:09 -0500 Subject: [PATCH 02/69] use sounds --- .../audioCues/browser/audioCueService.ts | 14 ++++++++++++++ .../audioCues/browser/media/chatRequestSent.mp3 | Bin 0 -> 36352 bytes .../browser/media/chatResponsePending.mp3 | Bin 0 -> 36352 bytes .../audioCues/browser/audioCues.contribution.ts | 8 ++++++++ .../contrib/chat/browser/chatWidget.ts | 6 +++--- 5 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 src/vs/platform/audioCues/browser/media/chatRequestSent.mp3 create mode 100644 src/vs/platform/audioCues/browser/media/chatResponsePending.mp3 diff --git a/src/vs/platform/audioCues/browser/audioCueService.ts b/src/vs/platform/audioCues/browser/audioCueService.ts index e9486c80517..32d0cf2678b 100644 --- a/src/vs/platform/audioCues/browser/audioCueService.ts +++ b/src/vs/platform/audioCues/browser/audioCueService.ts @@ -208,6 +208,8 @@ export class Sound { public static readonly diffLineInserted = Sound.register({ fileName: 'diffLineInserted.mp3' }); public static readonly diffLineDeleted = Sound.register({ fileName: 'diffLineDeleted.mp3' }); public static readonly diffLineModified = Sound.register({ fileName: 'diffLineModified.mp3' }); + public static readonly chatRequestSent = Sound.register({ fileName: 'chatRequestSent.mp3' }); + public static readonly chatResponsePending = Sound.register({ fileName: 'chatResponsePending.mp3' }); private constructor(public readonly fileName: string) { } } @@ -327,6 +329,18 @@ export class AudioCue { settingsKey: 'audioCues.diffLineModified' }); + public static readonly chatRequestSent = AudioCue.register({ + name: localize('audioCues.chatRequestSent', 'Chat Request Sent'), + sound: Sound.chatRequestSent, + settingsKey: 'audioCues.chatRequestSent' + }); + + public static readonly chatResponsePending = AudioCue.register({ + name: localize('audioCues.chatResponsePending', 'Chat Response Pending'), + sound: Sound.chatResponsePending, + settingsKey: 'audioCues.chatResponsePending' + }); + private constructor( public readonly sound: Sound, public readonly name: string, diff --git a/src/vs/platform/audioCues/browser/media/chatRequestSent.mp3 b/src/vs/platform/audioCues/browser/media/chatRequestSent.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..ac0791ef6bbfe62b102fbbdf71dbf27a0bc92a08 GIT binary patch literal 36352 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 R{$l3*;^!~su%FD_{{c8q7=-`; literal 0 HcmV?d00001 diff --git a/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts b/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts index 61153542d54..a43adc7c7f8 100644 --- a/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts +++ b/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts @@ -117,6 +117,14 @@ Registry.as(ConfigurationExtensions.Configuration).regis 'description': localize('audioCues.notebookCellFailed', "Plays a sound when a notebook cell execution fails."), ...audioCueFeatureBase, }, + 'audioCues.chatRequestSent': { + 'description': localize('audioCues.chatRequestSent', "Plays a sound when a chat request is made."), + ...audioCueFeatureBase + }, + 'audioCues.chatResponsePending': { + 'description': localize('audioCues.chatResponsePending', "Plays a sound on loop while the response is pending."), + ...audioCueFeatureBase + } } }); diff --git a/src/vs/workbench/contrib/chat/browser/chatWidget.ts b/src/vs/workbench/contrib/chat/browser/chatWidget.ts index 73f36ae572f..f13005eb58f 100644 --- a/src/vs/workbench/contrib/chat/browser/chatWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/chatWidget.ts @@ -390,18 +390,18 @@ export class ChatWidget extends Disposable implements IChatWidget { this.instantiationService.invokeFunction(clearChatSession, this); return; } - + await this.audioCueService.playAudioCue(AudioCue.chatRequestSent); const input = query ?? editorValue; - const cue = this.audioCueService.playAudioCueLoop(AudioCue.break); const result = await this.chatService.sendRequest(this.viewModel.sessionId, input); + const cue = this.audioCueService.playAudioCueLoop(AudioCue.chatResponsePending); if (result) { - cue.dispose(); this.inputPart.acceptInput(query); result.responseCompletePromise.then(() => { const responses = this.viewModel?.getItems().filter(isResponseVM); const lastResponse = responses?.[responses.length - 1]; if (lastResponse) { const errorDetails = lastResponse.errorDetails ? ` ${lastResponse.errorDetails.message}` : ''; + cue.dispose(); alert(lastResponse.response.value + errorDetails); } }); From 660a3228b2a9d86f2a96ee5ba6b2ef48d8f6aafb Mon Sep 17 00:00:00 2001 From: meganrogge Date: Wed, 14 Jun 2023 13:29:55 -0500 Subject: [PATCH 03/69] rm and append dom node --- .../contrib/chat/browser/chatInputPart.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts index d4ac5f52d13..cb3b9934fa3 100644 --- a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts @@ -59,6 +59,8 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge private followupsDisposables = this._register(new DisposableStore()); private _inputEditor!: CodeEditorWidget; + private _inputEditorElement!: HTMLElement; + public get inputEditor() { return this._inputEditor; } @@ -148,8 +150,14 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge this.history.add(editorValue); } - this._inputEditor.focus(); + const domNode = this._inputEditor.getDomNode(); + if (!domNode) { + return; + } + this._inputEditorElement.removeChild(domNode); this._inputEditor.setValue(''); + this._inputEditorElement.appendChild(domNode); + this._inputEditor.focus(); } render(container: HTMLElement, initialValue: string, widget: IChatWidget) { @@ -181,8 +189,8 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge options.suggest = { showIcons: false }; options.scrollbar = { ...(options.scrollbar ?? {}), vertical: 'hidden' }; - const inputEditorElement = dom.append(inputContainer, $('.interactive-input-editor')); - this._inputEditor = this._register(scopedInstantiationService.createInstance(CodeEditorWidget, inputEditorElement, options, getSimpleCodeEditorWidgetOptions())); + this._inputEditorElement = dom.append(inputContainer, $('.interactive-input-editor')); + this._inputEditor = this._register(scopedInstantiationService.createInstance(CodeEditorWidget, this._inputEditorElement, options, getSimpleCodeEditorWidgetOptions())); this._register(this._inputEditor.onDidChangeModelContent(() => { const currentHeight = Math.min(this._inputEditor.getContentHeight(), INPUT_EDITOR_MAX_HEIGHT); From 9cd42d9369376def607192e3a280e82b489b1ca6 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Wed, 14 Jun 2023 14:54:35 -0500 Subject: [PATCH 04/69] add another cue --- .../audioCues/browser/audioCueService.ts | 7 +++++++ .../browser/media/chatResponseReceived.mp3 | Bin 0 -> 36352 bytes .../audioCues/browser/audioCues.contribution.ts | 4 ++++ .../contrib/chat/browser/chatWidget.ts | 10 ++++++---- 4 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 src/vs/platform/audioCues/browser/media/chatResponseReceived.mp3 diff --git a/src/vs/platform/audioCues/browser/audioCueService.ts b/src/vs/platform/audioCues/browser/audioCueService.ts index 32d0cf2678b..fd7c40f9439 100644 --- a/src/vs/platform/audioCues/browser/audioCueService.ts +++ b/src/vs/platform/audioCues/browser/audioCueService.ts @@ -210,6 +210,7 @@ export class Sound { public static readonly diffLineModified = Sound.register({ fileName: 'diffLineModified.mp3' }); public static readonly chatRequestSent = Sound.register({ fileName: 'chatRequestSent.mp3' }); public static readonly chatResponsePending = Sound.register({ fileName: 'chatResponsePending.mp3' }); + public static readonly chatResponseReceived = Sound.register({ fileName: 'chatResponseReceived.mp3' }); private constructor(public readonly fileName: string) { } } @@ -341,6 +342,12 @@ export class AudioCue { settingsKey: 'audioCues.chatResponsePending' }); + public static readonly chatResponseReceived = AudioCue.register({ + name: localize('audioCues.chatResponseReceived', 'Chat Response Received'), + sound: Sound.chatResponseReceived, + settingsKey: 'audioCues.chatResponseReceived' + }); + private constructor( public readonly sound: Sound, public readonly name: string, diff --git a/src/vs/platform/audioCues/browser/media/chatResponseReceived.mp3 b/src/vs/platform/audioCues/browser/media/chatResponseReceived.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..c3ee2a511cecec3ae122e9744b21cb95ec7de0b5 GIT binary patch literal 36352 zcmeFZc{o)68$WzzF&Klf4_U@8p<`dN%*Yyw5TzJfDngbLF=s3xdlX6`ktLxGEsT9h zmPngWmMj&LeL2s}=kxtOzw7z$`RDoPxxVk~a(N$S=6#?0yxy<-zF+VA8cP#(B)}LF z7ai>F0e}y%4)8haNwf_LAUYFOK@|-Zor6bg0N@PZ?eBBeA=Llyk)t*M5&UQ9X#97g z{_jMUZ2I4c_J96m2L3-MYTCO0zDrHp_`k0)(fPk$1N^gE^nX{gx3M+;?`q(GK1ogW zKNB7De?R+QbIepV|IZ)(`9!UQ|9unV75`b||J{V?lmCtXdEkE@_@4*<=Yjuu;C~+Y zp9lWuf&Y2ne;)Xs2ma@Q|9Rm5FCKumo{|{%VvDMU+Cd~1xVT7Y2M+Q}jpD%O1dmvk zrmF-yXCh(IR6IjUEBF7*&WxX}ICoDTBY)o~rBtKXqRXKtOMdiH-n===#>J6GN7X=D z|2(-^(dy$pr-lH7fDf=e8u(tvNZd zQ;$inN(}{CFWr>P{3QR%o#)HndSb5Abk@C&S<}>WTLbI5`=4w6UB9*qNBov;-SRg4 z_(ABF=A5X_B6VtQ%?*YH8donxZN;x>wO{IkcMLcBy=<gm{j zZQFH_V68S>nvhwwTp*ZSY*evOGTv1+6Er_`G}|rQh*kEtr`wT)s)dRA#3vC<+xWhf z{MPUt-*y;#`=O1x+r9b8O>}g(njbIqgI<)60;Q`{pAcqm+&UK88Jv&IdPrNE(Z8+Fdz{zn-sQx6dQTUmn$Ic&PVV!t_Dfz;uDe`);qq_6Z<%e=`$5bO1f#qm5E>3C!(z zKJK05FFad5&H4IQi`dgUh}ze6mPN-?lfGvqHd;_8PVA;jeaDI)>aXJ5Z1`}FNGp}M ze4j$xSP&*yH^pU5iuTob#sgQr^c83Rl7p8u6Vd_v<&2`EpD8 z=!uT(5_>2>&oyr3VR-W#48IzqIuCo!;|XGBH%RnSpQyZJ z*-tAXRw547P-?T?b8KARY8J=qSa?h>neUfOJ9)SE$*?AQ$x%Z7=ec3uw7Dq-UhVTm zd<0&WgIY3N+DBDO3A{)PT-nKl^)5b-Ok=IXE}rEbJ|PiDb3D;_ z*=SKcWqJ(0HNO)8S24g7Nu}<>wGHa!N3YKzYfd~GcFRwm``mcvHrDv#=`wto=+W{Y z@2q>8*OZcf)|}?Gq{hI1W5}zff=h>eeb*Q8w{noOb z76it!tB$yU)<{)n0i6;))sGpVAC3p`AXay$qb-Dv#wimpI1a%0Z=Pe~u{F(_0tIOt z?b|xnxzVr>RVpcmt!Dr9u2y{e^f}*ubbc8=n!2{uw@UQC(>KXFC**moFB}UME}eYc z@BRy3Vcz=Ia!>f(lqYkfeVKuMv+?wj0L54~$O^SF@-{0*l|ZV!CrQFG@pA}5{W?KH z)!7GK^0fehvHsj;J{WGwuV!Q=vFWE+-4!m5HhvaQLJtx_H$Wt)?CH5hBoQHv*}wYQ$kxlf%I>)h3`Jnhy=iNFfKgiE7a|>uizc zq&hU`R4=BVA5ay^W6LmIwpIADqHyETw>fK9&Urod^HuK+UT*#Tdfu(yO%C6 ztp6Cjx>Pi$H8CN+zRr@-0hFH!_-Az(HhAhkvQ#hPjl&}STAvE`5SwC~PO|g}3Ji7j zU~%kFD?OP5hk#DvOjrQXXFUKU!w-y)*ODg{4fgKeGbhjH?$sVf%+`~jDUSV6{_}H1 zPJD9o#jqLRF7>a&;{&EO5h$n~lbsahqtF z&;w){x$#%e`qTd70M(@yYNtWOULc{c2;V~BM!H9Tj1}HAl8k0^!$EZ<-5gY`F0Io( z4yxbhIS#3bbIEphqjm8awzedj5wvx_{J?yr5feXd02**^LVY?A81jYyMlkSm$`iwF zXVU~fB+?l8QLg(H;PyhVb~)|S8$-uox4f4U8>Ww_3-G{8BasUa3INXfYOiABp9MoTB&d@B5YnuerOy7vK8_#VG$~uc1bijlnW= zZpkjf*JVxbeRbl1nD_|=P>asSO#ILk*O~aiBTiwt-EEptN|NN+J9UmXI8M3!<05!| zlDkme>HAu+13?qv{ybbjAZ>{jxNpzfMp`NfN!Sk+LL@GNL_9f`E+NYfjdP_!x{wYn zhYb>GJv{-4Nmi*m+10!J!j!Xw!uuI}O5MdNVsGDW^smE_Mn+--Ysbmi6#Kn+naIJvIR^mt`VA6c7Re4(`-zkeB2r1p1YPJX z1W6LuW9^b`g$b+xdo&(HKmzPBI!AMezM9L&mOXu&L=TGL=zM(fy7+!1ru5CxCWSuzVH+JH>*GEYQ$KY$Q;niTJ-CFoJb!`#1`?!z$ z$B4h%ryy25}giVpnF^%VVI{7a2yl>icmByJIM=egCRmS*yN(@>&ny#!#h=8r-!&6 z-q=53x4g40WV&YP1FsptNrCl!^*&plf0eyYGrxp+-R%DL%=ox(fd*p>&;Np9D%_}E z`0CHsx|>^*zP#)}*Bwk)+bS^GWWa)JIc|b$@i`D<-K~2E?A{uCcsSeZk;8&tONNL>(5Q+q z%qSON_{Sfvn9-Digvcu;nTU1yOw>0;b?zQ1dlYGp^qwZp2_}9r0knzBLDYtCU?N8t zB|_1kC-f8-_f%!G);{;9?Pqm}MfMh;2gQegkP`r#s67iF*$=U^lk7kgAP!2<9E1S? z?NE@8UmL31e?48sUnsnhScZNCy~_Qal$L+F&i@h|(g>?lxkk?BEIbu`1{-b|Jni6i z&iJSzcH|ysM@N%y54^kM#>m@tB5mI48oi&4e9TWkAtZCc*z$Ak6)fivpjqJrRw4m2 z?o0s2Epjk`5CKVgnj=%N7XsMqmMB_1+!SsL=mcJBK0$y@(>Xj5T<-SgfyUd@G;qDY5bU@!QtMBy}6&!iOOi-A6{LJ_A&Eg$n!}+4p6T3NOIhMamcb#o(4#FE?x2 z7IFmh1<*ei_x=3=QMp+}Gnre7v7f+V))Z6g!{UxTSTL?2ZFq!J$KuKg}XyQ}0Y6#HOU zn+*>Apc?c)+uq!Sqctl8MqGXMtB(EX)jA#F9{XMN3FUd{^8^d=!aQ0pm0<$&fkb)s z-uxTx6&0VK1tOc-z>l^Cs;7~7P?U6C?Fth=Nf2tu#e~T}SLe?_5uE<`PsjPW-`X?_ zSKcH4d{&n-3aSInAc8Ip;vqE1LGD5Uk2C-P0-`C>*4!j%G=u@7vFThC!^wWrfUJOSZvGz%V=|J)$mKZlCanH}rqYGSXvOHK9B3EC-X+>PaH z&mv~W&>(`5V*sls_E@rsA0i^ z0Gpa7bbg+4VQd)zP#Q=CSxKy*bPNwTNhh-ck0`8w2}J}rOrgj0tlmmwR5tvjaQ9JYz326^3*AmuL4Qu9PbUUj z{*wc)Kmb3Hh)vE+NdAkBi(S5~V%x0$GL~*3bA#7FL1ZAdK=|7CZ8hBe0$=2D!X8Ob zQNHSY@Y&S^Mt?rQ9L%!oM+ZEyt;E zxv=pd3KWiOm15wBk`Az3K4l!UaXZlc+9$ryAO3>gp*ZeotgY2swv`Hx z4Qn|$DHbrgzC2vW6?rJJg5%}qH}PT)XR{)1l>RyCSo{22ZG^u3IHpYuP{LU|8x{W&zc5T^O?z%hp`{awdt$1?C4r|EUBWm+s}xsdx{ zalxE56#dh$3kQvzdke!e)LOR+_`@#cbJyJqPg`Ywa0l&6zkxtgx;^xhOSFkEtWj5w zzTs73N09jCkPyimidn(jE+EV(VqOZQ;2YgbVh^GTk*u~D1Q9^U3_WS_Th+c3a%d+% z@4TVn;RF5IVpr%NSgWdEZdPHn1K=$x!v||K+l^1MK%A+y+RvXzbyQp)7--C=O-T*} zW$4AAC=)+v5DVa9g4)as^v3Eeg+Fi=koCoLPyK4TSK&#UEvo}gfWm+c$OX-VA4rNI zKxZWrA!IN>5~`s9PVWk!_>5zP@A`sh#8=r<0$)7#jzz_p2Ya0K($H!=Bb2r+bb9Pp z^~8NNg`UaB>PiXq-01|6y755H>k)`EITGA-=LyC#;0CXKj>;v!i9JtdER_8m~%|< z%{ivS7#d+j2o;w2mHkllyO4UdleU2?SEgw76(iqBB9Cx9#IGxoW>8`%PXHx*kWU~n=ls?CP?)7xPEwlLGwj6FjXjf>R0YJ{h5}cD zjwE;aV&6}Yy63;+>t3{!Gej`|fB5&;px?I#ZlLZd^UC|}{Yi&qub9kIqI!z=786#sRt zJzshD@50XUNO+?c?moE-_g=dF#N6TiU(7ELWPtO!<7P^;V>zKc?*lVvuE8r?p?9b5 z*mP9c2iNnV@fw+^y-)d2I=c42HkY(PSa}OFi}fJ$AOYksA%3~aj9=FQ)ao%))Sz!* z^qVu)jQkn@)|U~#Dw}01J;;pwht;I$kQYS|x=y)-7=2@mx|+i?ehewZM-jcnLeWk> zlHL?6eC3;-=moaWt08g96Dpq+bDtlY6Z7=BnZIAKB3q}&c1TP@2tW6oV4`WvwwVvV zUtm6`%`Z6{KK@>MA$n;J6cNldPc7Y}p26|16i39vCmq-(w}$O?(^@16Q+2@hsS>Vt(x3>6`O4&e(|SD(p`o=7HBB3^oTm* z`4vtH-fdlzs9O)VJ+{Yl(d+z`rC3Br$_P+_M=c&BkEs^Qq@E~>v;zJ0JFr0UT^ z(&1;jt0zJ>Qw@Vw^*c%D{ zZg#@MUjL`qc!*{QNjK#O$%z*J*-@#$(!f2YdoGJzrJ-ax(t^7AVsLJ4#_;i&PjANI zOoyDaDYwO+q=lTZi19K|-}4Cu{~8NqTw4Zna6q_AJPM3GVjgXCU>pyE zot!~_;wU3=B%Wdm9%Lu8&`WW{kB{mfxp_q8!Wo}EdLuQh8CAlUU;R#NTS!Ws@1)6f zxR}9kBjZ8Ae{S4)tl~~iv2cIwYvCD|dW90o(hztK`-)=6+H;U zc)2TI<#`73wPH27I>BO>H%JH+bW3fTwc%hXOA) z!4l5QNY%YN?UaUd==4v;W_Mi2hQ=0lsqp*V(;NCPyS9Brugv?{{BdL6#3lsL`FYI_ z(MB005hir zN)L62Lflu;>4d8oTTVGNfwdi=$e9VA`3FA`dgz#O%w|&H`MJ8L@N@oIj-goYIh&^B z3eQA_{sWi+1;E}REMl7;gEXL+9p+c&C)!#N5NaJt!fM@f^V3D0?WwC5!0*ZnhodK= z{=BPoAFKa(#L#GaHMQf?cF2X%yV=haJw?`cO&rtt-lxUtiJ%Mx1WSal0bK#`O8AS{ zr)=QgBek7R{0`J-pWv)qu9z}tWZVus51?a^<9cd5S}ps=Z9z+*X^$!ZoEPe1kdd?u zz4gQB0A4W16rKFk)5O^#xdGcIU^voGv(|bZJPg=^SW*nA0Z5@^o{LHo zC`j2c5CO!3Cgkf0@MKNn@O!n0|>LoFP3 z$-Cb~V|n#v-0EcCEH<|J5KGulghm*B8qlG;AfD1uKp5SK9cmH+@Xu3n=*EbrO&aLP zwA9jL20Ei%4+m1F>7U1HO0R!ERDS*OX7i=UdnfW1PPiVJ>NFjjGB(of*IG0_fC#>-X#X&ID4G{dt)D!>HfEeUi-joq~oYDH@Do z3xRw=`2(>D0D2n`7F9-T<-isSOX`{1$`?DjFGnHF#6GVL5B9|VlvSua@x$v;$k=QH zBlPMotnS}h?OhyjudpPVoEplfMIt-_3A- z-QL}_CW4=Ep{HY$+wotLg-G#l1yT4O3|-a?iU!#sZjikh02Sy+a#lUaO>zbe$h_Aj zJI~goZ+6>DA)aD$-!|^=dQ$vo!ctlC>pBOPx)$8Hnf`gFHDWuO;<`J@5S44|U!LJO zPd@qZIA=;xYuIvl>#Nl#@NN|&bA&fv*C)+u&il>G+h>J$1E6|Kx~jNaAgJ4F2C_hz z8kEjApbB7xff6Vz&>;#Eu}av(i^|yxi6RGR=h!cHqMarlaF@SR%(F=7i{G;TdT-V$ zxgJNEzg@%nE^5>j{(XeHONNIlSmB*sc;fO;%b=P;Ti1Gila&jOV#X}P5%BI9WB*iD zbZ>ObPnoKu*=^V(6Qod*j%O!`f%{v~KhZG9E7wrhVur%-q>_K{lbn0^;W&6V$k(WJ^;FmV7(BGF z^TOaw)eZh<2?xBsNxtvs?_HlVDuv;lMur(H8!_|B^E1Ms8*|Cx<7z!G2F@mL5+!hw zflU0Q0BEHXElm9G9=8}2fz3f5Z3jB zdNgvr%35M5>P>uvIp(gxnYUitNz-&pN;8PDzOz1q@lZQ{(R^>$BqVaUHflg1Y6h65~6UuC3gSls@0K?IjVoPfMWV zbsa@n)A;y#4k}aE9fM)%^Q?M7YKCcVhAE{nuHM)7PM>}mcbXu?#7`207ISQl`D-5- zXXR`gb=NI135KhdOQhXuP2Tr#uNIDf(pTLdW{dufD4j!TEnKk8KFekKXKqmkgsS)`A+; zZ!K1S*N^$oGL!NB@TXx0Vb*R@YvI~jjUOC(qNPs?do>DUwK&K*{QMURv{;&AW!Mu7 zwj(y8Um-2o*jN@oH2Je2hMe1FjSdvRVQh~Te&?}Bm4t4~(N|a`u$3pS=hhtFCzh*L zO?qFiwQ93FBECHN`sH?hhufi{#$Cs++eMW@2awC)~imJvCr)fzg zqTgslcgNRs^U4H;XU$-NhG4$Tk2$H!+B$QBGyH~?jQSMXe zz6QLsz_a~M>nEqOyB}=5AKS>?99w=p)+PFzanqZ=qFY`|wYDKvssdwfYHY_!Ez^e^ zVK@7KAT-jna&u)lt|zO~45)Uys<$V!UB4g*!}cHk(LB-g5C3$31R3!Qf5#WiJy6*! zQCUFV)U0DWa5_VhrM18|hZ9g{YW`(1H=nf(GEFRypJl0q%Q^;a(M6KxLum9GHI37zJLF7kGUG7lVQ zPyUha7^RSe|EWK{X?A;R?dEVI<2K3d8m71n`n6w>#-&#OPJO~qzysD8N~W6&gL>3v3@7C8%xiZ7U;=GP zt?SSa^*;y~@Fv+Mjn6CYGToa)1IwFFKKv7@OEO?&PU( zBM(K8tIhU%GXL}D5w7y&V?Ul->W}G7uI)~V1+4e&PFA|XKXhSNSVpIpnjrmMzqYWW z|3hox@<0BlfOj7~pFTP3V|7P5%<^Qp_*aOzk@_WBE#=FyL7(rZ5sYV%x~hc_bwcBqVBo7)|C3_f(f(KGNV zw#HVc^u%}%^yDnQv=)STaJ>^-J!lfbngzsJvjG4OQ5}{nKmi75gCG~l3>2ivIrvUK zyvKHP;!-Xro-Wz&x->KA;pdEU7o(1nw?<22KX&gQqaHm1M;A)Kp0~FH{EkdZ?G_>r zio_N9PFVPa$JRfSg&8$548Q-?<91@_DQmXV-G|^wl98HUqLI2rQvetW^lAv0WrCUz zKZvCZh$Cj`0%%;0zE=8n60k|x7tLQt9%W@0foASSsG>v_aBOM^L$%rI^k}yskqeDDYBtRD3vJ!SHU}1l5QvuCUt0cSrN$YhQiux zuEKQUJmCPuky|m72#_Fu0U__}D&(6@_Gq zUb_CQvSw(lf?zSb^(wbFb90rt(=`uwxxvyYF8O~);0F^Q>o%b0!x95MasHL35!NdS zD|5^gkQuoCWt~`T-t)gXdf$2owW(xb6AylZFfe_~GnS9QL;06~P~VQxnei(g+X*oF zC-U4b6F&l#6vTE}ogNL6Lqk|07BpJw0vlouq$ooC6dmN%QVx{vzB9!+CUpZ|%_5FL z6(+A<$QREQTLw=n%tn0Jm%pYkO|7YdZ~MWpQQyYP?Z&pjZPI$V%h-*p4UE$KKPLuN zRXvvnzlt9-n_0Pg1C(f9RF(W34ZcS;gF@sowQt^BCh zzrE6X<#s}gKL>Ymi|aNhSf?d4^@7=vvjER8blx^u>k|y$&?JFI(H3e^ACuMPP;#I< z38%@?c?uMQqCie)uL1&1XJdKTtPR-d%SmacaJ_s1d~MlHjNuF=c>UK-B9}`3cSM{04wotCmHm11a3kZi z=@dhgatT_~JO1v6#ndB=e}MJ)818htg{bqo4kw{0`sL~dg_{oCMzAi@0_!U3bvB=;b{N8ih%=o3K>_*#oR)@pld0U`d z6he=JK{ik}AcfmKM7lXpO%FkT@Iay1u3q6dj!yv)h8Q+G@e4fs>bQ$`I8l!vmBgT4 z75~8JJ{c+@9)DijKls34oo(`ZT2#JpTa+x5bT*j;$xsrr!x@C*H--tyMsVu8!-l;Ly^2mxf9+ zvTz07ah}R>*6!Huqmt?Ul~JE)5fyKJLBSZ5s{O4WszwKIfbxhd8eSb~AdXH)0I3vl zK#85j%UQ?!^KcJ}!fDNlH_QL_hE*H~D$AU_Z_O%#LW;WUNnO?Af;Pg8?&o%i8t|*; zUis$NJh>pN7Z` z8GpwZIR6lKt7V9)jNwn&>^v1IIq*#D$(7vL(>S}F`|`AVw^;3B9Wa;6=oVz!5F)sFaxy^4nR zoiXMl(L4pCkW#$d7gu}w?zvIz+u-(`aC@i!*zU5>4fYPCwSOX^zd{9rD# z{_=a3K%}8`Ta-}4CFXJE<`?)&WqsAnknn`BFVg%OhVNjw)_tz(*z>nL)%mt_;MGoB zJ$9T%(mA9^?kPYHg*}=gDqQYTWC4F@EUK_!$#Gm4}h9>{E>A z^y-JauJvVI9q=za6KPV@lTxl{-Vk|%ELSftocMyKTbGV~8EB^5AaS$55oUBnGAQW% z2HzPU%|G`w>&@?zz_YCu;BDzr)!QcRpdn36^M02l2h>iHg`5ejISIn)V6+AQuN)RY zJ%^uIE6pQW!RE-8>ZCj+M(?mG_!Ifq#q3Lvj4(~b=jah1BOkrplbP?LzBg`Pe-=r7 zvmgG@uqvUG<}Xoq)<0grG)gG-()-;<|2SmqOV*1d-CBnFvLfEce3tMWsEpiJ3;UX- zwuE{IdeGg}ik(1^K;j2^0Com3qA*Ak48FQnEf^TbsIy#Q3qA26@v+VK$Yb%w=hdy_ zL(iN0$(*)xNKg7b*8G5aJ^)^hDTgWCa9SA*C&1g`Et5|?^#U&NQhC}ri`x>^U%NlP zdx4wThrm!)io3t0yEvJ+7+!j#+k&y>joI%gbkN`oQJU@VzxY8@Tnw1`PhwJbH4{JX zeyhy*rMOR=S%2}WJ3#3u6dFOYWhWLG_8>`4J)+etS=SW^2#OkkmtIz7;wBDNBMvCV zs|uXv!Ml@p;cXWuiYFL=q@yl-;{`TS8gBMpE zdG*aU#^9a%6+8Q4|Sl z1b~c%?(-w7(Zm8ekZQ-kQd4vul7|HJ^qhN;Q1YRdz<#Awv+-7mpKjUfSrH#H90fEQ z>|EFn_xBD`+c!4edyX|0?7#yTzH}Bv6_iP)7)w5zS3xchiSZ6a>@Z57_lypXxq~?k zA$`TYgaDT_U;uJW_2x0E+I8d_=t@4Rp=X`}3If(33*g51kpU5iJvfeBbXDg#`!uRk za?soMLjN}wB0Iv5H4m_pPJA1u%Hw@Aaf$8F+=cZ_g$cFKNvG?b(k7_44DEh{-)8;! z>eO6vn+TVpJN7Zzh=J%|Z~iKeCB@6mg)pud1o;F>*B<1}9Si1)HOd6e2p<$TJ$MlH z6Z?$_9Aup3BIr6eJWI**X#^2VEV$DS0hmHEsr95_vn0C+1|lJoMGxofYPDvK)Dg0- z+bvz0a^Y+^uBq9bmPU)~+zos>EEmi}b&hmRfB0FX4Vs?7T%OltgrUz z@z=V#;M{HvMpgosHoZZ0cIP1-dfkATW&qLJ)@uE<$pfK8w*$sO#05sPf!*S%Op3LY~;2$iw!=1P>wXWI#IPZ8Gd|GVJt;SUpM+G3zLSvQ ztl7QyDvvz>EWUV)BW{IvT37nyjXm3SpTxHWF66D@Rirz=o^%uoyB=K0DBk}O!nT5= z0@tEUlxE-Syki&z+eQBoL&UBBR!t6Q}q_-+j>K)oS{nUdC!g9eG6U?;D`DQe8jF>%!E= z^@*CI$%FpNeIB!sE6c>>_pDRCM(`Y?AZ>&z#&T;FRt#wzRd3IMng=bwrzc;5&N1U4 z6F(^s+UCS-)L-AgSYM|CX8v4u?k|IXnieZvn>NbokWDoj@d;)aT8SE}5b{7ILIg~1 z4C8BK6o6@GhFAtsOp#i-rC0Rz&{)fh^2zdK7Tt~6@*|Hff4aY#K5uC8aBZv#elHfV zAp|!CGEVA(!t~; zzDvoE=|MPwMVTIhRy{gNg>mGC$^?G%0~!y-rbfDOKs7gx8xVB^N8;G{EFA8=RRErm z%Pn4HN}Kg39HI>?6D*qXU&NH}DCc*djN}%5v0<~mmC#~C_Fj_Fj?}q{4Leo4pZRnc zLvzLGfr7^T&}$MH44hKyHy2g^2HgjvNIe=Yokie&x}Ox_fM(l(_%Z7`nuP>JKn8S? z(X*1wU^ zAR@D__jvQyws+c2oH9{zd5i?CvXRlWwlFj@c0+vjkL2%$U^j+E%Z)1pBl7*6wTCBj zFOzF>bcpu}#}&y0JW+(e324TUgUROjxRFy@k53Lt&*ur8xOU{8%jD=`p<4ypm2vW82}{4%2z;B3 zyA6y3f!eXCMt@57-q7bcOXWpFRE9A-W;n{ZY3U@&v~hZf9J>P6jESF22z~s-s~84; zk`8sGN1gZQQ9bvEng1XwU1<#br1x)O5Fn}@=x38dcA^-KKCLlk0KoNyzy@&>c!8uk z+OO!iXgu^ZLt2rRpoKtQ?N-uE93M)TkGU>+l)=?X6EY*&U{_>E7e~*Ry&KxeQ+c}j zr^NIarC94&B_q{8&oB-ytAC*AA1|ftq0Iw){QWy;K zFI^r;rUwCdItwt=)C(vdmRtsKs1}qh_PLxc!Xj3P)#So0M1O(IRJT__8~;7;@m2Ov z)m$a-)aOGkhg&-=0)n+2)y4>++|St0Cn7Jo%EShc@@{FvJB^H0SE7Q?Sbn&%r{V62 zYVZKLQca3yL#@Hs33Ns1Ymm$=HbS4S22kiMC>c;~5da2)5oktpybK;kD=?YF z=j31EAmA+Xs-|NZ}p59b>-9) zF@^{Jp_~=%{mUtXlSkZiwx|qi%r}kx5_H|s!oux$gwqQ~2}*!q4%aM(z(}FlNFux_ zG!~H?(+cR!Akyj~G*Xy$50e=yP6|xV=x6joU#Ez%F+xRx%u#}Il)fXb!NoG+9lk^O zaNu+I%wK6WKe8oMBz&{K$Y+Ih8YQ>iInmGmEb&0_7*q8bW3);1ZkQKrvi!_)O@ntC z*Kk2o7q+vL*XCo-G8>(~$-d3RPX>TiJ)s}7%)n3ihjd2#;t@Er$n4)xQFcWz^5_0? zk@cq62n{+8kO{*Mq-*tvq@#o~6GYLLG<`O!W0)c|3G$ta<$vblJ`c!ZSUCBk&2G4 z@+baYHz%tSCN~k5H3~YP7Z*)0kRx5-f0|&{U`7tTqf0h-EuN#oj4=eVAxWwm&OM+Z ziVYNKGE+ZhVhR$WJS-$a5d|<5G@_jH1OgM(T7VHm5mJfMy#O6Ez$zmLoxCqvhj|Vx zrnaVwbg|7!mBv~7hg{cu7`SqCOxa)4>PpkH;p9nI-KLjGZDKllZiz=KsEq9E!2@__ zPu1QZOPL?+nS#{d4n`UAJxK8+t0x)jB`AvF)2*{kJIzfe9K()NSP;DI5CL6dhu>)U z!i`XjdBo^XzBEB=K3j&G8)+-?{+y;iy;#-VxcnNff0O@rY*%Q1XM@g2L}Gg=QaO(e z#$)!dy=Y`s5saEWBr-Ad&I{uriSODv0m15D3dm}jLQlTQl!6slkvI0%5m;N=G4!ME#63kMH8PEl zTt+*ZWofIW#Kx8jUI_7*^+{=YC;Pk2Q!)P1ala4B@1?D-%pEta=N3vm$Ktx5KXiP4 z3H81)f?Df8He1=aRTMI1pwrdA*Xld(WJYnXHHuF7VfYnXEsF@y|d z->q|$DFmJ(1D&7{pfeOK)Jur~j8C@t3IGZ8b0|*rgY1~Uyi44~`(aw7vtI8mZ0?g! zHjOP$;?7nJ#ryP%t9IRdm?As2H&}Wk{?^`pMMH<|^-j$pb7q;x7;C$i%;w+jaeOhx zyxKCl52{6vfg3qOsx>ivAZIgCeUAwZltpMrBKYa*2!a=PpzVn!0M8DfDSVIvd4XUFR3Pi zBUov??{ifrWgstoILmU4p8DYvrpK z-Za9Oe(zSn>musie_q@8mHBho47u+VoL>_1wGVzd|7*1B%d@?(+n3^Ey`ha4N2SD$ z%x(>Y2lmP4Mug{-oO<>uCdgw^kq@WT#3`m>v2vC&MB0=tIh^uJEL4Xv#gd31! z0TeW1QOUSyhcFh?9w7x{`pbmN{l{73 zY=miV(_ zlq?_?5T_8a-W9C~k_5)JzL5BTJU@-^if%QBn zT&^a?AA?!k(qQ!B*Qw>O1JwyE)+pM^rXi$|KBRPf;0rn1ppQ?iJ~ZUD*zhGLe)1u7 z8mNuhR2&bJV+F$FPU6u|N4UK#X%B_=H2q8j57@uFaS49(L7@D01AT13*SzZV5N6A& zqN(28A+5x1{t-`7l~e~l@~v~JS6$NEVY0Ir_M>j80M$jnYV;J1Wbn~4_*AK-z>SHX z949v6n^>b;l`LJcb!>!lg|o3BPB8g33Mx@z+0UPHfJHq(_Tp`hqm?BxQ*QA4xqzR2 z@UOwcm7{-WcdvdPkucwJj^MI0OFQ2Cbam@QTW;v5*bnMXTicag(~lh{TosZW4y#P5 zI}95*0ICH=S^<^@i-oFBgLLzrfjHv+eUQ|v!(|$Y-ogqNm4yY#r5djHx(@WecvSn~ z@9$H;Dpu{@`+raP(!F;5S3}=3qx&u2Tk2PSe#~CR9vQefn_k7ZQs@kbbAnDPK%IU{9o;ydpMNo8^@m+(-?3D?;XBF{ zwZ_!KD=*YMD1DF+akMkD=oZ1q(fz!!Y1F|h0S}N@elaHy1+7pgh){*{$u`Ok|&Xc#kVD#1* z(AoflehjgL!UcWK-p805e3Y#; zugfdnq^?h%ZZYT^IhvM4K7$-Sn61UW=O5rwrR}zpE-Ui9Bq#AJt4#2$i#iU-;G9zKNrPZQo8* z$~!OItG}qnh*X~0UY#HiR6kiVwV`t5p(odQI|GvL@{<ZG#S^==i;{vrM5;d!w#601zS2Z+Ld1D)nN+ zvZ6B0XXc(QFB8sNP-s3BdHbID&xs_z`ory6h6!A(kIB}3I?7tiQiWr?c)_exo!r=< z%2p-3TQ^<1awBf_d7r!8A@vt&E{QAm@xzzr(p4=}(Z6g8y`;by0wMP07Ka}4*}CSI zKVaUc9Y?(w>CrGa_l4v3hvPUWuiqB0!yK|#=~1nv5ljgC3zb>c(^HC%-=dcBDZ=a# z?jU)(`R;RrvPg!ZgdZM2PbgWX94Ar2i^Bv5`3Cr)#r-M~e7jn?!ls|rxu~AbiCF01 zxWFR~e>K##LqGU_MQ_p1?xcpn3l$FuhdwD=zBI>dl(9ASd9A^F%#V#+lx==&$x5Ru zD@rZb)OY-zKXw0+LfrHf4_0Z5aj~CurAJ)uwPW{};wF1N%>91)rlaa%d{$Wp=Y~M> zocV&oV{e_&6{u%?k4ckyab&_wCb1zrV>087CB!V~XgD{qHsGPnq-b|SeIuE(nsFyH zgxi+!nZ+6to^|3)Y|P$we&OzQ``xCEdQ#~mb>pGH+Ty~55GSQx6V6d~mY;vO`Kq%H z7T-27L$^nJdmE*YYg2Sng1f6mXu6hcTvGqG+Qp%JLx1o|Wiea`K>R#VD^y zuz8q;zh=QOjBN9Ajr(koksP|Zrrw^sBR4r%|HNqgbyxbi=J$Iiy8?WMz4C2(Pl+!^ z1gjM9*%@SRS%ky4pfi~|C^lpDYfY*mVGsX~g{?lkeHlEk8B5S28V^3LeExaV(4$-_ zKXNT@Rw4;@e%gd!%0fWb`_(qXX5iA6&3Gv;X5Ebv$Wh=&IB=?eB&=$4J_gN*vxR z$M5uuw6Hgo>6T9PP8OGQIoWZ^otxj8tarbz{a(qDbfZ7NbZ1}viMsguHh7mB=)7EW zAn_n}AVh5u{T?eUCo7a`%?Rd(*o9zm*y9y=uLis)6nHD#ox`II~`HT}aguO75|1 zK08`9+#_8y*XQ?7{o=N5#iCJN_OHU&Snk;}=Sq#l$*z|WbZ*Dy%(WDauj@>*4;Y)3 z9Mv$ibWzJwD^T?OnzV|~S(x?J_pQ}er~_SpI=G4q#dU=q8yki31CaQ^X-vp-<||My3w{D3xeP0|Pf5E)K_#Z-VMWBcI)G2oG;4PO%= zdYp!@8d@k!XvXngSVK5^PC zP;3_(0~J7{X5(Ux;T%{Wq=z8m#|FUs03bi~9OlOWbgqH0pyafSrx znNX9dxLj~JX2vP;-C8J5AL(hIGx}uwe2KS${fC0#5he8t+*~!w5Ak2%KetUFPv;l6 z*&Q>!xX~&cp^DY zamB88-$BByLh-pq?l?3Nt1v?~-4w_@1$84?_MFisp)G zr%3z<(M$0v(4%WoaQszZ2D@7!R$P8*h;8^)Yr+7cp+`0nAEZvk&vGoh{~~0|1wEGV zgThJqS;~O@2ib$e_Kvr`b>x-RWu>99Wg?sB3}ow_YwBeD7%!OR2SdFv>p#9kN&TWO zLQDJyhvb;~ac=|tYdg+X_t~`GEWFx-WUX^in~Wcw1#tgEAjl0$`)8Kae+bAwe;%Ax zS=sT2&6SM0R{_qZt<<@=Mo5lH#?MlWgdgxfe*PonM-?Exe%<>cjMV%sJ<6B4@@UCC zJs%x489!v{`Hvhm4X$4R98iJl7ZoU>dg1!@(KUU@gq^|z&9|04TpBGj+d1Dfe@N#3 znP+AEkfi%BIbPT-Kat9_{NRz_Kes(fvl}~=clGh6qTI_B|4dHizvb^|K*o=jlpi$j z>sfx{&@eynFT9Y?PiYNppy~*u7s4LAoEOXZ`+?6t`Hy7auli-hKmmZ3^v`4fB4K{u z_kRc|ZTQb75IvIF^*%pt%!^ITI*n+Zb5)#-A8m9E1MYiJJgh(xslm(ConfigurationExtensions.Configuration).regis 'audioCues.chatResponsePending': { 'description': localize('audioCues.chatResponsePending', "Plays a sound on loop while the response is pending."), ...audioCueFeatureBase + }, + 'audioCues.chatResponseReceived': { + 'description': localize('audioCues.chatResponseReceived', "Plays a sound on loop while the response has been received."), + ...audioCueFeatureBase } } }); diff --git a/src/vs/workbench/contrib/chat/browser/chatWidget.ts b/src/vs/workbench/contrib/chat/browser/chatWidget.ts index f13005eb58f..494739a0e60 100644 --- a/src/vs/workbench/contrib/chat/browser/chatWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/chatWidget.ts @@ -390,18 +390,20 @@ export class ChatWidget extends Disposable implements IChatWidget { this.instantiationService.invokeFunction(clearChatSession, this); return; } - await this.audioCueService.playAudioCue(AudioCue.chatRequestSent); + await this.audioCueService.playAudioCue(AudioCue.chatRequestSent, true); const input = query ?? editorValue; - const result = await this.chatService.sendRequest(this.viewModel.sessionId, input); const cue = this.audioCueService.playAudioCueLoop(AudioCue.chatResponsePending); + const result = await this.chatService.sendRequest(this.viewModel.sessionId, input); + const audioCueService = this.audioCueService; if (result) { this.inputPart.acceptInput(query); - result.responseCompletePromise.then(() => { + result.responseCompletePromise.then(async () => { + cue.dispose(); + audioCueService.playAudioCue(AudioCue.chatResponseReceived, true); const responses = this.viewModel?.getItems().filter(isResponseVM); const lastResponse = responses?.[responses.length - 1]; if (lastResponse) { const errorDetails = lastResponse.errorDetails ? ` ${lastResponse.errorDetails.message}` : ''; - cue.dispose(); alert(lastResponse.response.value + errorDetails); } }); From 4908243d91a70bd409fa612370fa6e586108c4fb Mon Sep 17 00:00:00 2001 From: meganrogge Date: Wed, 14 Jun 2023 15:59:42 -0500 Subject: [PATCH 05/69] use random index --- .../standalone/browser/standaloneServices.ts | 4 +- .../audioCues/browser/audioCueService.ts | 57 ++++++++++++++++-- ...sePending.mp3 => chatResponsePending1.mp3} | Bin .../browser/media/chatResponsePending2.mp3 | Bin 0 -> 36352 bytes .../browser/media/chatResponsePending3.mp3 | Bin 0 -> 36352 bytes .../browser/media/chatResponsePending4.mp3 | Bin 0 -> 36352 bytes .../browser/media/chatResponsePending5.mp3 | Bin 0 -> 36352 bytes .../browser/media/chatResponseReceived.mp3 | Bin 36352 -> 0 bytes .../contrib/chat/browser/chatWidget.ts | 11 ++-- 9 files changed, 59 insertions(+), 13 deletions(-) rename src/vs/platform/audioCues/browser/media/{chatResponsePending.mp3 => chatResponsePending1.mp3} (100%) create mode 100644 src/vs/platform/audioCues/browser/media/chatResponsePending2.mp3 create mode 100644 src/vs/platform/audioCues/browser/media/chatResponsePending3.mp3 create mode 100644 src/vs/platform/audioCues/browser/media/chatResponsePending4.mp3 create mode 100644 src/vs/platform/audioCues/browser/media/chatResponsePending5.mp3 delete mode 100644 src/vs/platform/audioCues/browser/media/chatResponseReceived.mp3 diff --git a/src/vs/editor/standalone/browser/standaloneServices.ts b/src/vs/editor/standalone/browser/standaloneServices.ts index 04be9018f8b..62bde1b0551 100644 --- a/src/vs/editor/standalone/browser/standaloneServices.ts +++ b/src/vs/editor/standalone/browser/standaloneServices.ts @@ -87,7 +87,7 @@ import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; import { IStorageService, InMemoryStorageService } from 'vs/platform/storage/common/storage'; import { DefaultConfiguration } from 'vs/platform/configuration/common/configurations'; import { WorkspaceEdit } from 'vs/editor/common/languages'; -import { AudioCue, IAudioCueService, Sound } from 'vs/platform/audioCues/browser/audioCueService'; +import { AudioCue, AudioCueGroupId, IAudioCueService, Sound } from 'vs/platform/audioCues/browser/audioCueService'; import { LogService } from 'vs/platform/log/common/logService'; import { getEditorFeatures } from 'vs/editor/common/editorFeatures'; import { onUnexpectedError } from 'vs/base/common/errors'; @@ -1058,6 +1058,8 @@ class StandaloneAudioService implements IAudioCueService { playAudioCueLoop(cue: AudioCue): IDisposable { return toDisposable(() => { }); } + playRandomAudioCue(groupId: AudioCueGroupId, allowManyInParallel?: boolean | undefined, loop?: boolean): void | IDisposable { + } } export interface IEditorOverrideServices { diff --git a/src/vs/platform/audioCues/browser/audioCueService.ts b/src/vs/platform/audioCues/browser/audioCueService.ts index fd7c40f9439..ac3e9a0d237 100644 --- a/src/vs/platform/audioCues/browser/audioCueService.ts +++ b/src/vs/platform/audioCues/browser/audioCueService.ts @@ -12,6 +12,10 @@ import { Event } from 'vs/base/common/event'; import { localize } from 'vs/nls'; import { observableFromEvent, derived } from 'vs/base/common/observable'; +export const enum AudioCueGroupId { + chatResponsePending = 'chatResponsePending' +} + export const IAudioCueService = createDecorator('audioCue'); export interface IAudioCueService { @@ -23,6 +27,7 @@ export interface IAudioCueService { playSound(cue: Sound, allowManyInParallel?: boolean): Promise; playAudioCueLoop(cue: AudioCue): IDisposable; + playRandomAudioCue(groupId: AudioCueGroupId, loop?: boolean): IDisposable | void; } export class AudioCueService extends Disposable implements IAudioCueService { @@ -52,6 +57,16 @@ export class AudioCueService extends Disposable implements IAudioCueService { await Promise.all(Array.from(sounds).map(sound => this.playSound(sound, true))); } + public playRandomAudioCue(groupId: AudioCueGroupId, loop?: boolean): void | IDisposable { + const cues = AudioCue.allAudioCues.filter(cue => cue.groupId === groupId); + const index = Math.floor(Math.random() * cues.length); + if (loop) { + return this.playAudioCueLoop(cues[index]); + } else { + this.playAudioCue(cues[index]); + } + } + private getVolumeInPercent(): number { const volume = this.configurationService.getValue('audioCues.volume'); if (typeof volume !== 'number') { @@ -209,7 +224,11 @@ export class Sound { public static readonly diffLineDeleted = Sound.register({ fileName: 'diffLineDeleted.mp3' }); public static readonly diffLineModified = Sound.register({ fileName: 'diffLineModified.mp3' }); public static readonly chatRequestSent = Sound.register({ fileName: 'chatRequestSent.mp3' }); - public static readonly chatResponsePending = Sound.register({ fileName: 'chatResponsePending.mp3' }); + public static readonly chatResponsePending1 = Sound.register({ fileName: 'chatResponsePending1.mp3' }); + public static readonly chatResponsePending2 = Sound.register({ fileName: 'chatResponsePending2.mp3' }); + public static readonly chatResponsePending3 = Sound.register({ fileName: 'chatResponsePending3.mp3' }); + public static readonly chatResponsePending4 = Sound.register({ fileName: 'chatResponsePending4.mp3' }); + public static readonly chatResponsePending5 = Sound.register({ fileName: 'chatResponsePending5.mp3' }); public static readonly chatResponseReceived = Sound.register({ fileName: 'chatResponseReceived.mp3' }); private constructor(public readonly fileName: string) { } @@ -217,13 +236,13 @@ export class Sound { export class AudioCue { private static _audioCues = new Set(); - private static register(options: { name: string; sound: Sound; settingsKey: string; + groupId?: AudioCueGroupId; }): AudioCue { - const audioCue = new AudioCue(options.sound, options.name, options.settingsKey); + const audioCue = new AudioCue(options.sound, options.name, options.settingsKey, options.groupId); AudioCue._audioCues.add(audioCue); return audioCue; } @@ -336,10 +355,35 @@ export class AudioCue { settingsKey: 'audioCues.chatRequestSent' }); - public static readonly chatResponsePending = AudioCue.register({ + public static readonly chatResponsePending = { name: localize('audioCues.chatResponsePending', 'Chat Response Pending'), - sound: Sound.chatResponsePending, - settingsKey: 'audioCues.chatResponsePending' + settingsKey: 'audioCues.chatResponsePending', + groupId: AudioCueGroupId.chatResponsePending + }; + + public static readonly chatResponsePending1 = AudioCue.register({ + sound: Sound.chatResponsePending1, + ...this.chatResponsePending + }); + + public static readonly chatResponsePending2 = AudioCue.register({ + sound: Sound.chatResponsePending2, + ...this.chatResponsePending + }); + + public static readonly chatResponsePending3 = AudioCue.register({ + sound: Sound.chatResponsePending3, + ...this.chatResponsePending + }); + + public static readonly chatResponsePending4 = AudioCue.register({ + sound: Sound.chatResponsePending4, + ...this.chatResponsePending + }); + + public static readonly chatResponsePending5 = AudioCue.register({ + sound: Sound.chatResponsePending5, + ...this.chatResponsePending }); public static readonly chatResponseReceived = AudioCue.register({ @@ -352,5 +396,6 @@ export class AudioCue { public readonly sound: Sound, public readonly name: string, public readonly settingsKey: string, + public readonly groupId?: string ) { } } diff --git a/src/vs/platform/audioCues/browser/media/chatResponsePending.mp3 b/src/vs/platform/audioCues/browser/media/chatResponsePending1.mp3 similarity index 100% rename from src/vs/platform/audioCues/browser/media/chatResponsePending.mp3 rename to src/vs/platform/audioCues/browser/media/chatResponsePending1.mp3 diff --git a/src/vs/platform/audioCues/browser/media/chatResponsePending2.mp3 b/src/vs/platform/audioCues/browser/media/chatResponsePending2.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..c082927ecc14393110f66749196465a664f0a4ae GIT binary patch literal 36352 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 LNK5lGquu`jHvE@2 literal 0 HcmV?d00001 diff --git a/src/vs/platform/audioCues/browser/media/chatResponsePending3.mp3 b/src/vs/platform/audioCues/browser/media/chatResponsePending3.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..99b75cda978bbc0e6b663c8462898460439fe2ce GIT binary patch literal 36352 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 literal 0 HcmV?d00001 diff --git a/src/vs/platform/audioCues/browser/media/chatResponsePending4.mp3 b/src/vs/platform/audioCues/browser/media/chatResponsePending4.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..f1ab44a26169fc2aba4a644c0c2bf0c65e7024ba GIT binary patch literal 36352 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 DUj~3< literal 0 HcmV?d00001 diff --git a/src/vs/platform/audioCues/browser/media/chatResponsePending5.mp3 b/src/vs/platform/audioCues/browser/media/chatResponsePending5.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..134edeb93af312ce98c260d0c63163d1492a96ff GIT binary patch literal 36352 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 literal 0 HcmV?d00001 diff --git a/src/vs/platform/audioCues/browser/media/chatResponseReceived.mp3 b/src/vs/platform/audioCues/browser/media/chatResponseReceived.mp3 deleted file mode 100644 index c3ee2a511cecec3ae122e9744b21cb95ec7de0b5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36352 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 { - cue.dispose(); - audioCueService.playAudioCue(AudioCue.chatResponseReceived, true); + cue?.dispose(); + this.audioCueService.playAudioCue(AudioCue.chatResponseReceived, true); const responses = this.viewModel?.getItems().filter(isResponseVM); const lastResponse = responses?.[responses.length - 1]; if (lastResponse) { From aa24684dec3ea0190581c88c64f3faee99ced568 Mon Sep 17 00:00:00 2001 From: yshaojun Date: Thu, 15 Jun 2023 20:31:39 +0800 Subject: [PATCH 06/69] fix: inline completion not displaying(#184108) --- .../inlineCompletions/browser/singleTextEdit.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/vs/editor/contrib/inlineCompletions/browser/singleTextEdit.ts b/src/vs/editor/contrib/inlineCompletions/browser/singleTextEdit.ts index dd8ae92d96d..8d74bd7bdcd 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/singleTextEdit.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/singleTextEdit.ts @@ -70,10 +70,13 @@ export class SingleTextEdit { const suggestionAddedIndentationLength = getLeadingWhitespace(edit.text).length; const replacedIndentation = sourceLine.substring(edit.range.startColumn - 1, sourceIndentationLength); - const rangeThatDoesNotReplaceIndentation = Range.fromPositions( - edit.range.getStartPosition().delta(0, replacedIndentation.length), - edit.range.getEndPosition() - ); + + const [startPosition, endPosition] = [edit.range.getStartPosition(), edit.range.getEndPosition()]; + const newStartPosition = + startPosition.column + replacedIndentation.length <= endPosition.column + ? startPosition.delta(0, replacedIndentation.length) + : endPosition; + const rangeThatDoesNotReplaceIndentation = Range.fromPositions(newStartPosition, endPosition); const suggestionWithoutIndentationChange = edit.text.startsWith(replacedIndentation) From 07465d7e92d0c9fdc3c991d574c819238feb2f28 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Thu, 15 Jun 2023 16:56:43 +0200 Subject: [PATCH 07/69] initial commit --- .../contrib/zoneWidget/browser/zoneWidget.ts | 3 ++- .../browser/inlineChatController.ts | 19 +++++++++++++++++++ .../inlineChat/browser/inlineChatWidget.ts | 10 ++++------ 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts b/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts index a003de17958..54c7910f648 100644 --- a/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts +++ b/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts @@ -31,6 +31,7 @@ export interface IOptions { allowUnlimitedHeight?: boolean; ordinal?: number; showInHiddenAreas?: boolean; + allowBehindVerticalScrollbar?: boolean; } export interface IStyles { @@ -271,7 +272,7 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { } protected _getWidth(info: EditorLayoutInfo): number { - return info.width - info.minimap.minimapWidth - info.verticalScrollbarWidth; + return info.width - info.minimap.minimapWidth - (this.options.allowBehindVerticalScrollbar ? 0 : info.verticalScrollbarWidth); } private _getLeft(info: EditorLayoutInfo): number { diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts index 4e7c0eeb191..eb7ca2e60ad 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts @@ -38,6 +38,7 @@ import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/se import { CellUri } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { Lazy } from 'vs/base/common/lazy'; +import { Selection } from 'vs/editor/common/core/selection'; export const enum State { CREATE_SESSION = 'CREATE_SESSION', @@ -100,6 +101,7 @@ export class InlineChatController implements IEditorContribution { private _activeSession?: Session; private _strategy?: EditModeStrategy; private _ignoreModelContentChanged = false; + private _selection: Selection | undefined; constructor( private readonly _editor: ICodeEditor, @@ -199,16 +201,32 @@ export class InlineChatController implements IEditorContribution { assertType(this._strategy); assertType(this._editor.hasModel()); + const info = this._editor.getLayoutInfo(); + const marginWithoutIndentation = info.glyphMarginWidth + info.decorationsWidth + info.lineNumbersWidth; + this._zone.value.container!.style.marginLeft = `${marginWithoutIndentation}px`; + let widgetPosition: Position | undefined; if (initialRender) { + this._selection = this._editor.getSelection(); widgetPosition = this._editor.getSelection().getEndPosition(); this._zone.value.setMargins(widgetPosition); + console.log('widgetPosition : ', widgetPosition); + console.log('selection : ', this._editor.getSelection()); } else { widgetPosition = this._strategy.getWidgetPosition() ?? this._zone.value.position ?? this._activeSession.wholeRange.value.getEndPosition(); const needsMargin = this._strategy.needsMargin(); if (!needsMargin) { this._zone.value.setMargins(widgetPosition, 0); } + // TODO: clean up + const widgetLineNumber = widgetPosition.lineNumber; + if (this._selection && widgetLineNumber >= this._selection.startLineNumber && widgetLineNumber < this._selection.endLineNumber) { + console.log('this._zone.value.container : ', this._zone.value.container); + this._zone.value.container!.style.backgroundColor = `var(--vscode-inlineChat-regionHighlight)`; + } + console.log('widgetPosition : ', widgetPosition); + console.log('selection : ', this._editor.getSelection()); + console.log('this._activeSession.wholeRange : ', this._activeSession.wholeRange); } this._zone.value.show(widgetPosition); } @@ -283,6 +301,7 @@ export class InlineChatController implements IEditorContribution { range: this._activeSession.wholeRange.value, options: InlineChatController._decoBlock }]); + console.log('wholeRangeDecoration', wholeRangeDecoration); this._sessionStore.add(toDisposable(() => wholeRangeDecoration.clear())); this._zone.value.widget.updateSlashCommands(this._activeSession.session.slashCommands ?? []); diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts index d8c37d0b67f..a63bd03f6ef 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts @@ -701,7 +701,7 @@ export class InlineChatZoneWidget extends ZoneWidget { @IInstantiationService private readonly _instaService: IInstantiationService, @IContextKeyService contextKeyService: IContextKeyService, ) { - super(editor, { showFrame: false, showArrow: false, isAccessible: true, className: 'inline-chat-widget', keepEditorSelection: true, showInHiddenAreas: true, ordinal: 10000 + 3 }); + super(editor, { showFrame: false, showArrow: false, isAccessible: true, className: 'inline-chat-widget', keepEditorSelection: true, showInHiddenAreas: true, ordinal: 10000 + 3, allowBehindVerticalScrollbar: true }); this._ctxVisible = CTX_INLINE_CHAT_VISIBLE.bindTo(contextKeyService); this._ctxCursorPosition = CTX_INLINE_CHAT_OUTER_CURSOR_POSITION.bindTo(contextKeyService); @@ -740,7 +740,7 @@ export class InlineChatZoneWidget extends ZoneWidget { protected override _doLayout(heightInPixel: number): void { - + console.log('inside of _doLayout'); const maxWidth = !this.widget.showsAnyPreview() ? 640 : Number.MAX_SAFE_INTEGER; const width = Math.min(maxWidth, this._availableSpaceGivenIndentation()); this._dimension = new Dimension(width, heightInPixel); @@ -801,12 +801,10 @@ export class InlineChatZoneWidget extends ZoneWidget { } this._indentationWidth = indentationWidth; const info = this.editor.getLayoutInfo(); - const marginWithoutIndentation = info.glyphMarginWidth + info.decorationsWidth + info.lineNumbersWidth; - const marginWithIndentation = marginWithoutIndentation + this._indentationWidth; const isEnoughAvailableSpaceWithIndentation = this._availableSpaceGivenIndentation() > 400; this._indentationWidth = isEnoughAvailableSpaceWithIndentation ? this._indentationWidth : 0; - const spaceLeft = isEnoughAvailableSpaceWithIndentation ? marginWithIndentation : marginWithoutIndentation; - const spaceRight = info.minimap.minimapWidth + info.verticalScrollbarWidth; + const spaceLeft = isEnoughAvailableSpaceWithIndentation ? this._indentationWidth : 0; + const spaceRight = info.minimap.minimapWidth; this.widget.domNode.style.marginLeft = `${spaceLeft}px`; this.widget.domNode.style.marginRight = `${spaceRight}px`; } From 363ab72a2bd9d46bd114c841334cac51cdcaf22b Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Thu, 15 Jun 2023 17:35:52 +0200 Subject: [PATCH 08/69] cleaning the code --- .../contrib/inlineChat/browser/inlineChat.css | 4 ++ .../browser/inlineChatController.ts | 25 ++--------- .../inlineChat/browser/inlineChatSession.ts | 5 ++- .../inlineChat/browser/inlineChatWidget.ts | 42 ++++++++++++------- 4 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChat.css b/src/vs/workbench/contrib/inlineChat/browser/inlineChat.css index 8b3b57cd302..162db7cf436 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChat.css +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChat.css @@ -7,6 +7,10 @@ z-index: 3; } +.monaco-editor .zone-widget-container.inside-selection { + background-color: var(--vscode-inlineChat-regionHighlight); +} + .monaco-editor .inline-chat { color: inherit; padding: 6px; diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts index eb7ca2e60ad..bf026a34fac 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts @@ -38,7 +38,6 @@ import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/se import { CellUri } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { Lazy } from 'vs/base/common/lazy'; -import { Selection } from 'vs/editor/common/core/selection'; export const enum State { CREATE_SESSION = 'CREATE_SESSION', @@ -101,7 +100,6 @@ export class InlineChatController implements IEditorContribution { private _activeSession?: Session; private _strategy?: EditModeStrategy; private _ignoreModelContentChanged = false; - private _selection: Selection | undefined; constructor( private readonly _editor: ICodeEditor, @@ -201,34 +199,20 @@ export class InlineChatController implements IEditorContribution { assertType(this._strategy); assertType(this._editor.hasModel()); - const info = this._editor.getLayoutInfo(); - const marginWithoutIndentation = info.glyphMarginWidth + info.decorationsWidth + info.lineNumbersWidth; - this._zone.value.container!.style.marginLeft = `${marginWithoutIndentation}px`; - let widgetPosition: Position | undefined; if (initialRender) { - this._selection = this._editor.getSelection(); widgetPosition = this._editor.getSelection().getEndPosition(); - this._zone.value.setMargins(widgetPosition); - console.log('widgetPosition : ', widgetPosition); - console.log('selection : ', this._editor.getSelection()); + this._zone.value.setContainerMargins(); + this._zone.value.setWidgetMargins(widgetPosition); } else { widgetPosition = this._strategy.getWidgetPosition() ?? this._zone.value.position ?? this._activeSession.wholeRange.value.getEndPosition(); const needsMargin = this._strategy.needsMargin(); if (!needsMargin) { - this._zone.value.setMargins(widgetPosition, 0); + this._zone.value.setWidgetMargins(widgetPosition, 0); } - // TODO: clean up - const widgetLineNumber = widgetPosition.lineNumber; - if (this._selection && widgetLineNumber >= this._selection.startLineNumber && widgetLineNumber < this._selection.endLineNumber) { - console.log('this._zone.value.container : ', this._zone.value.container); - this._zone.value.container!.style.backgroundColor = `var(--vscode-inlineChat-regionHighlight)`; - } - console.log('widgetPosition : ', widgetPosition); - console.log('selection : ', this._editor.getSelection()); - console.log('this._activeSession.wholeRange : ', this._activeSession.wholeRange); } this._zone.value.show(widgetPosition); + this._zone.value.updateBackgroundColor(widgetPosition, this._activeSession.selection); } protected async _nextState(state: State, options: InlineChatRunOptions | undefined): Promise { @@ -301,7 +285,6 @@ export class InlineChatController implements IEditorContribution { range: this._activeSession.wholeRange.value, options: InlineChatController._decoBlock }]); - console.log('wholeRangeDecoration', wholeRangeDecoration); this._sessionStore.add(toDisposable(() => wholeRangeDecoration.clear())); this._zone.value.widget.updateSlashCommands(this._activeSession.session.slashCommands ?? []); diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts index 141b5911cff..c8b920af65a 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts @@ -126,7 +126,8 @@ export class Session { readonly textModelN: ITextModel, readonly provider: IInlineChatSessionProvider, readonly session: IInlineChatSession, - readonly wholeRange: SessionWholeRange + readonly wholeRange: SessionWholeRange, + readonly selection: IRange ) { this.textModelNAltVersion = textModelN.getAlternativeVersionId(); this._teldata = { @@ -443,7 +444,7 @@ export class InlineChatSessionService implements IInlineChatSessionService { const wholeRangeMgr = new SessionWholeRange(textModel, wholeRange); store.add(wholeRangeMgr); - const session = new Session(options.editMode, editor, textModel0, textModel, provider, raw, wholeRangeMgr); + const session = new Session(options.editMode, editor, textModel0, textModel, provider, raw, wholeRangeMgr, editor.getSelection()); // store: key -> session const key = this._key(editor, textModel.uri); diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts index a63bd03f6ef..dbf1e490b28 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts @@ -7,7 +7,7 @@ import 'vs/css!./inlineChat'; import { DisposableStore, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { IActiveCodeEditor, ICodeEditor, IDiffEditorConstructionOptions } from 'vs/editor/browser/editorBrowser'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; -import { Range } from 'vs/editor/common/core/range'; +import { IRange, Range } from 'vs/editor/common/core/range'; import { localize } from 'vs/nls'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -47,8 +47,8 @@ import { AccessibilityVerbositySettingId } from 'vs/workbench/contrib/accessibil import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels'; import { ExpansionState } from 'vs/workbench/contrib/inlineChat/browser/inlineChatSession'; import { IdleValue } from 'vs/base/common/async'; -import * as aria from 'vs/base/browser/ui/aria/aria'; import { IMenuWorkbenchButtonBarOptions, MenuWorkbenchButtonBar } from 'vs/platform/actions/browser/buttonbar'; +import * as aria from 'vs/base/browser/ui/aria/aria'; const defaultAriaLabel = localize('aria-label', "Inline Chat Input"); @@ -740,17 +740,17 @@ export class InlineChatZoneWidget extends ZoneWidget { protected override _doLayout(heightInPixel: number): void { - console.log('inside of _doLayout'); + const maxWidth = !this.widget.showsAnyPreview() ? 640 : Number.MAX_SAFE_INTEGER; - const width = Math.min(maxWidth, this._availableSpaceGivenIndentation()); + const width = Math.min(maxWidth, this._availableSpaceGivenIndentation(this._indentationWidth)); this._dimension = new Dimension(width, heightInPixel); this.widget.domNode.style.width = `${width}px`; this.widget.layout(this._dimension); } - private _availableSpaceGivenIndentation(): number { + private _availableSpaceGivenIndentation(indentationWidth: number | undefined): number { const info = this.editor.getLayoutInfo(); - return info.contentWidth - (info.glyphMarginWidth + info.decorationsWidth + (this._indentationWidth ?? 0)); + return info.contentWidth - (info.glyphMarginWidth + info.decorationsWidth + (indentationWidth ?? 0)); } private _computeHeightInLines(): number { @@ -771,6 +771,14 @@ export class InlineChatZoneWidget extends ZoneWidget { this._ctxVisible.set(true); } + public updateBackgroundColor(position: Position, selection: IRange) { + if (!this.container) { + return; + } + const widgetLineNumber = position.lineNumber; + this.container.classList.toggle('inside-selection', widgetLineNumber >= selection.startLineNumber && widgetLineNumber < selection.endLineNumber); + } + private _calculateIndentationWidth(position: Position): number { const viewModel = this.editor._getViewModel(); if (!viewModel) { @@ -792,21 +800,25 @@ export class InlineChatZoneWidget extends ZoneWidget { return this.editor.getOffsetForColumn(indentationLineNumber ?? positionLine, indentationLevel ?? viewModel.getLineFirstNonWhitespaceColumn(positionLine)); } - setMargins(position: Position, indentationWidth?: number): void { + setContainerMargins(): void { + if (!this.container) { + return; + } + const info = this.editor.getLayoutInfo(); + const marginWithoutIndentation = info.glyphMarginWidth + info.decorationsWidth + info.lineNumbersWidth; + this.container.style.marginLeft = `${marginWithoutIndentation}px`; + } + + setWidgetMargins(position: Position, indentationWidth?: number): void { if (indentationWidth === undefined) { indentationWidth = this._calculateIndentationWidth(position); } if (this._indentationWidth === indentationWidth) { return; } - this._indentationWidth = indentationWidth; - const info = this.editor.getLayoutInfo(); - const isEnoughAvailableSpaceWithIndentation = this._availableSpaceGivenIndentation() > 400; - this._indentationWidth = isEnoughAvailableSpaceWithIndentation ? this._indentationWidth : 0; - const spaceLeft = isEnoughAvailableSpaceWithIndentation ? this._indentationWidth : 0; - const spaceRight = info.minimap.minimapWidth; - this.widget.domNode.style.marginLeft = `${spaceLeft}px`; - this.widget.domNode.style.marginRight = `${spaceRight}px`; + this._indentationWidth = this._availableSpaceGivenIndentation(indentationWidth) > 400 ? indentationWidth : 0; + this.widget.domNode.style.marginLeft = `${this._indentationWidth}px`; + this.widget.domNode.style.marginRight = `${this.editor.getLayoutInfo().minimap.minimapWidth}px`; } override hide(): void { From 193cbfdf21d7f8cb62cdbf4ff6b56de6568a74c8 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Thu, 15 Jun 2023 18:01:22 +0200 Subject: [PATCH 09/69] retriggering the tests --- src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts index dbf1e490b28..d3f917612db 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts @@ -47,8 +47,8 @@ import { AccessibilityVerbositySettingId } from 'vs/workbench/contrib/accessibil import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels'; import { ExpansionState } from 'vs/workbench/contrib/inlineChat/browser/inlineChatSession'; import { IdleValue } from 'vs/base/common/async'; -import { IMenuWorkbenchButtonBarOptions, MenuWorkbenchButtonBar } from 'vs/platform/actions/browser/buttonbar'; import * as aria from 'vs/base/browser/ui/aria/aria'; +import { IMenuWorkbenchButtonBarOptions, MenuWorkbenchButtonBar } from 'vs/platform/actions/browser/buttonbar'; const defaultAriaLabel = localize('aria-label', "Inline Chat Input"); From e086148b0e3a5be4f7bd014d9b92be00c5eb2fcf Mon Sep 17 00:00:00 2001 From: meganrogge Date: Thu, 15 Jun 2023 11:35:20 -0500 Subject: [PATCH 10/69] fix --- .../standalone/browser/standaloneServices.ts | 2 +- .../audioCues/browser/audioCueService.ts | 70 +++++++++--------- ...sePending1.mp3 => chatResponsePending.mp3} | Bin .../browser/media/chatResponseReceived1.mp3 | Bin 0 -> 36352 bytes ...Pending2.mp3 => chatResponseReceived2.mp3} | Bin ...Pending3.mp3 => chatResponseReceived3.mp3} | Bin ...Pending4.mp3 => chatResponseReceived4.mp3} | Bin ...Pending5.mp3 => chatResponseReceived5.mp3} | Bin .../contrib/chat/browser/chatWidget.ts | 4 +- 9 files changed, 36 insertions(+), 40 deletions(-) rename src/vs/platform/audioCues/browser/media/{chatResponsePending1.mp3 => chatResponsePending.mp3} (100%) create mode 100644 src/vs/platform/audioCues/browser/media/chatResponseReceived1.mp3 rename src/vs/platform/audioCues/browser/media/{chatResponsePending2.mp3 => chatResponseReceived2.mp3} (100%) rename src/vs/platform/audioCues/browser/media/{chatResponsePending3.mp3 => chatResponseReceived3.mp3} (100%) rename src/vs/platform/audioCues/browser/media/{chatResponsePending4.mp3 => chatResponseReceived4.mp3} (100%) rename src/vs/platform/audioCues/browser/media/{chatResponsePending5.mp3 => chatResponseReceived5.mp3} (100%) diff --git a/src/vs/editor/standalone/browser/standaloneServices.ts b/src/vs/editor/standalone/browser/standaloneServices.ts index 62bde1b0551..dcf5d9a30f5 100644 --- a/src/vs/editor/standalone/browser/standaloneServices.ts +++ b/src/vs/editor/standalone/browser/standaloneServices.ts @@ -1058,7 +1058,7 @@ class StandaloneAudioService implements IAudioCueService { playAudioCueLoop(cue: AudioCue): IDisposable { return toDisposable(() => { }); } - playRandomAudioCue(groupId: AudioCueGroupId, allowManyInParallel?: boolean | undefined, loop?: boolean): void | IDisposable { + playRandomAudioCue(groupId: AudioCueGroupId, allowManyInParallel?: boolean | undefined): void | IDisposable { } } diff --git a/src/vs/platform/audioCues/browser/audioCueService.ts b/src/vs/platform/audioCues/browser/audioCueService.ts index ac3e9a0d237..4708559dd35 100644 --- a/src/vs/platform/audioCues/browser/audioCueService.ts +++ b/src/vs/platform/audioCues/browser/audioCueService.ts @@ -13,7 +13,7 @@ import { localize } from 'vs/nls'; import { observableFromEvent, derived } from 'vs/base/common/observable'; export const enum AudioCueGroupId { - chatResponsePending = 'chatResponsePending' + chatResponseReceived = 'chatResponseReceived' } export const IAudioCueService = createDecorator('audioCue'); @@ -27,7 +27,7 @@ export interface IAudioCueService { playSound(cue: Sound, allowManyInParallel?: boolean): Promise; playAudioCueLoop(cue: AudioCue): IDisposable; - playRandomAudioCue(groupId: AudioCueGroupId, loop?: boolean): IDisposable | void; + playRandomAudioCue(groupId: AudioCueGroupId, allowManyInParallel?: boolean): IDisposable | void; } export class AudioCueService extends Disposable implements IAudioCueService { @@ -57,14 +57,10 @@ export class AudioCueService extends Disposable implements IAudioCueService { await Promise.all(Array.from(sounds).map(sound => this.playSound(sound, true))); } - public playRandomAudioCue(groupId: AudioCueGroupId, loop?: boolean): void | IDisposable { + public playRandomAudioCue(groupId: AudioCueGroupId, allowManyInParallel?: boolean): void | IDisposable { const cues = AudioCue.allAudioCues.filter(cue => cue.groupId === groupId); const index = Math.floor(Math.random() * cues.length); - if (loop) { - return this.playAudioCueLoop(cues[index]); - } else { - this.playAudioCue(cues[index]); - } + this.playAudioCue(cues[index], allowManyInParallel); } private getVolumeInPercent(): number { @@ -224,12 +220,12 @@ export class Sound { public static readonly diffLineDeleted = Sound.register({ fileName: 'diffLineDeleted.mp3' }); public static readonly diffLineModified = Sound.register({ fileName: 'diffLineModified.mp3' }); public static readonly chatRequestSent = Sound.register({ fileName: 'chatRequestSent.mp3' }); - public static readonly chatResponsePending1 = Sound.register({ fileName: 'chatResponsePending1.mp3' }); - public static readonly chatResponsePending2 = Sound.register({ fileName: 'chatResponsePending2.mp3' }); - public static readonly chatResponsePending3 = Sound.register({ fileName: 'chatResponsePending3.mp3' }); - public static readonly chatResponsePending4 = Sound.register({ fileName: 'chatResponsePending4.mp3' }); - public static readonly chatResponsePending5 = Sound.register({ fileName: 'chatResponsePending5.mp3' }); - public static readonly chatResponseReceived = Sound.register({ fileName: 'chatResponseReceived.mp3' }); + public static readonly chatResponsePending = Sound.register({ fileName: 'chatResponsePending.mp3' }); + public static readonly chatResponseReceived1 = Sound.register({ fileName: 'chatResponseReceived1.mp3' }); + public static readonly chatResponseReceived2 = Sound.register({ fileName: 'chatResponseReceived2.mp3' }); + public static readonly chatResponseReceived3 = Sound.register({ fileName: 'chatResponseReceived3.mp3' }); + public static readonly chatResponseReceived4 = Sound.register({ fileName: 'chatResponseReceived4.mp3' }); + public static readonly chatResponseReceived5 = Sound.register({ fileName: 'chatResponseReceived5.mp3' }); private constructor(public readonly fileName: string) { } } @@ -355,41 +351,41 @@ export class AudioCue { settingsKey: 'audioCues.chatRequestSent' }); - public static readonly chatResponsePending = { - name: localize('audioCues.chatResponsePending', 'Chat Response Pending'), - settingsKey: 'audioCues.chatResponsePending', - groupId: AudioCueGroupId.chatResponsePending + public static readonly chatResponseReceived = { + name: localize('audioCues.chatResponseReceived', 'Chat Response Received'), + settingsKey: 'audioCues.chatResponseReceived', + groupId: AudioCueGroupId.chatResponseReceived }; - public static readonly chatResponsePending1 = AudioCue.register({ - sound: Sound.chatResponsePending1, - ...this.chatResponsePending + public static readonly chatResponseReceived1 = AudioCue.register({ + sound: Sound.chatResponseReceived1, + ...this.chatResponseReceived }); - public static readonly chatResponsePending2 = AudioCue.register({ - sound: Sound.chatResponsePending2, - ...this.chatResponsePending + public static readonly chatResponseReceived2 = AudioCue.register({ + sound: Sound.chatResponseReceived2, + ...this.chatResponseReceived }); - public static readonly chatResponsePending3 = AudioCue.register({ - sound: Sound.chatResponsePending3, - ...this.chatResponsePending + public static readonly chatResponseReceived3 = AudioCue.register({ + sound: Sound.chatResponseReceived3, + ...this.chatResponseReceived }); - public static readonly chatResponsePending4 = AudioCue.register({ - sound: Sound.chatResponsePending4, - ...this.chatResponsePending + public static readonly chatResponseReceived4 = AudioCue.register({ + sound: Sound.chatResponseReceived4, + ...this.chatResponseReceived }); - public static readonly chatResponsePending5 = AudioCue.register({ - sound: Sound.chatResponsePending5, - ...this.chatResponsePending + public static readonly chatResponseReceived5 = AudioCue.register({ + sound: Sound.chatResponseReceived5, + ...this.chatResponseReceived }); - public static readonly chatResponseReceived = AudioCue.register({ - name: localize('audioCues.chatResponseReceived', 'Chat Response Received'), - sound: Sound.chatResponseReceived, - settingsKey: 'audioCues.chatResponseReceived' + public static readonly chatResponsePending = AudioCue.register({ + name: localize('audioCues.chatResponsePending', 'Chat Response Pending'), + sound: Sound.chatResponsePending, + settingsKey: 'audioCues.chatResponsePending' }); private constructor( diff --git a/src/vs/platform/audioCues/browser/media/chatResponsePending1.mp3 b/src/vs/platform/audioCues/browser/media/chatResponsePending.mp3 similarity index 100% rename from src/vs/platform/audioCues/browser/media/chatResponsePending1.mp3 rename to src/vs/platform/audioCues/browser/media/chatResponsePending.mp3 diff --git a/src/vs/platform/audioCues/browser/media/chatResponseReceived1.mp3 b/src/vs/platform/audioCues/browser/media/chatResponseReceived1.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..670fdef74ee6d7ce31103a6785feebbde99f4b67 GIT binary patch literal 36352 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 R{$l3*;^!~su%FD_{{c8q7=-`; literal 0 HcmV?d00001 diff --git a/src/vs/platform/audioCues/browser/media/chatResponsePending2.mp3 b/src/vs/platform/audioCues/browser/media/chatResponseReceived2.mp3 similarity index 100% rename from src/vs/platform/audioCues/browser/media/chatResponsePending2.mp3 rename to src/vs/platform/audioCues/browser/media/chatResponseReceived2.mp3 diff --git a/src/vs/platform/audioCues/browser/media/chatResponsePending3.mp3 b/src/vs/platform/audioCues/browser/media/chatResponseReceived3.mp3 similarity index 100% rename from src/vs/platform/audioCues/browser/media/chatResponsePending3.mp3 rename to src/vs/platform/audioCues/browser/media/chatResponseReceived3.mp3 diff --git a/src/vs/platform/audioCues/browser/media/chatResponsePending4.mp3 b/src/vs/platform/audioCues/browser/media/chatResponseReceived4.mp3 similarity index 100% rename from src/vs/platform/audioCues/browser/media/chatResponsePending4.mp3 rename to src/vs/platform/audioCues/browser/media/chatResponseReceived4.mp3 diff --git a/src/vs/platform/audioCues/browser/media/chatResponsePending5.mp3 b/src/vs/platform/audioCues/browser/media/chatResponseReceived5.mp3 similarity index 100% rename from src/vs/platform/audioCues/browser/media/chatResponsePending5.mp3 rename to src/vs/platform/audioCues/browser/media/chatResponseReceived5.mp3 diff --git a/src/vs/workbench/contrib/chat/browser/chatWidget.ts b/src/vs/workbench/contrib/chat/browser/chatWidget.ts index cb75be46473..b9fa3d3d42c 100644 --- a/src/vs/workbench/contrib/chat/browser/chatWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/chatWidget.ts @@ -392,13 +392,13 @@ export class ChatWidget extends Disposable implements IChatWidget { } this.audioCueService.playAudioCue(AudioCue.chatRequestSent, true); const input = query ?? editorValue; - const cue = this.audioCueService.playRandomAudioCue(AudioCueGroupId.chatResponsePending, true); + const cue = this.audioCueService.playAudioCueLoop(AudioCue.chatResponsePending); const result = await this.chatService.sendRequest(this.viewModel.sessionId, input); if (result) { this.inputPart.acceptInput(query); result.responseCompletePromise.then(async () => { cue?.dispose(); - this.audioCueService.playAudioCue(AudioCue.chatResponseReceived, true); + this.audioCueService.playRandomAudioCue(AudioCueGroupId.chatResponseReceived); const responses = this.viewModel?.getItems().filter(isResponseVM); const lastResponse = responses?.[responses.length - 1]; if (lastResponse) { From f27587102931eee7239d717cc6cbae6dd8fe0414 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Thu, 15 Jun 2023 11:59:11 -0500 Subject: [PATCH 11/69] cleanup --- src/vs/editor/standalone/browser/standaloneServices.ts | 2 +- src/vs/platform/audioCues/browser/audioCueService.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/editor/standalone/browser/standaloneServices.ts b/src/vs/editor/standalone/browser/standaloneServices.ts index dcf5d9a30f5..2f12a812631 100644 --- a/src/vs/editor/standalone/browser/standaloneServices.ts +++ b/src/vs/editor/standalone/browser/standaloneServices.ts @@ -1058,7 +1058,7 @@ class StandaloneAudioService implements IAudioCueService { playAudioCueLoop(cue: AudioCue): IDisposable { return toDisposable(() => { }); } - playRandomAudioCue(groupId: AudioCueGroupId, allowManyInParallel?: boolean | undefined): void | IDisposable { + playRandomAudioCue(groupId: AudioCueGroupId, allowManyInParallel?: boolean | undefined): void { } } diff --git a/src/vs/platform/audioCues/browser/audioCueService.ts b/src/vs/platform/audioCues/browser/audioCueService.ts index 4708559dd35..489e6e7a49f 100644 --- a/src/vs/platform/audioCues/browser/audioCueService.ts +++ b/src/vs/platform/audioCues/browser/audioCueService.ts @@ -27,7 +27,7 @@ export interface IAudioCueService { playSound(cue: Sound, allowManyInParallel?: boolean): Promise; playAudioCueLoop(cue: AudioCue): IDisposable; - playRandomAudioCue(groupId: AudioCueGroupId, allowManyInParallel?: boolean): IDisposable | void; + playRandomAudioCue(groupId: AudioCueGroupId, allowManyInParallel?: boolean): void; } export class AudioCueService extends Disposable implements IAudioCueService { @@ -57,7 +57,7 @@ export class AudioCueService extends Disposable implements IAudioCueService { await Promise.all(Array.from(sounds).map(sound => this.playSound(sound, true))); } - public playRandomAudioCue(groupId: AudioCueGroupId, allowManyInParallel?: boolean): void | IDisposable { + public playRandomAudioCue(groupId: AudioCueGroupId, allowManyInParallel?: boolean): void { const cues = AudioCue.allAudioCues.filter(cue => cue.groupId === groupId); const index = Math.floor(Math.random() * cues.length); this.playAudioCue(cues[index], allowManyInParallel); From 86a64afe95bc55a70908369f5c7e1f5302f2d0de Mon Sep 17 00:00:00 2001 From: meganrogge Date: Thu, 15 Jun 2023 12:46:08 -0500 Subject: [PATCH 12/69] fix issue --- src/vs/platform/audioCues/browser/audioCueService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/platform/audioCues/browser/audioCueService.ts b/src/vs/platform/audioCues/browser/audioCueService.ts index 489e6e7a49f..4abd131759f 100644 --- a/src/vs/platform/audioCues/browser/audioCueService.ts +++ b/src/vs/platform/audioCues/browser/audioCueService.ts @@ -103,7 +103,7 @@ export class AudioCueService extends Disposable implements IAudioCueService { let playing = true; const playSound = () => { if (playing) { - this.playSound(cue.sound, true).finally(() => { + this.playAudioCue(cue, true).finally(() => { if (playing) { playSound(); } From b9e10175b9f19e27c2bdc47784edb8000bba715e Mon Sep 17 00:00:00 2001 From: meganrogge Date: Thu, 15 Jun 2023 13:54:01 -0500 Subject: [PATCH 13/69] set to off by default --- .../contrib/audioCues/browser/audioCues.contribution.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts b/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts index 90a844680e0..0b767b35e90 100644 --- a/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts +++ b/src/vs/workbench/contrib/audioCues/browser/audioCues.contribution.ts @@ -119,15 +119,18 @@ Registry.as(ConfigurationExtensions.Configuration).regis }, 'audioCues.chatRequestSent': { 'description': localize('audioCues.chatRequestSent', "Plays a sound when a chat request is made."), - ...audioCueFeatureBase + ...audioCueFeatureBase, + default: 'off' }, 'audioCues.chatResponsePending': { 'description': localize('audioCues.chatResponsePending', "Plays a sound on loop while the response is pending."), - ...audioCueFeatureBase + ...audioCueFeatureBase, + default: 'off' }, 'audioCues.chatResponseReceived': { 'description': localize('audioCues.chatResponseReceived', "Plays a sound on loop while the response has been received."), - ...audioCueFeatureBase + ...audioCueFeatureBase, + default: 'off' } } }); From 4066bbfb05f22c92f470a8e13b5a67f60db6c72a Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Thu, 15 Jun 2023 13:57:17 -0500 Subject: [PATCH 14/69] Update src/vs/editor/standalone/browser/standaloneServices.ts --- src/vs/editor/standalone/browser/standaloneServices.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/standalone/browser/standaloneServices.ts b/src/vs/editor/standalone/browser/standaloneServices.ts index 2f12a812631..cc2ede5219c 100644 --- a/src/vs/editor/standalone/browser/standaloneServices.ts +++ b/src/vs/editor/standalone/browser/standaloneServices.ts @@ -1058,7 +1058,7 @@ class StandaloneAudioService implements IAudioCueService { playAudioCueLoop(cue: AudioCue): IDisposable { return toDisposable(() => { }); } - playRandomAudioCue(groupId: AudioCueGroupId, allowManyInParallel?: boolean | undefined): void { + playRandomAudioCue(groupId: AudioCueGroupId, allowManyInParallel?: boolean): void { } } From e0d2df090c746aa9e47fae49ec93f1290b8d8773 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Thu, 15 Jun 2023 14:46:58 -0500 Subject: [PATCH 15/69] loop every 7 seconds --- .../platform/audioCues/browser/audioCueService.ts | 15 +++++++++------ .../workbench/contrib/chat/browser/chatWidget.ts | 4 ++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/vs/platform/audioCues/browser/audioCueService.ts b/src/vs/platform/audioCues/browser/audioCueService.ts index 4abd131759f..5097b521851 100644 --- a/src/vs/platform/audioCues/browser/audioCueService.ts +++ b/src/vs/platform/audioCues/browser/audioCueService.ts @@ -26,7 +26,7 @@ export interface IAudioCueService { onEnabledChanged(cue: AudioCue): Event; playSound(cue: Sound, allowManyInParallel?: boolean): Promise; - playAudioCueLoop(cue: AudioCue): IDisposable; + playAudioCueLoop(cue: AudioCue, milliseconds: number): IDisposable; playRandomAudioCue(groupId: AudioCueGroupId, allowManyInParallel?: boolean): void; } @@ -75,10 +75,11 @@ export class AudioCueService extends Disposable implements IAudioCueService { private readonly playingSounds = new Set(); public async playSound(sound: Sound, allowManyInParallel = false): Promise { + console.log(sound.fileName, allowManyInParallel); if (!allowManyInParallel && this.playingSounds.has(sound)) { return; } - + console.log('playing', sound.fileName); this.playingSounds.add(sound); const url = FileAccess.asBrowserUri(`vs/platform/audioCues/browser/media/${sound.fileName}`).toString(true); @@ -99,14 +100,16 @@ export class AudioCueService extends Disposable implements IAudioCueService { } } - public playAudioCueLoop(cue: AudioCue): IDisposable { + public playAudioCueLoop(cue: AudioCue, milliseconds: number): IDisposable { let playing = true; const playSound = () => { if (playing) { this.playAudioCue(cue, true).finally(() => { - if (playing) { - playSound(); - } + setTimeout(() => { + if (playing) { + playSound(); + } + }, milliseconds); }); } }; diff --git a/src/vs/workbench/contrib/chat/browser/chatWidget.ts b/src/vs/workbench/contrib/chat/browser/chatWidget.ts index b9fa3d3d42c..0fd3d311dc7 100644 --- a/src/vs/workbench/contrib/chat/browser/chatWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/chatWidget.ts @@ -392,13 +392,13 @@ export class ChatWidget extends Disposable implements IChatWidget { } this.audioCueService.playAudioCue(AudioCue.chatRequestSent, true); const input = query ?? editorValue; - const cue = this.audioCueService.playAudioCueLoop(AudioCue.chatResponsePending); + const cue = this.audioCueService.playAudioCueLoop(AudioCue.chatResponsePending, 7000); const result = await this.chatService.sendRequest(this.viewModel.sessionId, input); if (result) { this.inputPart.acceptInput(query); result.responseCompletePromise.then(async () => { cue?.dispose(); - this.audioCueService.playRandomAudioCue(AudioCueGroupId.chatResponseReceived); + this.audioCueService.playRandomAudioCue(AudioCueGroupId.chatResponseReceived, true); const responses = this.viewModel?.getItems().filter(isResponseVM); const lastResponse = responses?.[responses.length - 1]; if (lastResponse) { From 9ea91c7e41c943c7290ee1262837ce721801c69b Mon Sep 17 00:00:00 2001 From: meganrogge Date: Thu, 15 Jun 2023 14:47:39 -0500 Subject: [PATCH 16/69] rm logs --- src/vs/platform/audioCues/browser/audioCueService.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/vs/platform/audioCues/browser/audioCueService.ts b/src/vs/platform/audioCues/browser/audioCueService.ts index 5097b521851..de3cf85a2ca 100644 --- a/src/vs/platform/audioCues/browser/audioCueService.ts +++ b/src/vs/platform/audioCues/browser/audioCueService.ts @@ -75,11 +75,9 @@ export class AudioCueService extends Disposable implements IAudioCueService { private readonly playingSounds = new Set(); public async playSound(sound: Sound, allowManyInParallel = false): Promise { - console.log(sound.fileName, allowManyInParallel); if (!allowManyInParallel && this.playingSounds.has(sound)) { return; } - console.log('playing', sound.fileName); this.playingSounds.add(sound); const url = FileAccess.asBrowserUri(`vs/platform/audioCues/browser/media/${sound.fileName}`).toString(true); From 5fe42187d64854529a7bfaebab52463c2f028486 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Thu, 15 Jun 2023 14:52:17 -0500 Subject: [PATCH 17/69] cleanup --- src/vs/platform/audioCues/browser/audioCueService.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/vs/platform/audioCues/browser/audioCueService.ts b/src/vs/platform/audioCues/browser/audioCueService.ts index de3cf85a2ca..1d4df23804c 100644 --- a/src/vs/platform/audioCues/browser/audioCueService.ts +++ b/src/vs/platform/audioCues/browser/audioCueService.ts @@ -12,10 +12,6 @@ import { Event } from 'vs/base/common/event'; import { localize } from 'vs/nls'; import { observableFromEvent, derived } from 'vs/base/common/observable'; -export const enum AudioCueGroupId { - chatResponseReceived = 'chatResponseReceived' -} - export const IAudioCueService = createDecorator('audioCue'); export interface IAudioCueService { @@ -112,9 +108,7 @@ export class AudioCueService extends Disposable implements IAudioCueService { } }; playSound(); - return toDisposable(() => { - playing = false; - }); + return toDisposable(() => playing = false); } private readonly obsoleteAudioCuesEnabled = observableFromEvent( @@ -231,6 +225,10 @@ export class Sound { private constructor(public readonly fileName: string) { } } +export const enum AudioCueGroupId { + chatResponseReceived = 'chatResponseReceived' +} + export class AudioCue { private static _audioCues = new Set(); private static register(options: { From e94b3ef2c33b1af3d20bc2b42f581752be67e06d Mon Sep 17 00:00:00 2001 From: meganrogge Date: Thu, 15 Jun 2023 15:06:43 -0500 Subject: [PATCH 18/69] polish --- src/vs/workbench/contrib/chat/browser/chatWidget.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatWidget.ts b/src/vs/workbench/contrib/chat/browser/chatWidget.ts index 0fd3d311dc7..4c14d0237c1 100644 --- a/src/vs/workbench/contrib/chat/browser/chatWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/chatWidget.ts @@ -53,6 +53,8 @@ export interface IChatWidgetStyles { resultEditorBackground: string; } +const CHAT_RESPONSE_PENDING_AUDIO_CUE_LOOP_MS = 7000; + export class ChatWidget extends Disposable implements IChatWidget { public static readonly CONTRIBS: { new(...args: [IChatWidget, ...any]): any }[] = []; @@ -391,13 +393,14 @@ export class ChatWidget extends Disposable implements IChatWidget { return; } this.audioCueService.playAudioCue(AudioCue.chatRequestSent, true); + const responsePendingAudioCue = this.audioCueService.playAudioCueLoop(AudioCue.chatResponsePending, CHAT_RESPONSE_PENDING_AUDIO_CUE_LOOP_MS); const input = query ?? editorValue; - const cue = this.audioCueService.playAudioCueLoop(AudioCue.chatResponsePending, 7000); const result = await this.chatService.sendRequest(this.viewModel.sessionId, input); + if (result) { this.inputPart.acceptInput(query); result.responseCompletePromise.then(async () => { - cue?.dispose(); + responsePendingAudioCue?.dispose(); this.audioCueService.playRandomAudioCue(AudioCueGroupId.chatResponseReceived, true); const responses = this.viewModel?.getItems().filter(isResponseVM); const lastResponse = responses?.[responses.length - 1]; From a54a2c5e4b7ef332720fb51c69e91b2b55e7374d Mon Sep 17 00:00:00 2001 From: meganrogge Date: Thu, 15 Jun 2023 15:18:06 -0500 Subject: [PATCH 19/69] add chatAccessibilityService --- .../contrib/chat/browser/chatWidget.ts | 40 ++++++++++++++----- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatWidget.ts b/src/vs/workbench/contrib/chat/browser/chatWidget.ts index 4c14d0237c1..86228410308 100644 --- a/src/vs/workbench/contrib/chat/browser/chatWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/chatWidget.ts @@ -53,8 +53,6 @@ export interface IChatWidgetStyles { resultEditorBackground: string; } -const CHAT_RESPONSE_PENDING_AUDIO_CUE_LOOP_MS = 7000; - export class ChatWidget extends Disposable implements IChatWidget { public static readonly CONTRIBS: { new(...args: [IChatWidget, ...any]): any }[] = []; @@ -110,6 +108,8 @@ export class ChatWidget extends Disposable implements IChatWidget { private lastSlashCommands: ISlashCommand[] | undefined; private slashCommandsPromise: Promise | undefined; + private _chatAccessibilityService: ChatAccessibilityService; + constructor( readonly viewContext: IChatWidgetViewContext, private readonly styles: IChatWidgetStyles, @@ -118,13 +118,14 @@ export class ChatWidget extends Disposable implements IChatWidget { @IChatService private readonly chatService: IChatService, @IChatWidgetService chatWidgetService: IChatWidgetService, @IContextMenuService private readonly contextMenuService: IContextMenuService, - @IAudioCueService private readonly audioCueService: IAudioCueService + @IAudioCueService audioCueService: IAudioCueService ) { super(); CONTEXT_IN_CHAT_SESSION.bindTo(contextKeyService).set(true); this.requestInProgress = CONTEXT_CHAT_REQUEST_IN_PROGRESS.bindTo(contextKeyService); this._register((chatWidgetService as ChatWidgetService).register(this)); + this._chatAccessibilityService = new ChatAccessibilityService(audioCueService); } get providerId(): string { @@ -392,22 +393,17 @@ export class ChatWidget extends Disposable implements IChatWidget { this.instantiationService.invokeFunction(clearChatSession, this); return; } - this.audioCueService.playAudioCue(AudioCue.chatRequestSent, true); - const responsePendingAudioCue = this.audioCueService.playAudioCueLoop(AudioCue.chatResponsePending, CHAT_RESPONSE_PENDING_AUDIO_CUE_LOOP_MS); + this._chatAccessibilityService.acceptRequest(); const input = query ?? editorValue; const result = await this.chatService.sendRequest(this.viewModel.sessionId, input); if (result) { this.inputPart.acceptInput(query); result.responseCompletePromise.then(async () => { - responsePendingAudioCue?.dispose(); - this.audioCueService.playRandomAudioCue(AudioCueGroupId.chatResponseReceived, true); + const responses = this.viewModel?.getItems().filter(isResponseVM); const lastResponse = responses?.[responses.length - 1]; - if (lastResponse) { - const errorDetails = lastResponse.errorDetails ? ` ${lastResponse.errorDetails.message}` : ''; - alert(lastResponse.response.value + errorDetails); - } + this._chatAccessibilityService.acceptResponse(lastResponse); }); } } @@ -513,3 +509,25 @@ export class ChatWidgetService implements IChatWidgetService { ); } } + +const CHAT_RESPONSE_PENDING_AUDIO_CUE_LOOP_MS = 7000; +class ChatAccessibilityService extends Disposable { + private _responsePendingAudioCue: IDisposable | undefined; + constructor(@IAudioCueService private readonly _audioCueService: IAudioCueService) { + super(); + } + acceptRequest(): void { + this._audioCueService.playAudioCue(AudioCue.chatRequestSent, true); + this._responsePendingAudioCue = this._audioCueService.playAudioCueLoop(AudioCue.chatResponsePending, CHAT_RESPONSE_PENDING_AUDIO_CUE_LOOP_MS); + } + acceptResponse(response?: IChatResponseViewModel): void { + this._responsePendingAudioCue?.dispose(); + if (!response) { + return; + } + this._audioCueService.playRandomAudioCue(AudioCueGroupId.chatResponseReceived, true); + const errorDetails = response.errorDetails ? ` ${response.errorDetails.message}` : ''; + alert(response.response.value + errorDetails); + } +} + From 0f3fa7bbaf3c01d0ba51d80d967efc695ee5df1d Mon Sep 17 00:00:00 2001 From: meganrogge Date: Thu, 15 Jun 2023 15:18:54 -0500 Subject: [PATCH 20/69] register chat accessibility service --- src/vs/workbench/contrib/chat/browser/chatWidget.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/contrib/chat/browser/chatWidget.ts b/src/vs/workbench/contrib/chat/browser/chatWidget.ts index 86228410308..1c0670eb6b2 100644 --- a/src/vs/workbench/contrib/chat/browser/chatWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/chatWidget.ts @@ -126,6 +126,7 @@ export class ChatWidget extends Disposable implements IChatWidget { this._register((chatWidgetService as ChatWidgetService).register(this)); this._chatAccessibilityService = new ChatAccessibilityService(audioCueService); + this._register(this._chatAccessibilityService); } get providerId(): string { From eae6a3607837efd99d57230de9e1338dfbf34e82 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Thu, 15 Jun 2023 15:25:33 -0500 Subject: [PATCH 21/69] ChatAccessibilityService --- .../contrib/chat/browser/chat.contribution.ts | 5 +++-- src/vs/workbench/contrib/chat/browser/chat.ts | 8 ++++++++ .../contrib/chat/browser/chatWidget.ts | 17 +++++++++-------- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts index d8130d27601..af94c2c5c24 100644 --- a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts +++ b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts @@ -22,11 +22,11 @@ import { registerChatExecuteActions } from 'vs/workbench/contrib/chat/browser/ac import { registerChatQuickQuestionActions } from 'vs/workbench/contrib/chat/browser/actions/chatQuickInputActions'; import { registerChatTitleActions } from 'vs/workbench/contrib/chat/browser/actions/chatTitleActions'; import { registerChatExportActions } from 'vs/workbench/contrib/chat/browser/actions/chatImportExport'; -import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat'; +import { IChatAccessibilityService, IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat'; import { ChatContributionService } from 'vs/workbench/contrib/chat/browser/chatContributionServiceImpl'; import { ChatEditor, IChatEditorOptions } from 'vs/workbench/contrib/chat/browser/chatEditor'; import { ChatEditorInput, ChatEditorInputSerializer } from 'vs/workbench/contrib/chat/browser/chatEditorInput'; -import { ChatWidgetService } from 'vs/workbench/contrib/chat/browser/chatWidget'; +import { ChatAccessibilityService, ChatWidgetService } from 'vs/workbench/contrib/chat/browser/chatWidget'; import 'vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib'; import { IChatContributionService } from 'vs/workbench/contrib/chat/common/chatContributionService'; import { IChatService } from 'vs/workbench/contrib/chat/common/chatService'; @@ -136,5 +136,6 @@ registerClearActions(); registerSingleton(IChatService, ChatService, InstantiationType.Delayed); registerSingleton(IChatContributionService, ChatContributionService, InstantiationType.Delayed); registerSingleton(IChatWidgetService, ChatWidgetService, InstantiationType.Delayed); +registerSingleton(IChatAccessibilityService, ChatAccessibilityService, InstantiationType.Delayed); registerSingleton(IChatWidgetHistoryService, ChatWidgetHistoryService, InstantiationType.Delayed); diff --git a/src/vs/workbench/contrib/chat/browser/chat.ts b/src/vs/workbench/contrib/chat/browser/chat.ts index ba977100111..9d8047338f8 100644 --- a/src/vs/workbench/contrib/chat/browser/chat.ts +++ b/src/vs/workbench/contrib/chat/browser/chat.ts @@ -11,6 +11,7 @@ import { URI } from 'vs/base/common/uri'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; export const IChatWidgetService = createDecorator('chatWidgetService'); +export const IChatAccessibilityService = createDecorator('chatAccessibilityService'); export interface IChatWidgetService { @@ -29,6 +30,13 @@ export interface IChatWidgetService { getWidgetByInputUri(uri: URI): IChatWidget | undefined; } + +export interface IChatAccessibilityService { + readonly _serviceBrand: undefined; + acceptRequest(): void; + acceptResponse(response?: IChatResponseViewModel): void; +} + export interface IChatCodeBlockInfo { codeBlockIndex: number; element: IChatResponseViewModel; diff --git a/src/vs/workbench/contrib/chat/browser/chatWidget.ts b/src/vs/workbench/contrib/chat/browser/chatWidget.ts index 1c0670eb6b2..7f756c4bb63 100644 --- a/src/vs/workbench/contrib/chat/browser/chatWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/chatWidget.ts @@ -24,7 +24,7 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle import { WorkbenchObjectTree } from 'vs/platform/list/browser/listService'; import { IViewsService } from 'vs/workbench/common/views'; import { clearChatSession } from 'vs/workbench/contrib/chat/browser/actions/chatClear'; -import { ChatTreeItem, IChatCodeBlockInfo, IChatWidget, IChatWidgetService, IChatWidgetViewContext } from 'vs/workbench/contrib/chat/browser/chat'; +import { ChatTreeItem, IChatAccessibilityService, IChatCodeBlockInfo, IChatWidget, IChatWidgetService, IChatWidgetViewContext } from 'vs/workbench/contrib/chat/browser/chat'; import { ChatInputPart } from 'vs/workbench/contrib/chat/browser/chatInputPart'; import { ChatAccessibilityProvider, ChatListDelegate, ChatListItemRenderer, IChatRendererDelegate } from 'vs/workbench/contrib/chat/browser/chatListRenderer'; import { ChatEditorOptions } from 'vs/workbench/contrib/chat/browser/chatOptions'; @@ -108,8 +108,6 @@ export class ChatWidget extends Disposable implements IChatWidget { private lastSlashCommands: ISlashCommand[] | undefined; private slashCommandsPromise: Promise | undefined; - private _chatAccessibilityService: ChatAccessibilityService; - constructor( readonly viewContext: IChatWidgetViewContext, private readonly styles: IChatWidgetStyles, @@ -118,15 +116,13 @@ export class ChatWidget extends Disposable implements IChatWidget { @IChatService private readonly chatService: IChatService, @IChatWidgetService chatWidgetService: IChatWidgetService, @IContextMenuService private readonly contextMenuService: IContextMenuService, - @IAudioCueService audioCueService: IAudioCueService + @IChatAccessibilityService private readonly _chatAccessibilityService: IChatAccessibilityService ) { super(); CONTEXT_IN_CHAT_SESSION.bindTo(contextKeyService).set(true); this.requestInProgress = CONTEXT_CHAT_REQUEST_IN_PROGRESS.bindTo(contextKeyService); this._register((chatWidgetService as ChatWidgetService).register(this)); - this._chatAccessibilityService = new ChatAccessibilityService(audioCueService); - this._register(this._chatAccessibilityService); } get providerId(): string { @@ -511,9 +507,14 @@ export class ChatWidgetService implements IChatWidgetService { } } + const CHAT_RESPONSE_PENDING_AUDIO_CUE_LOOP_MS = 7000; -class ChatAccessibilityService extends Disposable { +export class ChatAccessibilityService extends Disposable implements IChatAccessibilityService { + + declare readonly _serviceBrand: undefined; + private _responsePendingAudioCue: IDisposable | undefined; + constructor(@IAudioCueService private readonly _audioCueService: IAudioCueService) { super(); } @@ -523,10 +524,10 @@ class ChatAccessibilityService extends Disposable { } acceptResponse(response?: IChatResponseViewModel): void { this._responsePendingAudioCue?.dispose(); + this._audioCueService.playRandomAudioCue(AudioCueGroupId.chatResponseReceived, true); if (!response) { return; } - this._audioCueService.playRandomAudioCue(AudioCueGroupId.chatResponseReceived, true); const errorDetails = response.errorDetails ? ` ${response.errorDetails.message}` : ''; alert(response.response.value + errorDetails); } From 0e9c2fa760932b13f81516aff15f2b0112aa6eeb Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Thu, 15 Jun 2023 21:47:49 -0700 Subject: [PATCH 22/69] testing: use a real terminal in test Test Results view (#184963) * wip * wip * it works * address pr comments * add cwd capability to test peek view * add padding and fix peek display issues * ignore scroll events with default prevented * fixup tests * comments * comments --- .../browser/ui/scrollbar/scrollableElement.ts | 3 + .../terminal/browser/media/scrollbar.css | 33 +-- .../terminal/browser/media/terminal.css | 65 +++--- .../contrib/terminal/browser/terminal.ts | 94 ++++++++- .../terminal/browser/terminalActions.ts | 129 +++++++----- .../terminal/browser/terminalEditor.ts | 2 +- .../terminal/browser/terminalInstance.ts | 112 ++++------ .../terminal/browser/terminalService.ts | 38 +++- .../terminal/browser/xterm/xtermTerminal.ts | 194 +++++++++++++++--- .../terminal/common/terminalContextKey.ts | 8 + .../test/browser/xterm/xtermTerminal.test.ts | 4 +- .../test/browser/bufferContentTracker.test.ts | 2 + .../contrib/testing/browser/media/testing.css | 4 +- .../testing/browser/testingOutputPeek.ts | 181 ++++++++++++---- 14 files changed, 609 insertions(+), 260 deletions(-) diff --git a/src/vs/base/browser/ui/scrollbar/scrollableElement.ts b/src/vs/base/browser/ui/scrollbar/scrollableElement.ts index 87d4ed4d9fa..5cf11ce7854 100644 --- a/src/vs/base/browser/ui/scrollbar/scrollableElement.ts +++ b/src/vs/base/browser/ui/scrollbar/scrollableElement.ts @@ -373,6 +373,9 @@ export abstract class AbstractScrollableElement extends Widget { } private _onMouseWheel(e: StandardWheelEvent): void { + if (e.browserEvent?.defaultPrevented) { + return; + } const classifier = MouseWheelClassifier.INSTANCE; if (SCROLL_WHEEL_SMOOTH_SCROLL_ENABLED) { diff --git a/src/vs/workbench/contrib/terminal/browser/media/scrollbar.css b/src/vs/workbench/contrib/terminal/browser/media/scrollbar.css index d87b418ed89..2a1f155fc8e 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/scrollbar.css +++ b/src/vs/workbench/contrib/terminal/browser/media/scrollbar.css @@ -3,8 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -.monaco-workbench .editor-instance .xterm-viewport, -.monaco-workbench .pane-body.integrated-terminal .xterm-viewport { +.monaco-workbench .xterm-viewport { /* Use the hack presented in https://stackoverflow.com/a/38748186/1156119 to get opacity transitions working on the scrollbar */ -webkit-background-clip: text; background-clip: text; @@ -12,45 +11,35 @@ transition: background-color 800ms linear; } -.monaco-workbench .editor-instance .xterm-viewport, -.monaco-workbench .pane-body.integrated-terminal .xterm-viewport { +.monaco-workbench .xterm-viewport { scrollbar-width: thin; } -.monaco-workbench .editor-instance .xterm-viewport::-webkit-scrollbar, -.monaco-workbench .pane-body.integrated-terminal .xterm-viewport::-webkit-scrollbar { +.monaco-workbench .xterm-viewport::-webkit-scrollbar { width: 10px; } -.monaco-workbench .editor-instance .xterm-viewport::-webkit-scrollbar-track, -.monaco-workbench .pane-body.integrated-terminal .xterm-viewport::-webkit-scrollbar-track { +.monaco-workbench .xterm-viewport::-webkit-scrollbar-track { opacity: 0; } -.monaco-workbench .editor-instance .xterm-viewport::-webkit-scrollbar-thumb, -.monaco-workbench .pane-body.integrated-terminal .xterm-viewport::-webkit-scrollbar-thumb { +.monaco-workbench .xterm-viewport::-webkit-scrollbar-thumb { min-height: 20px; background-color: inherit; } -.monaco-workbench .editor-instance .force-scrollbar .xterm .xterm-viewport, -.monaco-workbench .pane-body.integrated-terminal .force-scrollbar .xterm .xterm-viewport, -.monaco-workbench .editor-instance .xterm.focus .xterm-viewport, -.monaco-workbench .pane-body.integrated-terminal .xterm.focus .xterm-viewport, -.monaco-workbench .editor-instance .xterm:focus .xterm-viewport, -.monaco-workbench .pane-body.integrated-terminal .xterm:focus .xterm-viewport, -.monaco-workbench .editor-instance .xterm:hover .xterm-viewport, -.monaco-workbench .pane-body.integrated-terminal .xterm:hover .xterm-viewport { +.monaco-workbench .force-scrollbar .xterm .xterm-viewport, +.monaco-workbench .xterm.focus .xterm-viewport, +.monaco-workbench .xterm:focus .xterm-viewport, +.monaco-workbench .xterm:hover .xterm-viewport { transition: opacity 100ms linear; cursor: default; } -.monaco-workbench .editor-instance .xterm .xterm-viewport::-webkit-scrollbar-thumb:hover, -.monaco-workbench .pane-body.integrated-terminal .xterm .xterm-viewport::-webkit-scrollbar-thumb:hover { +.monaco-workbench .xterm .xterm-viewport::-webkit-scrollbar-thumb:hover { transition: opacity 0ms linear; } -.monaco-workbench .editor-instance .xterm .xterm-viewport::-webkit-scrollbar-thumb:window-inactive, -.monaco-workbench .pane-body.integrated-terminal .xterm .xterm-viewport::-webkit-scrollbar-thumb:window-inactive { +.monaco-workbench .xterm .xterm-viewport::-webkit-scrollbar-thumb:window-inactive { background-color: inherit; } diff --git a/src/vs/workbench/contrib/terminal/browser/media/terminal.css b/src/vs/workbench/contrib/terminal/browser/media/terminal.css index 91c80d201f3..814626ed4f5 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/terminal.css +++ b/src/vs/workbench/contrib/terminal/browser/media/terminal.css @@ -26,8 +26,8 @@ .monaco-workbench .pane-body.integrated-terminal .terminal-groups-container, .monaco-workbench .pane-body.integrated-terminal .terminal-group, .monaco-workbench .pane-body.integrated-terminal .terminal-split-pane, -.monaco-workbench .editor-instance .terminal-split-pane, -.monaco-workbench .editor-instance .terminal-outer-container { +.monaco-workbench .terminal-editor .terminal-split-pane, +.monaco-workbench .terminal-editor .terminal-outer-container { height: 100%; } .monaco-workbench .part.sidebar .pane-body.integrated-terminal .terminal-outer-container, @@ -48,7 +48,7 @@ background-color: var(--vscode-terminal-tab-activeBorder); } /* Override monaco's styles for terminal editors */ -.monaco-workbench .editor-instance .xterm textarea:focus { +.monaco-workbench .terminal-editor .xterm textarea:focus { opacity: 0 !important; outline: 0 !important; } @@ -62,20 +62,23 @@ background-image: none !important; } -.monaco-workbench .editor-instance .terminal-wrapper { +.monaco-workbench .terminal-editor .terminal-wrapper { background-color: var(--vscode-terminal-background, --vscode-editorPane-background); } -.monaco-workbench .editor-instance .terminal-wrapper, +.monaco-workbench .terminal-editor .terminal-wrapper, .monaco-workbench .pane-body.integrated-terminal .terminal-wrapper { display: block; height: 100%; box-sizing: border-box; } -.monaco-workbench .editor-instance .xterm, -.monaco-workbench .pane-body.integrated-terminal .xterm { +.monaco-workbench .xterm { /* All terminals have at least 10px left/right edge padding and 2 padding on the bottom (so underscores on last line are visible */ padding: 0 10px 2px; +} + +.monaco-workbench .terminal-editor .xterm, +.monaco-workbench .pane-body.integrated-terminal .xterm { /* Bottom align the terminal within the split pane */ position: absolute; bottom: 0; @@ -88,23 +91,23 @@ top: 0; } -.monaco-workbench .editor-instance .terminal-wrapper.fixed-dims .xterm, +.monaco-workbench .terminal-editor .terminal-wrapper.fixed-dims .xterm, .monaco-workbench .pane-body.integrated-terminal .terminal-wrapper.fixed-dims .xterm { position: static; } -.monaco-workbench .editor-instance .xterm-viewport, +.monaco-workbench .terminal-editor .xterm-viewport, .monaco-workbench .pane-body.integrated-terminal .xterm-viewport { z-index: 30; } -.monaco-workbench .editor-instance .xterm-decoration-overview-ruler, +.monaco-workbench .terminal-editor .xterm-decoration-overview-ruler, .monaco-workbench .pane-body.integrated-terminal .xterm-decoration-overview-ruler { z-index: 31; /* Must be higher than .xterm-viewport */ pointer-events: none; } -.monaco-workbench .editor-instance .xterm-screen, +.monaco-workbench .terminal-editor .xterm-screen, .monaco-workbench .pane-body.integrated-terminal .xterm-screen { z-index: 31; } @@ -127,7 +130,7 @@ .xterm.xterm-cursor-pointer .xterm-screen { cursor: pointer; } .xterm.column-select.focus .xterm-screen { cursor: crosshair; } -.monaco-workbench .editor-instance .xterm { +.monaco-workbench .terminal-editor .xterm { padding-left: 20px !important; } @@ -136,34 +139,34 @@ padding-left: 20px !important; } -.monaco-workbench .editor-instance .terminal-group .monaco-split-view2.horizontal .split-view-view:last-child .xterm, +.monaco-workbench .terminal-editor .terminal-group .monaco-split-view2.horizontal .split-view-view:last-child .xterm, .monaco-workbench .pane-body.integrated-terminal .terminal-group .monaco-split-view2.horizontal .split-view-view:last-child .xterm { padding-right: 20px; } -.monaco-workbench .editor-instance .xterm a:not(.xterm-invalid-link), +.monaco-workbench .terminal-editor .xterm a:not(.xterm-invalid-link), .monaco-workbench .pane-body.integrated-terminal .xterm a:not(.xterm-invalid-link) { /* To support message box sizing */ position: relative; } -.monaco-workbench .editor-instance .terminal-wrapper > div, +.monaco-workbench .terminal-editor .terminal-wrapper > div, .monaco-workbench .pane-body.integrated-terminal .terminal-wrapper > div { height: 100%; } -.monaco-workbench .editor-instance .xterm-viewport, +.monaco-workbench .terminal-editor .xterm-viewport, .monaco-workbench .pane-body.integrated-terminal .xterm-viewport { box-sizing: border-box; } -.monaco-workbench .editor-instance .terminal-wrapper.fixed-dims, +.monaco-workbench .terminal-editor .terminal-wrapper.fixed-dims, .monaco-workbench .pane-body.integrated-terminal .terminal-wrapper.fixed-dims { /* The viewport should be positioned against this so it does't conflict with a fixed dimensions terminal horizontal scroll bar*/ position: relative; } -.monaco-workbench .editor-instance .terminal-wrapper:not(.fixed-dims) .xterm-viewport, +.monaco-workbench .terminal-editor .terminal-wrapper:not(.fixed-dims) .xterm-viewport, .monaco-workbench .pane-body.integrated-terminal .terminal-wrapper:not(.fixed-dims) .xterm-viewport { /* Override xterm.js' width as we want to size the viewport to fill the panel so the scrollbar is on the right edge */ width: auto !important; @@ -245,7 +248,7 @@ top: 0; } -.monaco-workbench .pane-body.integrated-terminal .xterm .xterm-helper-textarea:focus { +.monaco-workbench .xterm .xterm-helper-textarea:focus { /* Override the general vscode style applies `opacity:1!important` to textareas */ opacity: 0 !important; } @@ -522,34 +525,26 @@ background-color: var(--vscode-terminal-hoverHighlightBackground); } -.monaco-workbench .editor-instance .force-scrollbar .xterm .xterm-viewport, -.monaco-workbench .pane-body.integrated-terminal .force-scrollbar .xterm .xterm-viewport, -.monaco-workbench .editor-instance .xterm.focus .xterm-viewport, -.monaco-workbench .pane-body.integrated-terminal .xterm.focus .xterm-viewport, -.monaco-workbench .editor-instance .xterm:focus .xterm-viewport, -.monaco-workbench .pane-body.integrated-terminal .xterm:focus .xterm-viewport, -.monaco-workbench .editor-instance .xterm:hover .xterm-viewport, -.monaco-workbench .pane-body.integrated-terminal .xterm:hover .xterm-viewport { +.force-scrollbar .xterm .xterm-viewport, +.monaco-workbench .xterm.focus .xterm-viewport, +.monaco-workbench .xterm:focus .xterm-viewport, +.monaco-workbench .xterm:hover .xterm-viewport { background-color: var(--vscode-scrollbarSlider-background) !important; } -.monaco-workbench .editor-instance .xterm-viewport, -.monaco-workbench .pane-body.integrated-terminal .xterm-viewport { +.monaco-workbench .xterm-viewport { scrollbar-color: var(--vscode-scrollbarSlider-background) transparent; } -.monaco-workbench .editor-instance .xterm .xterm-viewport::-webkit-scrollbar-thumb:hover, -.monaco-workbench .pane-body.integrated-terminal .xterm .xterm-viewport::-webkit-scrollbar-thumb:hover { +.monaco-workbench .xterm .xterm-viewport::-webkit-scrollbar-thumb:hover { background-color: var(--vscode-scrollbarSlider-hoverBackground); } -.monaco-workbench .editor-instance .xterm-viewport:hover, -.monaco-workbench .pane-body.integrated-terminal .xterm-viewport:hover { +.monaco-workbench .xterm-viewport:hover { scrollbar-color: var(--vscode-scrollbarSlider-hoverBackground) transparent; } -.monaco-workbench .editor-instance .xterm .xterm-viewport::-webkit-scrollbar-thumb:active, -.monaco-workbench .pane-body.integrated-terminal .xterm .xterm-viewport::-webkit-scrollbar-thumb:active { +.monaco-workbench .xterm .xterm-viewport::-webkit-scrollbar-thumb:active { background-color: var(--vscode-scrollbarSlider-activeBackground); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 9c508dd76c3..21216688f4d 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -139,11 +139,21 @@ export const enum TerminalConnectionState { Connected } +export interface IDetachedXTermOptions { + cols: number; + rows: number; + colorProvider: IXtermColorProvider; + capabilities?: ITerminalCapabilityStore; + readonly?: boolean; +} + export interface ITerminalService extends ITerminalInstanceHost { readonly _serviceBrand: undefined; /** Gets all terminal instances, including editor and terminal view (group) instances. */ readonly instances: readonly ITerminalInstance[]; + /** Gets detached terminal instances created via {@link createDetachedXterm}. */ + readonly detachedXterms: Iterable; configHelper: ITerminalConfigHelper; isProcessSupportRegistered: boolean; readonly connectionState: TerminalConnectionState; @@ -171,6 +181,13 @@ export interface ITerminalService extends ITerminalInstanceHost { */ createTerminal(options?: ICreateTerminalOptions): Promise; + /** + * Creates a detached xterm instance which is not attached to the DOM or + * tracked as a terminal instance. + * @params options The options to create the terminal with + */ + createDetachedXterm(options: IDetachedXTermOptions): Promise; + /** * Creates a raw terminal instance, this should not be used outside of the terminal part. */ @@ -708,11 +725,6 @@ export interface ITerminalInstance { */ resetFocusContextKey(): void; - /** - * Select all text in the terminal. - */ - selectAll(): void; - /** * Focuses the terminal instance if it's able to (the xterm.js instance must exist). * @@ -947,7 +959,14 @@ export const enum XtermTerminalConstants { SearchHighlightLimit = 1000 } -export interface IXtermTerminal { +export interface IXtermAttachToElementOptions { + /** + * Whether GPU rendering should be enabled for this element, defaults to true. + */ + enableGpu: boolean; +} + +export interface IXtermTerminal extends IDisposable { /** * An object that tracks when commands are run and enables navigating and selecting between * them. @@ -962,6 +981,11 @@ export interface IXtermTerminal { readonly onDidChangeSelection: Event; readonly onDidChangeFindResults: Event<{ resultIndex: number; resultCount: number }>; + /** + * Event fired when focus enters (fires with true) or leaves (false) the terminal. + */ + readonly onDidChangeFocus: Event; + /** * Gets a view of the current texture atlas used by the renderers. */ @@ -972,6 +996,18 @@ export interface IXtermTerminal { */ readonly isStdinDisabled: boolean; + /** + * Whether the terminal is currently focused. + */ + readonly isFocused: boolean; + + /** + * Attached the terminal to the given element + * @param container Container the terminal will be rendered in + * @param options Additional options for mounting the terminal in an element + */ + attachToElement(container: HTMLElement, options?: Partial): void; + findResult?: { resultIndex: number; resultCount: number }; /** @@ -994,6 +1030,34 @@ export interface IXtermTerminal { */ getFont(): ITerminalFont; + /** + * Gets whether there's any terminal selection. + */ + hasSelection(): boolean; + + /** + * Clears any terminal selection. + */ + clearSelection(): void; + + /** + * Selects all terminal contents/ + */ + selectAll(): void; + + /** + * Copies the terminal selection. + * @param {boolean} copyAsHtml Whether to copy selection as HTML, defaults to false. + */ + copySelection(copyAsHtml?: boolean): void; + + /** + * Focuses the terminal. Warning: {@link ITerminalInstance.focus} should be + * preferred when dealing with terminal instances in order to get + * accessibility triggers. + */ + focus(): void; + /** Scroll the terminal buffer down 1 line. */ scrollDownLine(): void; /** Scroll the terminal buffer down 1 page. */ scrollDownPage(): void; /** Scroll the terminal buffer to the bottom. */ scrollToBottom(): void; @@ -1022,12 +1086,30 @@ export interface IXtermTerminal { */ getBufferReverseIterator(): IterableIterator; + /** + * Gets the buffer contents as HTML. + */ + getContentsAsHtml(): Promise; + /** * Refreshes the terminal after it has been moved. */ refresh(): void; } +export interface IDetachedXtermTerminal extends IXtermTerminal { + + /** + * Writes data to the terminal. + */ + write(data: string | Uint8Array): void; + + /** + * Resizes the terminal. + */ + resize(columns: number, rows: number): void; +} + export interface IInternalXtermTerminal { /** * Writes text directly to the terminal, bypassing the process. diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 4623b8aad7f..6b27e824491 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -32,7 +32,7 @@ import { IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspac import { PICK_WORKSPACE_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/workspaceCommands'; import { CLOSE_EDITOR_COMMAND_ID } from 'vs/workbench/browser/parts/editor/editorCommands'; import { ResourceContextKey } from 'vs/workbench/common/contextkeys'; -import { Direction, ICreateTerminalOptions, ITerminalEditorService, ITerminalGroupService, ITerminalInstance, ITerminalInstanceService, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { Direction, ICreateTerminalOptions, ITerminalEditorService, ITerminalGroupService, ITerminalInstance, ITerminalInstanceService, ITerminalService, IXtermTerminal } from 'vs/workbench/contrib/terminal/browser/terminal'; import { TerminalQuickAccessProvider } from 'vs/workbench/contrib/terminal/browser/terminalQuickAccess'; import { IRemoteTerminalAttachTarget, ITerminalConfigHelper, ITerminalProfileResolverService, ITerminalProfileService, TerminalCommandId } from 'vs/workbench/contrib/terminal/common/terminal'; import { TerminalContextKeys } from 'vs/workbench/contrib/terminal/common/terminalContextKey'; @@ -60,6 +60,7 @@ import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService import { TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities'; import { killTerminalIcon, newTerminalIcon } from 'vs/workbench/contrib/terminal/browser/terminalIcons'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { Iterable } from 'vs/base/common/iterator'; export const switchTerminalActionViewItemSeparator = '\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500'; export const switchTerminalShowTabsTitle = localize('showTerminalTabs', "Show Tabs"); @@ -179,6 +180,32 @@ export function registerActiveInstanceAction( }); } +/** + * A wrapper around {@link registerTerminalAction} that ensures an active terminal + * exists and provides it to the run function. + * + * This includes detached xterm terminals that are not managed by an {@link ITerminalInstance}. + */ +export function registerActiveXtermAction( + options: IAction2Options & { run: (activeTerminal: IXtermTerminal, accessor: ServicesAccessor, instance?: ITerminalInstance, args?: unknown) => void | Promise } +): IDisposable { + const originalRun = options.run; + return registerTerminalAction({ + ...options, + run: (c, accessor, args) => { + const activeDetached = Iterable.find(c.service.detachedXterms, d => d.isFocused); + if (activeDetached) { + return originalRun(activeDetached, accessor, undefined, args); + } + + const activeInstance = c.service.activeInstance; + if (activeInstance?.xterm) { + return originalRun(activeInstance.xterm, accessor, activeInstance, args); + } + } + }); +} + export interface ITerminalServicesCollection { service: ITerminalService; groupService: ITerminalGroupService; @@ -569,59 +596,59 @@ export function registerTerminalActions() { } }); - registerActiveInstanceAction({ + registerActiveXtermAction({ id: TerminalCommandId.ScrollDownLine, title: { value: localize('workbench.action.terminal.scrollDown', "Scroll Down (Line)"), original: 'Scroll Down (Line)' }, keybinding: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.PageDown, linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.DownArrow }, - when: ContextKeyExpr.and(TerminalContextKeys.focus, TerminalContextKeys.altBufferActive.negate()), + when: ContextKeyExpr.and(TerminalContextKeys.focusInAny, TerminalContextKeys.altBufferActive.negate()), weight: KeybindingWeight.WorkbenchContrib }, precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated), - run: (activeInstance) => activeInstance.scrollDownLine() + run: (xterm) => xterm.scrollDownLine() }); - registerActiveInstanceAction({ + registerActiveXtermAction({ id: TerminalCommandId.ScrollDownPage, title: { value: localize('workbench.action.terminal.scrollDownPage', "Scroll Down (Page)"), original: 'Scroll Down (Page)' }, keybinding: { primary: KeyMod.Shift | KeyCode.PageDown, mac: { primary: KeyCode.PageDown }, - when: ContextKeyExpr.and(TerminalContextKeys.focus, TerminalContextKeys.altBufferActive.negate()), + when: ContextKeyExpr.and(TerminalContextKeys.focusInAny, TerminalContextKeys.altBufferActive.negate()), weight: KeybindingWeight.WorkbenchContrib }, precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated), - run: (activeInstance) => activeInstance.scrollDownPage() + run: (xterm) => xterm.scrollDownPage() }); - registerActiveInstanceAction({ + registerActiveXtermAction({ id: TerminalCommandId.ScrollToBottom, title: { value: localize('workbench.action.terminal.scrollToBottom', "Scroll to Bottom"), original: 'Scroll to Bottom' }, keybinding: { primary: KeyMod.CtrlCmd | KeyCode.End, linux: { primary: KeyMod.Shift | KeyCode.End }, - when: ContextKeyExpr.and(TerminalContextKeys.focus, TerminalContextKeys.altBufferActive.negate()), + when: ContextKeyExpr.and(TerminalContextKeys.focusInAny, TerminalContextKeys.altBufferActive.negate()), weight: KeybindingWeight.WorkbenchContrib }, precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated), - run: (activeInstance) => activeInstance.scrollToBottom() + run: (xterm) => xterm.scrollToBottom() }); - registerActiveInstanceAction({ + registerActiveXtermAction({ id: TerminalCommandId.ScrollUpLine, title: { value: localize('workbench.action.terminal.scrollUp', "Scroll Up (Line)"), original: 'Scroll Up (Line)' }, keybinding: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.PageUp, linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.UpArrow }, - when: ContextKeyExpr.and(TerminalContextKeys.focus, TerminalContextKeys.altBufferActive.negate()), + when: ContextKeyExpr.and(TerminalContextKeys.focusInAny, TerminalContextKeys.altBufferActive.negate()), weight: KeybindingWeight.WorkbenchContrib }, precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated), - run: (activeInstance) => activeInstance.scrollUpLine() + run: (xterm) => xterm.scrollUpLine() }); - registerActiveInstanceAction({ + registerActiveXtermAction({ id: TerminalCommandId.ScrollUpPage, title: { value: localize('workbench.action.terminal.scrollUpPage', "Scroll Up (Page)"), original: 'Scroll Up (Page)' }, f1: true, @@ -629,38 +656,38 @@ export function registerTerminalActions() { keybinding: { primary: KeyMod.Shift | KeyCode.PageUp, mac: { primary: KeyCode.PageUp }, - when: ContextKeyExpr.and(TerminalContextKeys.focus, TerminalContextKeys.altBufferActive.negate()), + when: ContextKeyExpr.and(TerminalContextKeys.focusInAny, TerminalContextKeys.altBufferActive.negate()), weight: KeybindingWeight.WorkbenchContrib }, precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated), - run: (activeInstance) => activeInstance.scrollUpPage() + run: (xterm) => xterm.scrollUpPage() }); - registerActiveInstanceAction({ + registerActiveXtermAction({ id: TerminalCommandId.ScrollToTop, title: { value: localize('workbench.action.terminal.scrollToTop', "Scroll to Top"), original: 'Scroll to Top' }, keybinding: { primary: KeyMod.CtrlCmd | KeyCode.Home, linux: { primary: KeyMod.Shift | KeyCode.Home }, - when: ContextKeyExpr.and(TerminalContextKeys.focus, TerminalContextKeys.altBufferActive.negate()), + when: ContextKeyExpr.and(TerminalContextKeys.focusInAny, TerminalContextKeys.altBufferActive.negate()), weight: KeybindingWeight.WorkbenchContrib }, precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated), - run: (activeInstance) => activeInstance.scrollToTop() + run: (xterm) => xterm.scrollToTop() }); - registerActiveInstanceAction({ + registerActiveXtermAction({ id: TerminalCommandId.ClearSelection, title: { value: localize('workbench.action.terminal.clearSelection', "Clear Selection"), original: 'Clear Selection' }, keybinding: { primary: KeyCode.Escape, - when: ContextKeyExpr.and(TerminalContextKeys.focus, TerminalContextKeys.textSelected, TerminalContextKeys.notFindVisible), + when: ContextKeyExpr.and(TerminalContextKeys.focusInAny, TerminalContextKeys.textSelected, TerminalContextKeys.notFindVisible), weight: KeybindingWeight.WorkbenchContrib }, precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated), - run: (activeInstance) => { - if (activeInstance.hasSelection()) { - activeInstance.clearSelection(); + run: (xterm) => { + if (xterm.hasSelection()) { + xterm.clearSelection(); } } }); @@ -879,23 +906,25 @@ export function registerTerminalActions() { } }); - registerActiveInstanceAction({ + registerActiveXtermAction({ id: TerminalCommandId.SelectToPreviousLine, title: { value: localize('workbench.action.terminal.selectToPreviousLine', "Select To Previous Line"), original: 'Select To Previous Line' }, precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated), - run: async (activeInstance) => { - activeInstance.xterm?.markTracker.selectToPreviousLine(); - activeInstance.focus(); + run: async (xterm, _, instance) => { + xterm.markTracker.selectToPreviousLine(); + // prefer to call focus on the TerminalInstance for additional accessibility triggers + (instance || xterm).focus(); } }); - registerActiveInstanceAction({ + registerActiveXtermAction({ id: TerminalCommandId.SelectToNextLine, title: { value: localize('workbench.action.terminal.selectToNextLine', "Select To Next Line"), original: 'Select To Next Line' }, precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated), - run: async (activeInstance) => { - activeInstance.xterm?.markTracker.selectToNextLine(); - activeInstance.focus(); + run: async (xterm, _, instance) => { + xterm.markTracker.selectToNextLine(); + // prefer to call focus on the TerminalInstance for additional accessibility triggers + (instance || xterm).focus(); } }); @@ -1152,7 +1181,7 @@ export function registerTerminalActions() { } }); - registerActiveInstanceAction({ + registerActiveXtermAction({ id: TerminalCommandId.SelectAll, title: { value: localize('workbench.action.terminal.selectAll', "Select All"), original: 'Select All' }, precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated), @@ -1165,9 +1194,9 @@ export function registerTerminalActions() { // makes it easier for users to see how it works though. mac: { primary: KeyMod.CtrlCmd | KeyCode.KeyA }, weight: KeybindingWeight.WorkbenchContrib, - when: TerminalContextKeys.focus + when: TerminalContextKeys.focusInAny }], - run: (activeInstance) => activeInstance.selectAll() + run: (xterm) => xterm.selectAll() }); registerTerminalAction({ @@ -1455,42 +1484,48 @@ export function registerTerminalActions() { // Some commands depend on platform features if (BrowserFeatures.clipboard.writeText) { - registerActiveInstanceAction({ + registerActiveXtermAction({ id: TerminalCommandId.CopySelection, title: { value: localize('workbench.action.terminal.copySelection', "Copy Selection"), original: 'Copy Selection' }, // TODO: Why is copy still showing up when text isn't selected? - precondition: ContextKeyExpr.and(ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated), TerminalContextKeys.textSelected), + precondition: ContextKeyExpr.or(TerminalContextKeys.textSelectedInFocused, ContextKeyExpr.and(ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated), TerminalContextKeys.textSelected)), keybinding: [{ primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyC, mac: { primary: KeyMod.CtrlCmd | KeyCode.KeyC }, weight: KeybindingWeight.WorkbenchContrib, - when: ContextKeyExpr.and(TerminalContextKeys.textSelected, TerminalContextKeys.focus) + when: ContextKeyExpr.or( + ContextKeyExpr.and(TerminalContextKeys.textSelected, TerminalContextKeys.focus), + TerminalContextKeys.textSelectedInFocused, + ) }], run: (activeInstance) => activeInstance.copySelection() }); - registerActiveInstanceAction({ + registerActiveXtermAction({ id: TerminalCommandId.CopyAndClearSelection, title: { value: localize('workbench.action.terminal.copyAndClearSelection', "Copy and Clear Selection"), original: 'Copy and Clear Selection' }, - precondition: ContextKeyExpr.and(ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated), TerminalContextKeys.textSelected), + precondition: ContextKeyExpr.or(TerminalContextKeys.textSelectedInFocused, ContextKeyExpr.and(ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated), TerminalContextKeys.textSelected)), keybinding: [{ win: { primary: KeyMod.CtrlCmd | KeyCode.KeyC }, weight: KeybindingWeight.WorkbenchContrib, - when: ContextKeyExpr.and(TerminalContextKeys.textSelected, TerminalContextKeys.focus) + when: ContextKeyExpr.or( + ContextKeyExpr.and(TerminalContextKeys.textSelected, TerminalContextKeys.focus), + TerminalContextKeys.textSelectedInFocused, + ) }], - run: async (activeInstance) => { - await activeInstance.copySelection(); - activeInstance.clearSelection(); + run: async (xterm) => { + await xterm.copySelection(); + xterm.clearSelection(); } }); - registerActiveInstanceAction({ + registerActiveXtermAction({ id: TerminalCommandId.CopySelectionAsHtml, title: { value: localize('workbench.action.terminal.copySelectionAsHtml', "Copy Selection as HTML"), original: 'Copy Selection as HTML' }, f1: true, category, - precondition: ContextKeyExpr.and(ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated), TerminalContextKeys.textSelected), - run: (activeInstance) => activeInstance.copySelection(true) + precondition: ContextKeyExpr.or(TerminalContextKeys.textSelectedInFocused, ContextKeyExpr.and(ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated), TerminalContextKeys.textSelected)), + run: (xterm) => xterm.copySelection(true) }); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts b/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts index 9ddc5d62403..eb04b5e2667 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts @@ -103,7 +103,7 @@ export class TerminalEditor extends EditorPane { // eslint-disable-next-line @typescript-eslint/naming-convention protected createEditor(parent: HTMLElement): void { this._editorInstanceElement = parent; - this._overflowGuardElement = dom.$('.terminal-overflow-guard'); + this._overflowGuardElement = dom.$('.terminal-overflow-guard.terminal-editor'); this._editorInstanceElement.appendChild(this._overflowGuardElement); this._registerListeners(); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index f7826508e51..7a48be17e03 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -17,25 +17,28 @@ import { ErrorNoTelemetry, onUnexpectedError } from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; import { KeyCode } from 'vs/base/common/keyCodes'; import { ISeparator, template } from 'vs/base/common/labels'; -import { Disposable, dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; import { Schemas } from 'vs/base/common/network'; import * as path from 'vs/base/common/path'; -import { isMacintosh, isWindows, OperatingSystem, OS } from 'vs/base/common/platform'; +import { OS, OperatingSystem, isMacintosh, isWindows } from 'vs/base/common/platform'; import { ScrollbarVisibility } from 'vs/base/common/scrollable'; import { withNullAsUndefined } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; import { TabFocus, TabFocusContext } from 'vs/editor/browser/config/tabFocus'; import * as nls from 'vs/nls'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; +import { AudioCue, IAudioCueService } from 'vs/platform/audioCues/browser/audioCueService'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { CodeDataTransfers, containsDragType } from 'vs/platform/dnd/browser/dnd'; +import { FileSystemProviderCapabilities, IFileService } from 'vs/platform/files/common/files'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { ResultKind } from 'vs/platform/keybinding/common/keybindingResolver'; import { ILogService } from 'vs/platform/log/common/log'; import { INotificationService, IPromptChoice, Severity } from 'vs/platform/notification/common/notification'; import { IOpenerService } from 'vs/platform/opener/common/opener'; @@ -45,18 +48,24 @@ import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storag import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IMarkProperties, ITerminalCommand, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities'; import { TerminalCapabilityStoreMultiplexer } from 'vs/platform/terminal/common/capabilities/terminalCapabilityStore'; +import { IEnvironmentVariableCollection, IMergedEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariable'; +import { deserializeEnvironmentVariableCollections } from 'vs/platform/terminal/common/environmentVariableShared'; import { IProcessDataEvent, IProcessPropertyMap, IReconnectionProperties, IShellLaunchConfig, ITerminalDimensionsOverride, ITerminalLaunchError, PosixShellType, ProcessPropertyType, ShellIntegrationStatus, TerminalExitReason, TerminalIcon, TerminalLocation, TerminalSettingId, TerminalShellType, TitleEventSource, WindowsShellType } from 'vs/platform/terminal/common/terminal'; import { formatMessageForTerminal } from 'vs/platform/terminal/common/terminalStrings'; +import { editorBackground } from 'vs/platform/theme/common/colorRegistry'; import { getIconRegistry } from 'vs/platform/theme/common/iconRegistry'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IWorkspaceTrustRequestService } from 'vs/platform/workspace/common/workspaceTrust'; +import { PANEL_BACKGROUND, SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme'; import { IViewDescriptorService, IViewsService, ViewContainerLocation } from 'vs/workbench/common/views'; +import { AccessibilityVerbositySettingId } from 'vs/workbench/contrib/accessibility/browser/accessibilityContribution'; import { TaskSettingId } from 'vs/workbench/contrib/tasks/common/tasks'; import { IRequestAddInstanceToGroupEvent, ITerminalContribution, ITerminalInstance, TerminalDataTransfers } from 'vs/workbench/contrib/terminal/browser/terminal'; import { TerminalLaunchHelpAction } from 'vs/workbench/contrib/terminal/browser/terminalActions'; import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper'; import { TerminalEditorInput } from 'vs/workbench/contrib/terminal/browser/terminalEditorInput'; +import { TerminalExtensionsRegistry } from 'vs/workbench/contrib/terminal/browser/terminalExtensions'; import { getColorClass, getColorStyleElement, getStandardColors } from 'vs/workbench/contrib/terminal/browser/terminalIcon'; import { TerminalProcessManager } from 'vs/workbench/contrib/terminal/browser/terminalProcessManager'; import { showRunRecentQuickPick } from 'vs/workbench/contrib/terminal/browser/terminalRunRecentQuickPick'; @@ -64,31 +73,21 @@ import { ITerminalStatusList, TerminalStatus, TerminalStatusList } from 'vs/work import { getTerminalResourcesFromDragEvent, getTerminalUri } from 'vs/workbench/contrib/terminal/browser/terminalUri'; import { TerminalWidgetManager } from 'vs/workbench/contrib/terminal/browser/widgets/widgetManager'; import { LineDataEventAddon } from 'vs/workbench/contrib/terminal/browser/xterm/lineDataEventAddon'; -import { XtermTerminal } from 'vs/workbench/contrib/terminal/browser/xterm/xtermTerminal'; +import { XtermTerminal, getXtermScaledDimensions } from 'vs/workbench/contrib/terminal/browser/xterm/xtermTerminal'; import { IEnvironmentVariableInfo } from 'vs/workbench/contrib/terminal/common/environmentVariable'; -import { deserializeEnvironmentVariableCollections } from 'vs/platform/terminal/common/environmentVariableShared'; import { getCommandHistory, getDirectoryHistory } from 'vs/workbench/contrib/terminal/common/history'; -import { DEFAULT_COMMANDS_TO_SKIP_SHELL, ITerminalProcessManager, ITerminalProfileResolverService, ProcessState, TerminalCommandId, TERMINAL_CREATION_COMMANDS, TERMINAL_VIEW_ID } from 'vs/workbench/contrib/terminal/common/terminal'; +import { DEFAULT_COMMANDS_TO_SKIP_SHELL, ITerminalProcessManager, ITerminalProfileResolverService, ProcessState, TERMINAL_CREATION_COMMANDS, TERMINAL_VIEW_ID, TerminalCommandId } from 'vs/workbench/contrib/terminal/common/terminal'; +import { TERMINAL_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; import { TerminalContextKeys } from 'vs/workbench/contrib/terminal/common/terminalContextKey'; +import { getWorkspaceForTerminal, preparePathForShell } from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { IWorkbenchLayoutService, Position } from 'vs/workbench/services/layout/browser/layoutService'; import { IPathService } from 'vs/workbench/services/path/common/pathService'; import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences'; -import type { IMarker, Terminal as XTermTerminal } from 'xterm'; -import { IAudioCueService, AudioCue } from 'vs/platform/audioCues/browser/audioCueService'; -import { FileSystemProviderCapabilities, IFileService } from 'vs/platform/files/common/files'; -import { getWorkspaceForTerminal, preparePathForShell } from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; -import { IEnvironmentVariableCollection, IMergedEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariable'; import { ISimpleSelectedSuggestion } from 'vs/workbench/services/suggest/browser/simpleSuggestWidget'; -import { TERMINAL_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; -import { editorBackground } from 'vs/platform/theme/common/colorRegistry'; -import { PANEL_BACKGROUND, SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme'; -import { TerminalExtensionsRegistry } from 'vs/workbench/contrib/terminal/browser/terminalExtensions'; -import { ResolvedKeybinding } from 'vs/base/common/keybindings'; -import { ResultKind } from 'vs/platform/keybinding/common/keybindingResolver'; -import { AccessibilityVerbositySettingId } from 'vs/workbench/contrib/accessibility/browser/accessibilityContribution'; +import type { IMarker, Terminal as XTermTerminal } from 'xterm'; const enum Constants { /** @@ -105,19 +104,6 @@ const enum Constants { } let xtermConstructor: Promise | undefined; -function getXtermConstructor(keybinding?: ResolvedKeybinding): Promise { - if (xtermConstructor) { - return xtermConstructor; - } - xtermConstructor = Promises.withAsyncBody(async (resolve) => { - const Terminal = (await import('xterm')).Terminal; - // Localize strings - Terminal.strings.promptLabel = nls.localize('terminal.integrated.a11yPromptLabel', 'Terminal input'); - Terminal.strings.tooMuchOutput = keybinding ? nls.localize('terminal.integrated.useAccessibleBuffer', 'Use the accessible buffer {0} to manually review output', keybinding.getLabel()) : nls.localize('terminal.integrated.useAccessibleBufferNoKb', 'Use the Terminal: Focus Accessible Buffer command to manually review output'); - resolve(Terminal); - }); - return xtermConstructor; -} interface ICanvasDimensions { width: number; @@ -642,28 +628,15 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } const font = this.xterm ? this.xterm.getFont() : this._configHelper.getFont(); - if (!font.charWidth || !font.charHeight) { + const newRC = getXtermScaledDimensions(font, dimension.width, dimension.height); + if (!newRC) { this._setLastKnownColsAndRows(); return null; } - // Because xterm.js converts from CSS pixels to actual pixels through - // the use of canvas, window.devicePixelRatio needs to be used here in - // order to be precise. font.charWidth/charHeight alone as insufficient - // when window.devicePixelRatio changes. - const scaledWidthAvailable = dimension.width * window.devicePixelRatio; - - const scaledCharWidth = font.charWidth * window.devicePixelRatio + font.letterSpacing; - const newCols = Math.max(Math.floor(scaledWidthAvailable / scaledCharWidth), 1); - - const scaledHeightAvailable = dimension.height * window.devicePixelRatio; - const scaledCharHeight = Math.ceil(font.charHeight * window.devicePixelRatio); - const scaledLineHeight = Math.floor(scaledCharHeight * font.lineHeight); - const newRows = Math.max(Math.floor(scaledHeightAvailable / scaledLineHeight), 1); - - if (this._cols !== newCols || this._rows !== newRows) { - this._cols = newCols; - this._rows = newRows; + if (this._cols !== newRC.cols || this._rows !== newRC.rows) { + this._cols = newRC.cols; + this._rows = newRC.rows; this._fireMaximumDimensionsChanged(); } @@ -704,11 +677,26 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { get persistentProcessId(): number | undefined { return this._processManager.persistentProcessId; } get shouldPersist(): boolean { return this._processManager.shouldPersist && !this.shellLaunchConfig.isTransient && (!this.reconnectionProperties || this._configurationService.getValue(TaskSettingId.Reconnection) === true); } + public static getXtermConstructor(keybindingService: IKeybindingService, contextKeyService: IContextKeyService) { + const keybinding = keybindingService.lookupKeybinding(TerminalCommandId.FocusAccessibleBuffer, contextKeyService); + if (xtermConstructor) { + return xtermConstructor; + } + xtermConstructor = Promises.withAsyncBody(async (resolve) => { + const Terminal = (await import('xterm')).Terminal; + // Localize strings + Terminal.strings.promptLabel = nls.localize('terminal.integrated.a11yPromptLabel', 'Terminal input'); + Terminal.strings.tooMuchOutput = keybinding ? nls.localize('terminal.integrated.useAccessibleBuffer', 'Use the accessible buffer {0} to manually review output', keybinding.getLabel()) : nls.localize('terminal.integrated.useAccessibleBufferNoKb', 'Use the Terminal: Focus Accessible Buffer command to manually review output'); + resolve(Terminal); + }); + return xtermConstructor; + } + /** * Create xterm.js instance and attach data listeners. */ protected async _createXterm(): Promise { - const Terminal = await getXtermConstructor(this._keybindingService.lookupKeybinding(TerminalCommandId.FocusAccessibleBuffer, this._contextKeyService)); + const Terminal = await TerminalInstance.getXtermConstructor(this._keybindingService, this._contextKeyService); if (this._isDisposed) { throw new ErrorNoTelemetry('Terminal disposed of during xterm.js creation'); } @@ -1072,25 +1060,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { async copySelection(asHtml?: boolean, command?: ITerminalCommand): Promise { const xterm = await this._xtermReadyPromise; - if (this.hasSelection() || (asHtml && command)) { - if (asHtml) { - const textAsHtml = await xterm.getSelectionAsHtml(command); - function listener(e: any) { - if (!e.clipboardData.types.includes('text/plain')) { - e.clipboardData.setData('text/plain', command?.getOutput() ?? ''); - } - e.clipboardData.setData('text/html', textAsHtml); - e.preventDefault(); - } - document.addEventListener('copy', listener); - document.execCommand('copy'); - document.removeEventListener('copy', listener); - } else { - await this._clipboardService.writeText(xterm.raw.getSelection()); - } - } else { - this._notificationService.warn(nls.localize('terminal.integrated.copySelection.noSelection', 'The terminal has no selection to copy')); - } + await xterm.copySelection(asHtml, command); } get selection(): string | undefined { @@ -1101,12 +1071,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this.xterm?.raw.clearSelection(); } - selectAll(): void { - // Focus here to ensure the terminal context key is set - this.xterm?.raw.focus(); - this.xterm?.raw.selectAll(); - } - private _refreshAltBufferContextKey() { this._terminalAltBufferActiveContextKey.set(!!(this.xterm && this.xterm.raw.buffer.active === this.xterm.raw.buffer.alternate)); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 4a2e36cceca..08dd70e1fad 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -30,7 +30,7 @@ import { ThemeIcon } from 'vs/base/common/themables'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { VirtualWorkspaceContext } from 'vs/workbench/common/contextkeys'; import { IEditableData, IViewsService } from 'vs/workbench/common/views'; -import { ICreateTerminalOptions, IRequestAddInstanceToGroupEvent, ITerminalEditorService, ITerminalGroup, ITerminalGroupService, ITerminalInstance, ITerminalInstanceHost, ITerminalInstanceService, ITerminalLocationOptions, ITerminalService, ITerminalServiceNativeDelegate, TerminalConnectionState, TerminalEditorLocation } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { ICreateTerminalOptions, IDetachedXTermOptions, IDetachedXtermTerminal, IRequestAddInstanceToGroupEvent, ITerminalEditorService, ITerminalGroup, ITerminalGroupService, ITerminalInstance, ITerminalInstanceHost, ITerminalInstanceService, ITerminalLocationOptions, ITerminalService, ITerminalServiceNativeDelegate, IXtermTerminal, TerminalConnectionState, TerminalEditorLocation } from 'vs/workbench/contrib/terminal/browser/terminal'; import { getCwdForSplit } from 'vs/workbench/contrib/terminal/browser/terminalActions'; import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper'; import { TerminalEditorInput } from 'vs/workbench/contrib/terminal/browser/terminalEditorInput'; @@ -47,12 +47,17 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { ILifecycleService, ShutdownReason, StartupKind, WillShutdownEvent } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; +import { XtermTerminal } from 'vs/workbench/contrib/terminal/browser/xterm/xtermTerminal'; +import { TerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminalInstance'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { TerminalCapabilityStore } from 'vs/platform/terminal/common/capabilities/terminalCapabilityStore'; export class TerminalService implements ITerminalService { declare _serviceBrand: undefined; private _hostActiveTerminals: Map = new Map(); + private _detachedXterms = new Set(); private _terminalEditorActive: IContextKey; private readonly _terminalShellTypeContextKey: IContextKey; @@ -80,6 +85,9 @@ export class TerminalService implements ITerminalService { get instances(): ITerminalInstance[] { return this._terminalGroupService.instances.concat(this._terminalEditorService.instances); } + get detachedXterms(): Iterable { + return this._detachedXterms; + } private _reconnectedTerminals: Map = new Map(); getReconnectedTerminals(reconnectionOwner: string): ITerminalInstance[] | undefined { @@ -163,7 +171,8 @@ export class TerminalService implements ITerminalService { @IExtensionService private readonly _extensionService: IExtensionService, @INotificationService private readonly _notificationService: INotificationService, @IWorkspaceContextService private readonly _workspaceContextService: IWorkspaceContextService, - @ICommandService private readonly _commandService: ICommandService + @ICommandService private readonly _commandService: ICommandService, + @IKeybindingService private readonly _keybindingService: IKeybindingService ) { this._configHelper = this._instantiationService.createInstance(TerminalConfigHelper); // the below avoids having to poll routinely. @@ -971,6 +980,31 @@ export class TerminalService implements ITerminalService { return this._createTerminal(shellLaunchConfig, location, options); } + async createDetachedXterm(options: IDetachedXTermOptions): Promise { + const ctor = await TerminalInstance.getXtermConstructor(this._keybindingService, this._contextKeyService); + const instance = this._instantiationService.createInstance( + XtermTerminal, + ctor, + this._configHelper, + options.cols, + options.rows, + options.colorProvider, + options.capabilities || new TerminalCapabilityStore(), + '', + undefined, + false, + ); + + if (options.readonly) { + instance.raw.attachCustomKeyEventHandler(() => false); + } + + this._detachedXterms.add(instance); + instance.onDidDispose(() => this._detachedXterms.delete(instance)); + + return instance; + } + private async _resolveCwd(shellLaunchConfig: IShellLaunchConfig, splitActiveTerminal: boolean, options?: ICreateTerminalOptions): Promise { const cwd = shellLaunchConfig.cwd; if (!cwd) { diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts index c6f4d4ea87f..a188ac5ea5a 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts @@ -10,6 +10,7 @@ import type { Unicode11Addon as Unicode11AddonType } from 'xterm-addon-unicode11 import type { WebglAddon as WebglAddonType } from 'xterm-addon-webgl'; import type { SerializeAddon as SerializeAddonType } from 'xterm-addon-serialize'; import type { ImageAddon as ImageAddonType } from 'xterm-addon-image'; +import * as dom from 'vs/base/browser/dom'; import { IXtermCore } from 'vs/workbench/contrib/terminal/browser/xterm-private'; import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper'; @@ -18,7 +19,7 @@ import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { IShellIntegration, TerminalSettingId } from 'vs/platform/terminal/common/terminal'; import { ITerminalFont } from 'vs/workbench/contrib/terminal/common/terminal'; import { isSafari } from 'vs/base/browser/browser'; -import { IMarkTracker, IInternalXtermTerminal, IXtermTerminal, ISuggestController, IXtermColorProvider, XtermTerminalConstants } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { IMarkTracker, IInternalXtermTerminal, IXtermTerminal, ISuggestController, IXtermColorProvider, XtermTerminalConstants, IXtermAttachToElementOptions, IDetachedXtermTerminal } from 'vs/workbench/contrib/terminal/browser/terminal'; import { ILogService } from 'vs/platform/log/common/log'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { TerminalStorageKeys } from 'vs/workbench/contrib/terminal/common/terminalStorageKeys'; @@ -35,7 +36,9 @@ import { ITerminalCapabilityStore, ITerminalCommand, TerminalCapability } from ' import { Emitter } from 'vs/base/common/event'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { SuggestAddon } from 'vs/workbench/contrib/terminal/browser/xterm/suggestAddon'; -import { IContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { TerminalContextKeys } from 'vs/workbench/contrib/terminal/common/terminalContextKey'; +import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; const enum RenderConstants { /** @@ -108,7 +111,7 @@ function getFullBufferLineAsString(lineIndex: number, buffer: IBuffer): { lineDa * Wraps the xterm object with additional functionality. Interaction with the backing process is out * of the scope of this class. */ -export class XtermTerminal extends DisposableStore implements IXtermTerminal, IInternalXtermTerminal { +export class XtermTerminal extends DisposableStore implements IXtermTerminal, IDetachedXtermTerminal, IInternalXtermTerminal { /** The raw xterm.js instance */ readonly raw: RawXtermTerminal; @@ -123,14 +126,14 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II } private _core: IXtermCore; private static _suggestedRendererType: 'canvas' | 'dom' | undefined = undefined; - private _container?: HTMLElement; + private _attached?: { container: HTMLElement; options: IXtermAttachToElementOptions }; // Always on addons private _markNavigationAddon: MarkNavigationAddon; private _shellIntegrationAddon: ShellIntegrationAddon; private _decorationAddon: DecorationAddon; - private _suggestAddon: SuggestAddon; + private _suggestAddon?: SuggestAddon; // Optional addons private _canvasAddon?: CanvasAddonType; @@ -139,6 +142,9 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II private _webglAddon?: WebglAddonType; private _serializeAddon?: SerializeAddonType; private _imageAddon?: ImageAddonType; + private readonly _attachedDisposables = this.add(new DisposableStore()); + private readonly _anyTerminalFocusContextKey: IContextKey; + private readonly _anyFocusedTerminalHasSelection: IContextKey; private _lastFindResult: { resultIndex: number; resultCount: number } | undefined; get findResult(): { resultIndex: number; resultCount: number } | undefined { return this._lastFindResult; } @@ -156,6 +162,10 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II readonly onDidChangeFindResults = this._onDidChangeFindResults.event; private readonly _onDidChangeSelection = new Emitter(); readonly onDidChangeSelection = this._onDidChangeSelection.event; + private readonly _onDidChangeFocus = new Emitter(); + readonly onDidChangeFocus = this._onDidChangeFocus.event; + private readonly _onDidDispose = new Emitter(); + readonly onDidDispose = this._onDidDispose.event; get markTracker(): IMarkTracker { return this._markNavigationAddon; } get shellIntegration(): IShellIntegration { return this._shellIntegrationAddon; } @@ -169,6 +179,10 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II return createImageBitmap(canvas); } + public get isFocused() { + return !!this.raw.element?.contains(document.activeElement); + } + /** * @param xtermCtor The xterm.js constructor, this is passed in so it can be fetched lazily * outside of this class such that {@link raw} is not nullable. @@ -181,7 +195,7 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II private readonly _backgroundColorProvider: IXtermColorProvider, private readonly _capabilities: ITerminalCapabilityStore, shellIntegrationNonce: string, - private readonly _terminalSuggestWidgetVisibleContextKey: IContextKey, + private readonly _terminalSuggestWidgetVisibleContextKey: IContextKey | undefined, disableShellIntegrationReporting: boolean, @IConfigurationService private readonly _configurationService: IConfigurationService, @IInstantiationService private readonly _instantiationService: IInstantiationService, @@ -189,7 +203,9 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II @INotificationService private readonly _notificationService: INotificationService, @IStorageService private readonly _storageService: IStorageService, @IThemeService private readonly _themeService: IThemeService, - @ITelemetryService private readonly _telemetryService: ITelemetryService + @ITelemetryService private readonly _telemetryService: ITelemetryService, + @IClipboardService private readonly _clipboardService: IClipboardService, + @IContextKeyService contextKeyService: IContextKeyService, ) { super(); const font = this._configHelper.getFont(undefined, true); @@ -242,7 +258,12 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II this.add(this._themeService.onDidColorThemeChange(theme => this._updateTheme(theme))); // Refire events - this.add(this.raw.onSelectionChange(() => this._onDidChangeSelection.fire())); + this.add(this.raw.onSelectionChange(() => { + this._onDidChangeSelection.fire(); + if (this.isFocused) { + this._anyFocusedTerminalHasSelection.set(this.raw.hasSelection()); + } + })); // Load addons this._updateUnicodeVersion(); @@ -255,14 +276,29 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II this._shellIntegrationAddon = this._instantiationService.createInstance(ShellIntegrationAddon, shellIntegrationNonce, disableShellIntegrationReporting, this._telemetryService); this.raw.loadAddon(this._shellIntegrationAddon); + this._anyTerminalFocusContextKey = TerminalContextKeys.focusInAny.bindTo(contextKeyService); + this._anyFocusedTerminalHasSelection = TerminalContextKeys.textSelectedInFocused.bindTo(contextKeyService); + // Load the suggest addon, this should be loaded regardless of the setting as the sequences // may still come in - this._suggestAddon = this._instantiationService.createInstance(SuggestAddon, this._terminalSuggestWidgetVisibleContextKey); - this.raw.loadAddon(this._suggestAddon); - this._suggestAddon.onAcceptedCompletion(async text => { - this._onDidRequestFocus.fire(); - this._onDidRequestSendText.fire(text); - }); + if (this._terminalSuggestWidgetVisibleContextKey) { + this._suggestAddon = this._instantiationService.createInstance(SuggestAddon, this._terminalSuggestWidgetVisibleContextKey); + this.raw.loadAddon(this._suggestAddon); + this._suggestAddon.onAcceptedCompletion(async text => { + this._onDidRequestFocus.fire(); + this._onDidRequestSendText.fire(text); + }); + } + } + + async getContentsAsHtml(): Promise { + if (!this._serializeAddon) { + const Addon = await this._getSerializeAddonConstructor(); + this._serializeAddon = new Addon(); + this.raw.loadAddon(this._serializeAddon); + } + + return this._serializeAddon.serializeAsHTML(); } async getSelectionAsHtml(command?: ITerminalCommand): Promise { @@ -286,22 +322,50 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II return result; } - attachToElement(container: HTMLElement): HTMLElement { - if (!this._container) { + attachToElement(container: HTMLElement, partialOptions?: Partial): HTMLElement { + const options: IXtermAttachToElementOptions = { enableGpu: true, ...partialOptions }; + if (!this._attached) { this.raw.open(container); } + // TODO: Move before open to the DOM renderer doesn't initialize - if (this._shouldLoadWebgl()) { - this._enableWebglRenderer(); - } else if (this._shouldLoadCanvas()) { - this._enableCanvasRenderer(); + if (options.enableGpu) { + if (this._shouldLoadWebgl()) { + this._enableWebglRenderer(); + } else if (this._shouldLoadCanvas()) { + this._enableCanvasRenderer(); + } } - this._suggestAddon.setContainer(container); + if (!this.raw.element || !this.raw.textarea) { + throw new Error('xterm elements not set after open'); + } - this._container = container; + const ad = this._attachedDisposables; + ad.clear(); + ad.add(dom.addDisposableListener(this.raw.textarea, 'focus', () => this._setFocused(true))); + ad.add(dom.addDisposableListener(this.raw.textarea, 'blur', () => this._setFocused(false))); + ad.add(dom.addDisposableListener(this.raw.textarea, 'focusout', () => this._setFocused(false))); + + this._suggestAddon?.setContainer(container); + + this._attached = { container, options }; // Screen must be created at this point as xterm.open is called - return this._container.querySelector('.xterm-screen')!; + return this._attached?.container.querySelector('.xterm-screen')!; + } + + private _setFocused(isFocused: boolean) { + this._onDidChangeFocus.fire(isFocused); + this._anyTerminalFocusContextKey.set(isFocused); + this._anyFocusedTerminalHasSelection.set(isFocused && this.raw.hasSelection()); + } + + write(data: string | Uint8Array): void { + this.raw.write(data); + } + + resize(columns: number, rows: number): void { + this.raw.resize(columns, rows); } updateConfig(): void { @@ -324,14 +388,16 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II this.raw.options.wordSeparator = config.wordSeparators; this.raw.options.customGlyphs = config.customGlyphs; this.raw.options.smoothScrollDuration = config.smoothScrolling ? RenderConstants.SmoothScrollDuration : 0; - if (this._shouldLoadWebgl()) { - this._enableWebglRenderer(); - } else { - this._disposeOfWebglRenderer(); - if (this._shouldLoadCanvas()) { - this._enableCanvasRenderer(); + if (this._attached?.options.enableGpu) { + if (this._shouldLoadWebgl()) { + this._enableWebglRenderer(); } else { - this._disposeOfCanvasRenderer(); + this._disposeOfWebglRenderer(); + if (this._shouldLoadCanvas()) { + this._enableCanvasRenderer(); + } else { + this._disposeOfCanvasRenderer(); + } } } this._refreshImageAddon(); @@ -496,6 +562,45 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II this._capabilities.get(TerminalCapability.CommandDetection)?.handleCommandStart(); } + hasSelection(): boolean { + return this.raw.hasSelection(); + } + + clearSelection(): void { + this.raw.clearSelection(); + } + + selectAll(): void { + this.raw.focus(); + this.raw.selectAll(); + } + + focus(): void { + this.raw.focus(); + } + + async copySelection(asHtml?: boolean, command?: ITerminalCommand): Promise { + if (this.hasSelection() || (asHtml && command)) { + if (asHtml) { + const textAsHtml = await this.getSelectionAsHtml(command); + function listener(e: any) { + if (!e.clipboardData.types.includes('text/plain')) { + e.clipboardData.setData('text/plain', command?.getOutput() ?? ''); + } + e.clipboardData.setData('text/html', textAsHtml); + e.preventDefault(); + } + document.addEventListener('copy', listener); + document.execCommand('copy'); + document.removeEventListener('copy', listener); + } else { + await this._clipboardService.writeText(this.raw.getSelection()); + } + } else { + this._notificationService.warn(localize('terminal.integrated.copySelection.noSelection', 'The terminal has no selection to copy')); + } + } + private _setCursorBlink(blink: boolean): void { if (this.raw.options.cursorBlink !== blink) { this.raw.options.cursorBlink = blink; @@ -765,4 +870,33 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II _writeText(data: string): void { this.raw.write(data); } + + public override dispose(): void { + this._anyTerminalFocusContextKey.reset(); + this._anyFocusedTerminalHasSelection.reset(); + this._onDidDispose.fire(); + super.dispose(); + } +} + +export function getXtermScaledDimensions(font: ITerminalFont, width: number, height: number) { + if (!font.charWidth || !font.charHeight) { + return null; + } + + // Because xterm.js converts from CSS pixels to actual pixels through + // the use of canvas, window.devicePixelRatio needs to be used here in + // order to be precise. font.charWidth/charHeight alone as insufficient + // when window.devicePixelRatio changes. + const scaledWidthAvailable = width * window.devicePixelRatio; + + const scaledCharWidth = font.charWidth * window.devicePixelRatio + font.letterSpacing; + const cols = Math.max(Math.floor(scaledWidthAvailable / scaledCharWidth), 1); + + const scaledHeightAvailable = height * window.devicePixelRatio; + const scaledCharHeight = Math.ceil(font.charHeight * window.devicePixelRatio); + const scaledLineHeight = Math.floor(scaledCharHeight * font.lineHeight); + const rows = Math.max(Math.floor(scaledHeightAvailable / scaledLineHeight), 1); + + return { rows, cols }; } diff --git a/src/vs/workbench/contrib/terminal/common/terminalContextKey.ts b/src/vs/workbench/contrib/terminal/common/terminalContextKey.ts index a3eb8693d01..1d480dbd649 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalContextKey.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalContextKey.ts @@ -14,6 +14,7 @@ export const enum TerminalContextKeyStrings { HasFixedWidth = 'terminalHasFixedWidth', ProcessSupported = 'terminalProcessSupported', Focus = 'terminalFocus', + FocusInAny = 'terminalFocusInAny', AccessibleBufferFocus = 'terminalAccessibleBufferFocus', EditorFocus = 'terminalEditorFocus', TabsFocus = 'terminalTabsFocus', @@ -26,6 +27,7 @@ export const enum TerminalContextKeyStrings { A11yTreeFocus = 'terminalA11yTreeFocus', ViewShowing = 'terminalViewShowing', TextSelected = 'terminalTextSelected', + TextSelectedInFocused = 'terminalTextSelectedInFocused', FindVisible = 'terminalFindVisible', FindInputFocused = 'terminalFindInputFocused', FindFocused = 'terminalFindFocused', @@ -43,6 +45,9 @@ export namespace TerminalContextKeys { /** Whether the terminal is focused. */ export const focus = new RawContextKey(TerminalContextKeyStrings.Focus, false, localize('terminalFocusContextKey', "Whether the terminal is focused.")); + /** Whether any terminal is focused, including detached terminals used in other UI. */ + export const focusInAny = new RawContextKey(TerminalContextKeyStrings.FocusInAny, false, localize('terminalFocusInAnyContextKey', "Whether any terminal is focused, including detached terminals used in other UI.")); + /** Whether the accessible buffer is focused. */ export const accessibleBufferFocus = new RawContextKey(TerminalContextKeyStrings.AccessibleBufferFocus, false, localize('terminalAccessibleBufferFocusContextKey', "Whether the terminal accessible buffer is focused.")); @@ -94,6 +99,9 @@ export namespace TerminalContextKeys { /** Whether text is selected in the active terminal. */ export const textSelected = new RawContextKey(TerminalContextKeyStrings.TextSelected, false, localize('terminalTextSelectedContextKey', "Whether text is selected in the active terminal.")); + /** Whether text is selected in a focused terminal. `textSelected` counts text selected in an active in a terminal view or an editor, where `textSelectedInFocused` simply counts text in an element with DOM focus. */ + export const textSelectedInFocused = new RawContextKey(TerminalContextKeyStrings.TextSelectedInFocused, false, localize('terminalTextSelectedInFocusedContextKey', "Whether text is selected in a focused terminal.")); + /** Whether text is NOT selected in the active terminal. */ export const notTextSelected = textSelected.toNegated(); diff --git a/src/vs/workbench/contrib/terminal/test/browser/xterm/xtermTerminal.test.ts b/src/vs/workbench/contrib/terminal/test/browser/xterm/xtermTerminal.test.ts index a9c5ff1af01..f3e30380a60 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/xterm/xtermTerminal.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/xterm/xtermTerminal.test.ts @@ -30,6 +30,7 @@ import { TestLifecycleService } from 'vs/workbench/test/browser/workbenchTestSer import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService'; import { Color, RGBA } from 'vs/base/common/color'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; class TestWebglAddon implements WebglAddon { static shouldThrow = false; @@ -117,6 +118,7 @@ suite('XtermTerminal', () => { instantiationService.stub(IViewDescriptorService, viewDescriptorService); instantiationService.stub(IContextMenuService, instantiationService.createInstance(ContextMenuService)); instantiationService.stub(ILifecycleService, new TestLifecycleService()); + instantiationService.stub(IContextKeyService, new MockContextKeyService()); configHelper = instantiationService.createInstance(TerminalConfigHelper); xterm = instantiationService.createInstance(TestXtermTerminal, Terminal, configHelper, 80, 30, { getBackgroundColor: () => undefined }, new TerminalCapabilityStore(), '', new MockContextKeyService().createKey('', true)!, true); @@ -251,7 +253,7 @@ suite('XtermTerminal', () => { // Open xterm as otherwise the webgl addon won't activate const container = document.createElement('div'); - xterm.raw.open(container); + xterm.attachToElement(container); // Auto should activate the webgl addon await configurationService.setUserConfiguration('terminal', { integrated: { ...defaultTerminalConfig, gpuAcceleration: 'auto' } }); diff --git a/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts b/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts index 8ee82c2813d..e1945415abf 100644 --- a/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts +++ b/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts @@ -7,6 +7,7 @@ import * as assert from 'assert'; import { isWindows } from 'vs/base/common/platform'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { ContextMenuService } from 'vs/platform/contextview/browser/contextMenuService'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; @@ -56,6 +57,7 @@ suite('Buffer Content Tracker', () => { instantiationService.stub(ILogService, new NullLogService()); instantiationService.stub(IContextMenuService, instantiationService.createInstance(ContextMenuService)); instantiationService.stub(ILifecycleService, new TestLifecycleService()); + instantiationService.stub(IContextKeyService, new MockContextKeyService()); configHelper = instantiationService.createInstance(TerminalConfigHelper); capabilities = new TerminalCapabilityStore(); if (!isWindows) { diff --git a/src/vs/workbench/contrib/testing/browser/media/testing.css b/src/vs/workbench/contrib/testing/browser/media/testing.css index e42b0ddbdfe..11ae1f8784f 100644 --- a/src/vs/workbench/contrib/testing/browser/media/testing.css +++ b/src/vs/workbench/contrib/testing/browser/media/testing.css @@ -186,8 +186,8 @@ border-bottom-width: 2px; } -.monaco-editor .zone-widget.test-output-peek .test-output-peek-message-container, -.monaco-editor .zone-widget.test-output-peek .test-output-peek-tree { +.test-output-peek-message-container, +.test-output-peek-tree { height: 100%; } diff --git a/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts b/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts index 3eec54c4a97..5fc25be8ed2 100644 --- a/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts +++ b/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts @@ -34,7 +34,6 @@ import 'vs/css!./testingOutputPeek'; import { ICodeEditor, IDiffEditorConstructionOptions, isCodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorAction2 } from 'vs/editor/browser/editorExtensions'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; -import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; import { EmbeddedCodeEditorWidget, EmbeddedDiffEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget'; import { IDiffEditorOptions, IEditorOptions } from 'vs/editor/common/config/editorOptions'; @@ -44,7 +43,7 @@ import { IEditor, IEditorContribution, ScrollType } from 'vs/editor/common/edito import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { IResolvedTextEditorModel, ITextModelService } from 'vs/editor/common/services/resolverService'; import { MarkdownRenderer } from 'vs/editor/contrib/markdownRenderer/browser/markdownRenderer'; -import { IPeekViewService, PeekViewWidget, peekViewTitleForeground, peekViewTitleInfoForeground } from 'vs/editor/contrib/peekView/browser/peekView'; +import { IPeekViewService, PeekViewWidget, peekViewResultsBackground, peekViewTitleForeground, peekViewTitleInfoForeground } from 'vs/editor/contrib/peekView/browser/peekView'; import { localize } from 'vs/nls'; import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { MenuEntryActionViewItem, createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; @@ -62,10 +61,17 @@ import { INotificationService } from 'vs/platform/notification/common/notificati import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities'; +import { TerminalCapabilityStore } from 'vs/platform/terminal/common/capabilities/terminalCapabilityStore'; import { IColorTheme, IThemeService } from 'vs/platform/theme/common/themeService'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IViewPaneOptions, ViewPane } from 'vs/workbench/browser/parts/views/viewPane'; import { EditorModel } from 'vs/workbench/common/editor/editorModel'; -import { IViewDescriptorService, IViewsService } from 'vs/workbench/common/views'; +import { PANEL_BACKGROUND, SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme'; +import { IViewDescriptorService, IViewsService, ViewContainerLocation } from 'vs/workbench/common/views'; +import { IDetachedXtermTerminal, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { getXtermScaledDimensions } from 'vs/workbench/contrib/terminal/browser/xterm/xtermTerminal'; +import { TERMINAL_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; import { flatTestItemDelimiter } from 'vs/workbench/contrib/testing/browser/explorerProjections/display'; import { getTestItemContextOverlay } from 'vs/workbench/contrib/testing/browser/explorerProjections/testItemContextOverlay'; import * as icons from 'vs/workbench/contrib/testing/browser/icons'; @@ -719,11 +725,12 @@ class TestResultsViewContent extends Disposable { this.splitView = new SplitView(containerElement, { orientation: Orientation.HORIZONTAL }); const { historyVisible, showRevealLocationOnMessages } = this.options; + const isInPeekView = this.editor !== undefined; const messageContainer = dom.append(containerElement, dom.$('.test-output-peek-message-container')); this.contentProviders = [ this._register(this.instantiationService.createInstance(DiffContentProvider, this.editor, messageContainer)), this._register(this.instantiationService.createInstance(MarkdownTestMessagePeek, messageContainer)), - this._register(this.instantiationService.createInstance(PlainTextMessagePeek, this.editor, messageContainer)), + this._register(this.instantiationService.createInstance(PlainTextMessagePeek, messageContainer, isInPeekView)), ]; const treeContainer = dom.append(containerElement, dom.$('.test-output-peek-tree')); @@ -1139,65 +1146,155 @@ class MarkdownTestMessagePeek extends Disposable implements IPeekOutputRenderer } } + class PlainTextMessagePeek extends Disposable implements IPeekOutputRenderer { - private readonly widget = this._register(new MutableDisposable()); - private readonly model = this._register(new MutableDisposable()); - private dimension?: dom.IDimension; + private dimensions?: dom.IDimension; + private readonly terminalCwd = this._register(new MutableObservableValue('')); + + /** Active terminal instance. */ + private readonly terminal = this._register(new MutableDisposable()); + /** Listener for streaming result data */ + private readonly outputDataListener = this._register(new MutableDisposable()); constructor( - private readonly editor: ICodeEditor | undefined, private readonly container: HTMLElement, - @IInstantiationService private readonly instantiationService: IInstantiationService, - @ITextModelService private readonly modelService: ITextModelService, + private readonly isInPeekView: boolean, + @ITestResultService private readonly resultService: ITestResultService, + @ITerminalService private readonly terminalService: ITerminalService, + @IViewDescriptorService private readonly viewDescriptorService: IViewDescriptorService, + @IWorkspaceContextService private readonly workspaceContext: IWorkspaceContextService, ) { super(); } + private async makeTerminal() { + const prev = this.terminal.value; + if (prev) { + prev.clearBuffer(); + prev.clearSearchDecorations(); + // clearBuffer tries to retain the prompt line, but this doesn't exist for tests. + // So clear the screen (J) and move to home (H) to ensure previous data is cleaned up. + prev.write(`\x1b[2J\x1b[0;0H`); + return prev; + } + + const capabilities = new TerminalCapabilityStore(); + const cwd = this.terminalCwd; + capabilities.add(TerminalCapability.CwdDetection, { + type: TerminalCapability.CwdDetection, + get cwds() { return [cwd.value]; }, + onDidChangeCwd: cwd.onDidChange, + getCwd: () => cwd.value, + updateCwd: () => { }, + }); + + return this.terminal.value = await this.terminalService.createDetachedXterm({ + rows: 10, + cols: 80, + readonly: true, + capabilities, + colorProvider: { + getBackgroundColor: theme => { + const terminalBackground = theme.getColor(TERMINAL_BACKGROUND_COLOR); + if (terminalBackground) { + return terminalBackground; + } + if (this.isInPeekView) { + return theme.getColor(peekViewResultsBackground); + } + const location = this.viewDescriptorService.getViewLocationById(Testing.ResultsViewId); + return location === ViewContainerLocation.Panel + ? theme.getColor(PANEL_BACKGROUND) + : theme.getColor(SIDE_BAR_BACKGROUND); + }, + } + }); + } + public async update(subject: InspectSubject) { - let uri: URI; + this.outputDataListener.clear(); + if (subject instanceof MessageSubject) { const message = subject.messages[subject.messageIndex]; if (isDiffable(message) || typeof message.message !== 'string') { return this.clear(); } - uri = subject.messageUri; + + this.updateCwd(subject.test.uri); + const terminal = await this.makeTerminal(); + terminal.write(message.message); + this.layoutTerminal(terminal); + this.attachTerminalToDom(terminal); } else { - uri = subject.outputUri; - } - - - const modelRef = this.model.value = await this.modelService.createModelReference(uri); - if (!this.widget.value) { - this.widget.value = this.editor ? this.instantiationService.createInstance( - EmbeddedCodeEditorWidget, - this.container, - commonEditorOptions, - {}, - this.editor, - ) : this.instantiationService.createInstance( - CodeEditorWidget, - this.container, - commonEditorOptions, - { isSimpleWidget: true } - ); - - if (this.dimension) { - this.widget.value.layout(this.dimension); + const result = this.resultService.getResult(subject.resultId); + const task = result?.tasks[subject.taskIndex]; + if (!task) { + return this.clear(); } - } - this.widget.value.setModel(modelRef.object.textEditorModel); - this.widget.value.updateOptions(commonEditorOptions); + // Update the cwd and use the first test to try to hint at the correct cwd, + // but often this will fall back to the first workspace folder. + this.updateCwd(Iterable.find(result.tests, t => !!t.item.uri)?.item.uri); + + const terminal = await this.makeTerminal(); + if (result instanceof LiveTestResult) { + let hadData = false; + for (const buffer of task.output.buffers) { + hadData ||= buffer.byteLength > 0; + terminal.write(buffer.buffer); + } + if (!hadData && !task.running) { + this.writeNotice(terminal, localize('runNoOutout', 'The test run did not record any output.')); + } + } else { + this.writeNotice(terminal, localize('runNoOutputForPast', 'Test output is only available for new test runs.')); + } + + this.attachTerminalToDom(terminal); + this.outputDataListener.value = task.output.onDidWriteData(e => terminal.write(e.buffer)); + } + } + + private updateCwd(testUri?: URI) { + const wf = (testUri && this.workspaceContext.getWorkspaceFolder(testUri)) + || this.workspaceContext.getWorkspace().folders[0]; + if (wf) { + this.terminalCwd.value = wf.uri.fsPath; + } + } + + private writeNotice(terminal: IDetachedXtermTerminal, str: string) { + terminal.write(`\x1b[2m${str}\x1b[0m`); + } + + private attachTerminalToDom(terminal: IDetachedXtermTerminal) { + terminal.write('\x1b[?25l'); // hide cursor + requestAnimationFrame(() => this.layoutTerminal(terminal)); + terminal.attachToElement(this.container, { enableGpu: false }); } private clear() { - this.model.clear(); - this.widget.clear(); + this.outputDataListener.clear(); + this.terminal.clear(); } public layout(dimensions: dom.IDimension) { - this.dimension = dimensions; - this.widget.value?.layout(dimensions); + this.dimensions = dimensions; + if (this.terminal.value) { + this.layoutTerminal(this.terminal.value, dimensions.width, dimensions.height); + } + } + + private layoutTerminal( + xterm: IDetachedXtermTerminal, + width = this.dimensions?.width ?? this.container.clientWidth, + height = this.dimensions?.height ?? this.container.clientHeight + ) { + width -= 10 + 20; // scrollbar width + margin + const scaled = getXtermScaledDimensions(xterm.getFont(), width, height); + if (scaled) { + xterm.resize(scaled.cols, scaled.rows); + } } } @@ -1515,6 +1612,10 @@ class OutputPeekTree extends Disposable { const resultNode = cc.get(result)! as TestResultElement; const disposable = new DisposableStore(); disposable.add(result.onNewTask(() => { + if (result.tasks.length === 1) { + this.requestReveal.fire(new TaskSubject(result.id, 0)); // reveal the first task in new runs + } + if (this.tree.hasElement(resultNode)) { this.tree.setChildren(resultNode, getResultChildren(result), { diffIdentityProvider }); } From 518a183762f44cfab36b237ac4034b83f5b5f3e4 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 16 Jun 2023 09:10:24 +0200 Subject: [PATCH 23/69] eng - add build version of node.js to `.yarnrc` (#185302) * eng - add build version of node.js to `.yarnrc` * :up: distro --- build/gulpfile.reh.js | 17 +++++++++-------- package.json | 4 ++-- product.json | 7 ++----- remote/.yarnrc | 1 + 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/build/gulpfile.reh.js b/build/gulpfile.reh.js index 53ac36242aa..1435eb7b5f0 100644 --- a/build/gulpfile.reh.js +++ b/build/gulpfile.reh.js @@ -125,8 +125,9 @@ const serverWithWebEntryPoints = [ function getNodeVersion() { const yarnrc = fs.readFileSync(path.join(REPO_ROOT, 'remote', '.yarnrc'), 'utf8'); - const target = /^target "(.*)"$/m.exec(yarnrc)[1]; - return target; + const nodeVersion = /^target "(.*)"$/m.exec(yarnrc)[1]; + const internalNodeVersion = /^ms_build_id "(.*)"$/m.exec(yarnrc)[1]; + return { nodeVersion, internalNodeVersion }; } function getNodeChecksum(nodeVersion, platform, arch) { @@ -156,7 +157,7 @@ function getNodeChecksum(nodeVersion, platform, arch) { return undefined; } -const nodeVersion = getNodeVersion(); +const { nodeVersion, internalNodeVersion } = getNodeVersion(); BUILD_TARGETS.forEach(({ platform, arch }) => { gulp.task(task.define(`node-${platform}-${arch}`, () => { @@ -193,7 +194,7 @@ function nodejs(platform, arch) { arch = 'x64'; } - log(`Downloading node.js ${nodeVersion} ${platform} ${arch} from ${product.nodejs.repository}...`); + log(`Downloading node.js ${nodeVersion} ${platform} ${arch} from ${product.nodejsRepository}...`); const checksumSha256 = getNodeChecksum(nodeVersion, platform, arch); @@ -205,14 +206,14 @@ function nodejs(platform, arch) { switch (platform) { case 'win32': - return (product.nodejs.repository !== 'https://nodejs.org' ? - fetchGithub(product.nodejs.repository, { version: product.nodejs.version, name: `win-${arch}-node.exe`, checksumSha256 }) : + return (product.nodejsRepository !== 'https://nodejs.org' ? + fetchGithub(product.nodejsRepository, { version: `${nodeVersion}-${internalNodeVersion}`, name: `win-${arch}-node.exe`, checksumSha256 }) : fetchUrls(`/dist/v${nodeVersion}/win-${arch}/node.exe`, { base: 'https://nodejs.org', checksumSha256 })) .pipe(rename('node.exe')); case 'darwin': case 'linux': - return (product.nodejs.repository !== 'https://nodejs.org' ? - fetchGithub(product.nodejs.repository, { version: product.nodejs.version, name: `node-v${nodeVersion}-${platform}-${arch}.tar.gz`, checksumSha256 }) : + return (product.nodejsRepository !== 'https://nodejs.org' ? + fetchGithub(product.nodejsRepository, { version: `${nodeVersion}-${internalNodeVersion}`, name: `node-v${nodeVersion}-${platform}-${arch}.tar.gz`, checksumSha256 }) : fetchUrls(`/dist/v${nodeVersion}/node-v${nodeVersion}-${platform}-${arch}.tar.gz`, { base: 'https://nodejs.org', checksumSha256 }) ).pipe(flatmap(stream => stream.pipe(gunzip()).pipe(untar()))) .pipe(filter('**/node')) diff --git a/package.json b/package.json index 84d7fe5a5a0..9de4de7a356 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.80.0", - "distro": "a44605dbeeed7ad5c41513260004329c4f502793", + "distro": "94a4bd29af2fe03e39c7867fdca1b2e27fed3a39", "author": { "name": "Microsoft Corporation" }, @@ -230,4 +230,4 @@ "optionalDependencies": { "windows-foreground-love": "0.5.0" } -} +} \ No newline at end of file diff --git a/product.json b/product.json index 51d2bfe00d6..f055d4c86f4 100644 --- a/product.json +++ b/product.json @@ -30,6 +30,7 @@ "linuxIconName": "code-oss", "licenseFileName": "LICENSE.txt", "reportIssueUrl": "https://github.com/microsoft/vscode/issues/new", + "nodejsRepository": "https://nodejs.org", "urlProtocol": "code-oss", "webviewContentExternalBaseUrlTemplate": "https://{{uuid}}.vscode-cdn.net/insider/ef65ac1ba57f57f2a3961bfe94aa20481caca4c6/out/vs/workbench/contrib/webview/browser/pre/", "builtInExtensions": [ @@ -81,9 +82,5 @@ "publisherDisplayName": "Microsoft" } } - ], - "nodejs": { - "repository": "https://nodejs.org", - "version": "16.17.1" - } + ] } diff --git a/remote/.yarnrc b/remote/.yarnrc index 340ea50f6b3..d714499d29d 100644 --- a/remote/.yarnrc +++ b/remote/.yarnrc @@ -1,4 +1,5 @@ disturl "http://nodejs.org/dist" target "16.17.1" +ms_build_id "20230714" runtime "node" build_from_source "true" From d2364c6338343ef2e4a2c50a70ab2daa04846761 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Fri, 16 Jun 2023 09:24:28 +0200 Subject: [PATCH 24/69] Add user setting for disabling comment max height (#185301) Fixes #181846 --- src/vs/workbench/contrib/comments/browser/commentNode.ts | 4 ++++ .../contrib/comments/browser/comments.contribution.ts | 5 +++++ src/vs/workbench/contrib/comments/browser/media/review.css | 3 +++ .../contrib/comments/common/commentsConfiguration.ts | 1 + 4 files changed, 13 insertions(+) diff --git a/src/vs/workbench/contrib/comments/browser/commentNode.ts b/src/vs/workbench/contrib/comments/browser/commentNode.ts index 6f3edc9f382..82f7cd850af 100644 --- a/src/vs/workbench/contrib/comments/browser/commentNode.ts +++ b/src/vs/workbench/contrib/comments/browser/commentNode.ts @@ -46,6 +46,7 @@ import { SmoothScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollable import { DomEmitter } from 'vs/base/browser/event'; import { CommentContextKeys } from 'vs/workbench/contrib/comments/common/commentContextKeys'; import { FileAccess } from 'vs/base/common/network'; +import { COMMENTS_SECTION, ICommentsConfiguration } from 'vs/workbench/contrib/comments/common/commentsConfiguration'; class CommentsActionRunner extends ActionRunner { protected override async runAction(action: IAction, context: any[]): Promise { @@ -131,6 +132,9 @@ export class CommentNode extends Disposable { this.createHeader(this._commentDetailsContainer); this._body = document.createElement(`div`); this._body.classList.add('comment-body', MOUSE_CURSOR_TEXT_CSS_CLASS_NAME); + if (configurationService.getValue(COMMENTS_SECTION)?.maxHeight !== false) { + this._body.classList.add('comment-body-max-height'); + } this.createScroll(this._commentDetailsContainer, this._body); this.updateCommentBody(this.comment.body); diff --git a/src/vs/workbench/contrib/comments/browser/comments.contribution.ts b/src/vs/workbench/contrib/comments/browser/comments.contribution.ts index be456347977..803aa80a18e 100644 --- a/src/vs/workbench/contrib/comments/browser/comments.contribution.ts +++ b/src/vs/workbench/contrib/comments/browser/comments.contribution.ts @@ -39,6 +39,11 @@ Registry.as(ConfigurationExtensions.Configuration).regis type: 'boolean', default: true, description: nls.localize('comments.visible', "Controls the visibility of the comments bar and comment threads in editors that have commenting ranges and comments. Comments are still accessible via the Comments view and will cause commenting to be toggled on in the same way running the command \"Comments: Toggle Editor Commenting\" toggles comments.") + }, + 'comments.maxHeight': { + type: 'boolean', + default: true, + description: nls.localize('comments.maxHeight', "Controls whether the comments widget scrolls or expands.") } } }); diff --git a/src/vs/workbench/contrib/comments/browser/media/review.css b/src/vs/workbench/contrib/comments/browser/media/review.css index 8667a78a9a9..13be5cf92fb 100644 --- a/src/vs/workbench/contrib/comments/browser/media/review.css +++ b/src/vs/workbench/contrib/comments/browser/media/review.css @@ -136,6 +136,9 @@ .review-widget .body .review-comment .review-comment-contents .comment-body { padding-top: 4px; +} + +.review-widget .body .review-comment .review-comment-contents .comment-body-max-height { max-height: 20em; } diff --git a/src/vs/workbench/contrib/comments/common/commentsConfiguration.ts b/src/vs/workbench/contrib/comments/common/commentsConfiguration.ts index f2f812b14d6..efc9d016415 100644 --- a/src/vs/workbench/contrib/comments/common/commentsConfiguration.ts +++ b/src/vs/workbench/contrib/comments/common/commentsConfiguration.ts @@ -7,6 +7,7 @@ export interface ICommentsConfiguration { openView: 'never' | 'file' | 'firstFile'; useRelativeTime: boolean; visible: boolean; + maxHeight: boolean; } export const COMMENTS_SECTION = 'comments'; From 65cc13aa8f76ad7106dd7c177f0e0ce9fd534a6e Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 16 Jun 2023 09:56:53 +0200 Subject: [PATCH 25/69] fix https://github.com/microsoft/vscode/issues/185305 (#185308) --- src/vs/workbench/contrib/search/browser/media/searchview.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/contrib/search/browser/media/searchview.css b/src/vs/workbench/contrib/search/browser/media/searchview.css index 2c434917669..68bdf40a0f0 100644 --- a/src/vs/workbench/contrib/search/browser/media/searchview.css +++ b/src/vs/workbench/contrib/search/browser/media/searchview.css @@ -35,6 +35,7 @@ display: flex; align-items: center; justify-content: center; + background-color: unset; } .monaco-workbench .search-view .search-widget .toggle-replace-button:hover { From bc472a44b5c4bfe9060758935959d631aa2dcec1 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 16 Jun 2023 09:57:52 +0200 Subject: [PATCH 26/69] fix https://github.com/microsoft/vscode/issues/185040 (#185306) --- .../contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts index 5734d7b46a7..0dfbe444af8 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts @@ -87,6 +87,9 @@ export class InlineChatLivePreviewWidget extends ZoneWidget { }, editor); this._disposables.add(this._diffEditor); this._diffEditor.setModel({ original: this._session.textModel0, modified: editor.getModel() }); + this._diffEditor.updateOptions({ + lineDecorationsWidth: editor.getLayoutInfo().decorationsWidth + }); const doStyle = () => { const theme = themeService.getColorTheme(); From d76a6328659249d6743968b4622307aae101db91 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 16 Jun 2023 10:39:18 +0200 Subject: [PATCH 27/69] changes from the review --- src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts | 3 +-- .../contrib/inlineChat/browser/inlineChatController.ts | 4 ++-- .../contrib/inlineChat/browser/inlineChatSession.ts | 5 ++--- .../contrib/inlineChat/browser/inlineChatWidget.ts | 8 ++++++-- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts b/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts index 54c7910f648..a003de17958 100644 --- a/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts +++ b/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts @@ -31,7 +31,6 @@ export interface IOptions { allowUnlimitedHeight?: boolean; ordinal?: number; showInHiddenAreas?: boolean; - allowBehindVerticalScrollbar?: boolean; } export interface IStyles { @@ -272,7 +271,7 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { } protected _getWidth(info: EditorLayoutInfo): number { - return info.width - info.minimap.minimapWidth - (this.options.allowBehindVerticalScrollbar ? 0 : info.verticalScrollbarWidth); + return info.width - info.minimap.minimapWidth - info.verticalScrollbarWidth; } private _getLeft(info: EditorLayoutInfo): number { diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts index bf026a34fac..148fa5aa3f7 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts @@ -199,7 +199,7 @@ export class InlineChatController implements IEditorContribution { assertType(this._strategy); assertType(this._editor.hasModel()); - let widgetPosition: Position | undefined; + let widgetPosition: Position; if (initialRender) { widgetPosition = this._editor.getSelection().getEndPosition(); this._zone.value.setContainerMargins(); @@ -212,7 +212,7 @@ export class InlineChatController implements IEditorContribution { } } this._zone.value.show(widgetPosition); - this._zone.value.updateBackgroundColor(widgetPosition, this._activeSession.selection); + this._zone.value.updateBackgroundColor(widgetPosition, this._activeSession.wholeRange.value); } protected async _nextState(state: State, options: InlineChatRunOptions | undefined): Promise { diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts index c8b920af65a..141b5911cff 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts @@ -126,8 +126,7 @@ export class Session { readonly textModelN: ITextModel, readonly provider: IInlineChatSessionProvider, readonly session: IInlineChatSession, - readonly wholeRange: SessionWholeRange, - readonly selection: IRange + readonly wholeRange: SessionWholeRange ) { this.textModelNAltVersion = textModelN.getAlternativeVersionId(); this._teldata = { @@ -444,7 +443,7 @@ export class InlineChatSessionService implements IInlineChatSessionService { const wholeRangeMgr = new SessionWholeRange(textModel, wholeRange); store.add(wholeRangeMgr); - const session = new Session(options.editMode, editor, textModel0, textModel, provider, raw, wholeRangeMgr, editor.getSelection()); + const session = new Session(options.editMode, editor, textModel0, textModel, provider, raw, wholeRangeMgr); // store: key -> session const key = this._key(editor, textModel.uri); diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts index d3f917612db..e656cd6c6a3 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts @@ -6,7 +6,7 @@ import 'vs/css!./inlineChat'; import { DisposableStore, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { IActiveCodeEditor, ICodeEditor, IDiffEditorConstructionOptions } from 'vs/editor/browser/editorBrowser'; -import { EditorOption } from 'vs/editor/common/config/editorOptions'; +import { EditorLayoutInfo, EditorOption } from 'vs/editor/common/config/editorOptions'; import { IRange, Range } from 'vs/editor/common/core/range'; import { localize } from 'vs/nls'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; @@ -701,7 +701,7 @@ export class InlineChatZoneWidget extends ZoneWidget { @IInstantiationService private readonly _instaService: IInstantiationService, @IContextKeyService contextKeyService: IContextKeyService, ) { - super(editor, { showFrame: false, showArrow: false, isAccessible: true, className: 'inline-chat-widget', keepEditorSelection: true, showInHiddenAreas: true, ordinal: 10000 + 3, allowBehindVerticalScrollbar: true }); + super(editor, { showFrame: false, showArrow: false, isAccessible: true, className: 'inline-chat-widget', keepEditorSelection: true, showInHiddenAreas: true, ordinal: 10000 + 3 }); this._ctxVisible = CTX_INLINE_CHAT_VISIBLE.bindTo(contextKeyService); this._ctxCursorPosition = CTX_INLINE_CHAT_OUTER_CURSOR_POSITION.bindTo(contextKeyService); @@ -771,6 +771,10 @@ export class InlineChatZoneWidget extends ZoneWidget { this._ctxVisible.set(true); } + override _getWidth(info: EditorLayoutInfo): number { + return info.width - info.minimap.minimapWidth - 0; + } + public updateBackgroundColor(position: Position, selection: IRange) { if (!this.container) { return; From ee3b5436a09e2cfa75f384fb0e24de2cc6d53b97 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 16 Jun 2023 10:41:06 +0200 Subject: [PATCH 28/69] cleaning the code --- .../contrib/inlineChat/browser/inlineChatController.ts | 2 +- src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts index 305cc1dad26..437e03e0800 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts @@ -196,6 +196,7 @@ export class InlineChatController implements IEditorContribution { private _showWidget(initialRender: boolean = false) { assertType(this._editor.hasModel()); + assertType(this._activeSession); let widgetPosition: Position; if (initialRender) { @@ -203,7 +204,6 @@ export class InlineChatController implements IEditorContribution { this._zone.value.setContainerMargins(); this._zone.value.setWidgetMargins(widgetPosition); } else { - assertType(this._activeSession); assertType(this._strategy); widgetPosition = this._strategy.getWidgetPosition() ?? this._zone.value.position ?? this._activeSession.wholeRange.value.getEndPosition(); const needsMargin = this._strategy.needsMargin(); diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts index 6b25b4bc2db..e9b2459e598 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts @@ -774,7 +774,7 @@ export class InlineChatZoneWidget extends ZoneWidget { } override _getWidth(info: EditorLayoutInfo): number { - return info.width - info.minimap.minimapWidth - 0; + return info.width - info.minimap.minimapWidth; } public updateBackgroundColor(position: Position, selection: IRange) { From 653e8d0f0a84dffe5124131245a17550cc9cbff4 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 16 Jun 2023 10:50:40 +0200 Subject: [PATCH 29/69] placing the update backrgound elsewhere --- .../contrib/inlineChat/browser/inlineChatController.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts index 437e03e0800..7668966eef0 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts @@ -196,7 +196,6 @@ export class InlineChatController implements IEditorContribution { private _showWidget(initialRender: boolean = false) { assertType(this._editor.hasModel()); - assertType(this._activeSession); let widgetPosition: Position; if (initialRender) { @@ -204,15 +203,16 @@ export class InlineChatController implements IEditorContribution { this._zone.value.setContainerMargins(); this._zone.value.setWidgetMargins(widgetPosition); } else { + assertType(this._activeSession); assertType(this._strategy); widgetPosition = this._strategy.getWidgetPosition() ?? this._zone.value.position ?? this._activeSession.wholeRange.value.getEndPosition(); const needsMargin = this._strategy.needsMargin(); if (!needsMargin) { this._zone.value.setWidgetMargins(widgetPosition, 0); } + this._zone.value.updateBackgroundColor(widgetPosition, this._activeSession.wholeRange.value); } this._zone.value.show(widgetPosition); - this._zone.value.updateBackgroundColor(widgetPosition, this._activeSession.wholeRange.value); } protected async _nextState(state: State, options: InlineChatRunOptions): Promise { From 61ba389b0a7108af0411c73ab30c7e4350051645 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 16 Jun 2023 11:07:57 +0200 Subject: [PATCH 30/69] use default btn styles only on opt-in (#185313) --- src/vs/base/browser/ui/button/button.css | 65 ++++++++++++-------- src/vs/platform/actions/browser/buttonbar.ts | 1 + 2 files changed, 39 insertions(+), 27 deletions(-) diff --git a/src/vs/base/browser/ui/button/button.css b/src/vs/base/browser/ui/button/button.css index a5a79e7fc2d..14a189bd0fc 100644 --- a/src/vs/base/browser/ui/button/button.css +++ b/src/vs/base/browser/ui/button/button.css @@ -25,25 +25,6 @@ text-decoration: none !important; } -.monaco-button { - color: var(--vscode-button-foreground); - background-color: var(--vscode-button-background); -} - -.monaco-button:hover { - background-color: var(--vscode-button-hoverBackground); -} - -.monaco-button.secondary { - color: var(--vscode-button-secondaryForeground); - background-color: var(--vscode-button-secondaryBackground); -} - -.monaco-button.secondary:hover { - background-color: var(--vscode-button-secondaryHoverBackground); -} - - .monaco-button.disabled:focus, .monaco-button.disabled { opacity: 0.4 !important; @@ -109,19 +90,11 @@ .monaco-button-dropdown .monaco-button-dropdown-separator { padding: 4px 0; cursor: default; - background-color: var(--vscode-button-background); - border-top: 1px solid var(--vscode-button-border); - border-bottom: 1px solid var(--vscode-button-border); -} - -.monaco-button.secondary + .monaco-button-dropdown-separator { - background-color: var(--vscode-button-secondaryBackground); } .monaco-button-dropdown .monaco-button-dropdown-separator > div { height: 100%; width: 1px; - background-color: var(--vscode-button-separator); } .monaco-button-dropdown > .monaco-button.monaco-dropdown-button { @@ -159,3 +132,41 @@ margin: 0 0.2em; color: inherit !important; } + +/* default color styles - based on CSS variables */ + +.monaco-button.default-colors, +.monaco-button-dropdown.default-colors > .monaco-button{ + color: var(--vscode-button-foreground); + background-color: var(--vscode-button-background); +} + +.monaco-button.default-colors:hover, +.monaco-button-dropdown.default-colors > .monaco-button:hover { + background-color: var(--vscode-button-hoverBackground); +} + +.monaco-button.default-colors.secondary, +.monaco-button-dropdown.default-colors > .monaco-button.secondary { + color: var(--vscode-button-secondaryForeground); + background-color: var(--vscode-button-secondaryBackground); +} + +.monaco-button.default-colors.secondary:hover, +.monaco-button-dropdown.default-colors > .monaco-button.secondary:hover { + background-color: var(--vscode-button-secondaryHoverBackground); +} + +.monaco-button-dropdown.default-colors .monaco-button-dropdown-separator { + background-color: var(--vscode-button-background); + border-top: 1px solid var(--vscode-button-border); + border-bottom: 1px solid var(--vscode-button-border); +} + +.monaco-button-dropdown.default-colors .monaco-button.secondary + .monaco-button-dropdown-separator { + background-color: var(--vscode-button-secondaryBackground); +} + +.monaco-button-dropdown.default-colors .monaco-button-dropdown-separator > div { + background-color: var(--vscode-button-separator); +} diff --git a/src/vs/platform/actions/browser/buttonbar.ts b/src/vs/platform/actions/browser/buttonbar.ts index 811ccaac879..c08d3ab3548 100644 --- a/src/vs/platform/actions/browser/buttonbar.ts +++ b/src/vs/platform/actions/browser/buttonbar.ts @@ -88,6 +88,7 @@ export class MenuWorkbenchButtonBar extends ButtonBar { } btn.enabled = action.enabled; + btn.element.classList.add('default-colors'); if (conifgProvider(action)?.showLabel ?? true) { btn.label = action.label; } else { From 6cf7b9d8cd19403a3f9a885218284341abf00e1c Mon Sep 17 00:00:00 2001 From: Johannes Date: Fri, 16 Jun 2023 12:32:29 +0200 Subject: [PATCH 31/69] for embedded diff editors link word highlighters --- .../browser/wordHighlighter.ts | 33 +++++++++++++++++-- .../browser/inlineChatLivePreviewWidget.ts | 7 ++++ 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/vs/editor/contrib/wordHighlighter/browser/wordHighlighter.ts b/src/vs/editor/contrib/wordHighlighter/browser/wordHighlighter.ts index ee6b06b6319..324ddc6f09d 100644 --- a/src/vs/editor/contrib/wordHighlighter/browser/wordHighlighter.ts +++ b/src/vs/editor/contrib/wordHighlighter/browser/wordHighlighter.ts @@ -9,7 +9,7 @@ import { CancelablePromise, createCancelablePromise, first, timeout } from 'vs/b import { CancellationToken } from 'vs/base/common/cancellation'; import { onUnexpectedError, onUnexpectedExternalError } from 'vs/base/common/errors'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { IActiveCodeEditor, ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorAction, EditorContributionInstantiation, IActionOptions, registerEditorAction, registerEditorContribution, registerModelAndPositionCommand } from 'vs/editor/browser/editorExtensions'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; @@ -29,6 +29,7 @@ import { IWordAtPosition } from 'vs/editor/common/core/wordHelper'; import { LanguageFeatureRegistry } from 'vs/editor/common/languageFeatureRegistry'; import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures'; import { getHighlightDecorationOptions } from 'vs/editor/contrib/wordHighlighter/browser/highlightDecorations'; +import { Iterable } from 'vs/base/common/iterator'; const ctxHasWordHighlights = new RawContextKey('hasWordHighlights', false); @@ -192,9 +193,12 @@ class WordHighlighter { private readonly _hasWordHighlights: IContextKey; private _ignorePositionChangeEvent: boolean; - constructor(editor: IActiveCodeEditor, providers: LanguageFeatureRegistry, contextKeyService: IContextKeyService) { + private readonly linkedHighlighters: () => Iterable; + + constructor(editor: IActiveCodeEditor, providers: LanguageFeatureRegistry, linkedHighlighters: () => Iterable, contextKeyService: IContextKeyService) { this.editor = editor; this.providers = providers; + this.linkedHighlighters = linkedHighlighters; this._hasWordHighlights = ctxHasWordHighlights.bindTo(contextKeyService); this._ignorePositionChangeEvent = false; this.occurrencesHighlight = this.editor.getOption(EditorOption.occurrencesHighlight); @@ -453,6 +457,14 @@ class WordHighlighter { this.decorations.set(decorations); this._hasWordHighlights.set(this.hasDecorations()); + + // update decorators of friends + for (const other of this.linkedHighlighters()) { + if (other?.editor.getModel() === this.editor.getModel()) { + other.decorations.set(decorations); + other._hasWordHighlights.set(other.hasDecorations()); + } + } } public dispose(): void { @@ -470,13 +482,15 @@ export class WordHighlighterContribution extends Disposable implements IEditorCo } private wordHighlighter: WordHighlighter | null; + private linkedContributions: Set; constructor(editor: ICodeEditor, @IContextKeyService contextKeyService: IContextKeyService, @ILanguageFeaturesService languageFeaturesService: ILanguageFeaturesService) { super(); this.wordHighlighter = null; + this.linkedContributions = new Set(); const createWordHighlighterIfPossible = () => { if (editor.hasModel()) { - this.wordHighlighter = new WordHighlighter(editor, languageFeaturesService.documentHighlightProvider, contextKeyService); + this.wordHighlighter = new WordHighlighter(editor, languageFeaturesService.documentHighlightProvider, () => Iterable.map(this.linkedContributions, c => c.wordHighlighter), contextKeyService); } }; this._register(editor.onDidChangeModel((e) => { @@ -514,6 +528,19 @@ export class WordHighlighterContribution extends Disposable implements IEditorCo this.wordHighlighter?.stop(); } + public linkWordHighlighters(editor: ICodeEditor): IDisposable { + const other = WordHighlighterContribution.get(editor); + if (!other) { + return Disposable.None; + } + this.linkedContributions.add(other); + other.linkedContributions.add(this); + return toDisposable(() => { + this.linkedContributions.delete(other); + other.linkedContributions.delete(this); + }); + } + public override dispose(): void { if (this.wordHighlighter) { this.wordHighlighter.dispose(); diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts index 0dfbe444af8..69cc2f686a2 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatLivePreviewWidget.ts @@ -33,6 +33,7 @@ import { EditOperation } from 'vs/editor/common/core/editOperation'; import { Session } from 'vs/workbench/contrib/inlineChat/browser/inlineChatSession'; import { ILanguageService } from 'vs/editor/common/languages/language'; import { FoldingController } from 'vs/editor/contrib/folding/browser/folding'; +import { WordHighlighterContribution } from 'vs/editor/contrib/wordHighlighter/browser/wordHighlighter'; export class InlineChatLivePreviewWidget extends ZoneWidget { @@ -85,12 +86,18 @@ export class InlineChatLivePreviewWidget extends ZoneWidget { originalEditor: { contributions: diffContributions }, modifiedEditor: { contributions: diffContributions } }, editor); + this._disposables.add(this._diffEditor); this._diffEditor.setModel({ original: this._session.textModel0, modified: editor.getModel() }); this._diffEditor.updateOptions({ lineDecorationsWidth: editor.getLayoutInfo().decorationsWidth }); + const highlighter = WordHighlighterContribution.get(editor); + if (highlighter) { + this._disposables.add(highlighter.linkWordHighlighters(this._diffEditor.getModifiedEditor())); + } + const doStyle = () => { const theme = themeService.getColorTheme(); const overrides: [target: string, source: string][] = [ From 7322bbd289ee289add38a74c167cde5cbe89e65a Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 16 Jun 2023 13:18:15 +0200 Subject: [PATCH 32/69] update whole range visual decoration after changes are applied (#185315) * update whole range visual decoration after changes are applied * fix tests --- .../inlineChat/browser/inlineChatController.ts | 13 +++++++++---- .../inlineChat/browser/inlineChatSession.ts | 15 ++++++++------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts index 7668966eef0..21fa4aa01f3 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts @@ -292,11 +292,16 @@ export class InlineChatController implements IEditorContribution { this._sessionStore.clear(); - const wholeRangeDecoration = this._editor.createDecorationsCollection([{ - range: this._activeSession.wholeRange.value, - options: InlineChatController._decoBlock - }]); + const wholeRangeDecoration = this._editor.createDecorationsCollection(); + const updateWholeRangeDecoration = () => { + wholeRangeDecoration.set([{ + range: this._activeSession!.wholeRange.value, + options: InlineChatController._decoBlock + }]); + }; this._sessionStore.add(toDisposable(() => wholeRangeDecoration.clear())); + this._sessionStore.add(this._activeSession.wholeRange.onDidChange(updateWholeRangeDecoration)); + updateWholeRangeDecoration(); this._zone.value.widget.updateSlashCommands(this._activeSession.session.slashCommands ?? []); this._zone.value.widget.placeholder = this._getPlaceholderText(); diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts index fde0ebbe2b8..293cac5c336 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts @@ -66,20 +66,20 @@ class SessionWholeRange { private static readonly _options = { description: 'inlineChat/session/wholeRange' }; - private readonly _store = new DisposableStore(); + private readonly _onDidChange = new Emitter(); + readonly onDidChange: Event = this._onDidChange.event; + private readonly _decorationIds: string[] = []; constructor(private readonly _textModel: ITextModel, wholeRange: IRange) { this._decorationIds = _textModel.deltaDecorations([], [{ range: wholeRange, options: SessionWholeRange._options }]); - this._store.add(toDisposable(() => { - if (!_textModel.isDisposed()) { - _textModel.deltaDecorations(this._decorationIds, []); - } - })); } dispose() { - this._store.dispose(); + this._onDidChange.dispose(); + if (!this._textModel.isDisposed()) { + this._textModel.deltaDecorations(this._decorationIds, []); + } } trackEdits(edits: ISingleEditOperation[]): void { @@ -88,6 +88,7 @@ class SessionWholeRange { newDeco.push({ range: edit.range, options: SessionWholeRange._options }); } this._decorationIds.push(...this._textModel.deltaDecorations([], newDeco)); + this._onDidChange.fire(this); } get value(): Range { From dedbfed2692684da7c22a5c3471fb7ad7fbf783f Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 16 Jun 2023 13:57:14 +0200 Subject: [PATCH 33/69] fix build (#185325) --- src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts index e9b2459e598..84a44857e19 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts @@ -773,7 +773,7 @@ export class InlineChatZoneWidget extends ZoneWidget { this._ctxVisible.set(true); } - override _getWidth(info: EditorLayoutInfo): number { + protected override _getWidth(info: EditorLayoutInfo): number { return info.width - info.minimap.minimapWidth; } From e2470cf4101025093676c77a684e4a77f3ea873c Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 16 Jun 2023 14:36:10 +0200 Subject: [PATCH 34/69] tweak resolve info so that we know if resolve was needed and if it already finished, also make telemetry gate more fair (#185327) * tweak resolve info so that we know if resolve was needed and if it already finished, also make telemetry gate more fair * also log the resolve duration --- .../editor/contrib/suggest/browser/suggest.ts | 17 +++++++----- .../suggest/browser/suggestController.ts | 26 +++++++++++-------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/vs/editor/contrib/suggest/browser/suggest.ts b/src/vs/editor/contrib/suggest/browser/suggest.ts index 3409fa42392..8e4d8326d52 100644 --- a/src/vs/editor/contrib/suggest/browser/suggest.ts +++ b/src/vs/editor/contrib/suggest/browser/suggest.ts @@ -73,7 +73,7 @@ export class CompletionItem { readonly extensionId?: ExtensionIdentifier; // resolving - private _isResolved?: boolean; + private _resolveDuration?: number; private _resolveCache?: Promise; constructor( @@ -122,32 +122,37 @@ export class CompletionItem { // create the suggestion resolver if (typeof provider.resolveCompletionItem !== 'function') { this._resolveCache = Promise.resolve(); - this._isResolved = true; + this._resolveDuration = 0; } } // ---- resolving get isResolved(): boolean { - return !!this._isResolved; + return this._resolveDuration !== undefined; + } + + get resolveDuration(): number { + return this._resolveDuration !== undefined ? this._resolveDuration : -1; } async resolve(token: CancellationToken) { if (!this._resolveCache) { const sub = token.onCancellationRequested(() => { this._resolveCache = undefined; - this._isResolved = false; + this._resolveDuration = undefined; }); + const sw = new StopWatch(true); this._resolveCache = Promise.resolve(this.provider.resolveCompletionItem!(this.completion, token)).then(value => { Object.assign(this.completion, value); - this._isResolved = true; + this._resolveDuration = sw.elapsed(); sub.dispose(); }, err => { if (isCancellationError(err)) { // the IPC queue will reject the request with the // cancellation error -> reset cached this._resolveCache = undefined; - this._isResolved = false; + this._resolveDuration = undefined; } }); } diff --git a/src/vs/editor/contrib/suggest/browser/suggestController.ts b/src/vs/editor/contrib/suggest/browser/suggestController.ts index 0341a938c24..68f9b0fb155 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestController.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestController.ts @@ -482,20 +482,24 @@ export class SuggestController implements IEditorContribution { // clear only now - after all tasks are done Promise.all(tasks).finally(() => { - this._reportSuggestionAcceptedTelemetry(item, model, event, isResolved); + this._reportSuggestionAcceptedTelemetry(item, model, isResolved); this.model.clear(); cts.dispose(); }); } - private _telemetryGate: number = 0; - private _reportSuggestionAcceptedTelemetry(item: CompletionItem, model: ITextModel, acceptedSuggestion: ISelectedSuggestion, itemResolved: boolean) { - if (this._telemetryGate++ % 100 !== 0) { + private _reportSuggestionAcceptedTelemetry(item: CompletionItem, model: ITextModel, itemResolved: boolean) { + + if (Math.floor(Math.random() * 100) === 0) { + // throttle telemetry event because accepting completions happens a lot return; } - type AcceptedSuggestion = { providerId: string; fileExtension: string; languageId: string; basenameHash: string; kind: number; itemResolved: boolean }; + type AcceptedSuggestion = { + providerId: string; fileExtension: string; languageId: string; basenameHash: string; kind: number; + resolveInfo: number; resolveDuration: number; + }; type AcceptedSuggestionClassification = { owner: 'jrieken'; comment: 'Information accepting completion items'; @@ -504,18 +508,18 @@ export class SuggestController implements IEditorContribution { fileExtension: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'File extension of the file into which the completion was inserted' }; languageId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Language type of the file into which the completion was inserted' }; kind: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'The completion item kind' }; - itemResolved: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'If the item was inserted before resolving was done' }; + resolveInfo: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'If the item was inserted before resolving was done' }; + resolveDuration: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'How long resolving took to finish' }; }; - // _debugDisplayName looks like `vscode.css-language-features(/-:)`, where the last bit is the trigger chars - // normalize it to just the extension ID and lowercase - const providerId = item.extensionId ? item.extensionId.value : (acceptedSuggestion.item.provider._debugDisplayName ?? 'unknown').split('(', 1)[0].toLowerCase(); + this._telemetryService.publicLog2('suggest.acceptedSuggestion', { - providerId, + providerId: item.extensionId?.value ?? 'unknown', kind: item.completion.kind, basenameHash: hash(basename(model.uri)).toString(16), languageId: model.getLanguageId(), fileExtension: extname(model.uri), - itemResolved + resolveInfo: !item.provider.resolveCompletionItem ? -1 : itemResolved ? 1 : 0, + resolveDuration: item.resolveDuration }); } From 10cf7f040aed90d00c57fea99c7006d71b726862 Mon Sep 17 00:00:00 2001 From: Robo Date: Fri, 16 Jun 2023 21:55:59 +0900 Subject: [PATCH 35/69] chore: add distro info to telemetry on linux (#185261) --- .eslintrc.json | 2 + src/vs/base/node/osReleaseInfo.ts | 73 +++++++++++++++++++ .../node/remoteExtensionHostAgentServer.ts | 27 ++++++- 3 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 src/vs/base/node/osReleaseInfo.ts diff --git a/.eslintrc.json b/.eslintrc.json index 7e6b386b804..c28784041b4 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -233,6 +233,7 @@ "electron", "events", "fs", + "fs/promises", "graceful-fs", "http", "https", @@ -244,6 +245,7 @@ "os", "path", "perf_hooks", + "readline", "stream", "string_decoder", "tas-client-umd", diff --git a/src/vs/base/node/osReleaseInfo.ts b/src/vs/base/node/osReleaseInfo.ts new file mode 100644 index 00000000000..f72b0fe82ba --- /dev/null +++ b/src/vs/base/node/osReleaseInfo.ts @@ -0,0 +1,73 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { constants as FSConstants } from 'fs'; +import { open, FileHandle } from 'fs/promises'; +import { createInterface as readLines } from 'readline'; +import * as Platform from 'vs/base/common/platform'; + +type ReleaseInfo = { + id: string; + id_like?: string; + version_id?: string; +}; + +export async function getOSReleaseInfo(errorLogger: (error: any) => void): Promise { + if (Platform.isMacintosh || Platform.isWindows) { + return; + } + + // Extract release information on linux based systems + // using the identifiers specified in + // https://www.freedesktop.org/software/systemd/man/os-release.html + let handle: FileHandle | undefined; + for (const filePath of ['/etc/os-release', '/usr/lib/os-release', '/etc/lsb-release']) { + try { + handle = await open(filePath, FSConstants.R_OK); + break; + } catch (err) { } + } + + if (!handle) { + errorLogger('Unable to retrieve release information from known identifier paths.'); + return; + } + + try { + const osReleaseKeys = new Set([ + 'ID', + 'DISTRIB_ID', + 'ID_LIKE', + 'VERSION_ID', + 'DISTRIB_RELEASE', + ]); + const releaseInfo: ReleaseInfo = { + id: 'unknown' + }; + + for await (const line of readLines({ input: handle.createReadStream(), crlfDelay: Infinity })) { + if (!line.includes('=')) { + continue; + } + const key = line.split('=')[0].toUpperCase().trim(); + if (osReleaseKeys.has(key)) { + const value = line.split('=')[1].replace(/"/g, '').toLowerCase().trim(); + if (key === 'ID' || key === 'DISTRIB_ID') { + releaseInfo.id = value; + } else if (key === 'ID_LIKE') { + releaseInfo.id_like = value; + } else if (key === 'VERSION_ID' || key === 'DISTRIB_RELEASE') { + releaseInfo.version_id = value; + } + } + } + + return releaseInfo; + } catch (err) { + errorLogger(err); + } + + return; +} diff --git a/src/vs/server/node/remoteExtensionHostAgentServer.ts b/src/vs/server/node/remoteExtensionHostAgentServer.ts index 86fa775403e..5a2d9943ac9 100644 --- a/src/vs/server/node/remoteExtensionHostAgentServer.ts +++ b/src/vs/server/node/remoteExtensionHostAgentServer.ts @@ -22,6 +22,7 @@ import * as platform from 'vs/base/common/platform'; import { createRegExp, escapeRegExpCharacters } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; +import { getOSReleaseInfo } from 'vs/base/node/osReleaseInfo'; import { findFreePort } from 'vs/base/node/ports'; import { addUNCHostToAllowlist, disableUNCAccessRestrictions } from 'vs/base/node/unc'; import { PersistentProtocol } from 'vs/base/parts/ipc/common/ipc.net'; @@ -788,7 +789,7 @@ export async function createServer(address: string | net.AddressInfo | null, arg const vscodeServerListenTime: number = (global).vscodeServerListenTime; const vscodeServerCodeLoadedTime: number = (global).vscodeServerCodeLoadedTime; - instantiationService.invokeFunction((accessor) => { + instantiationService.invokeFunction(async (accessor) => { const telemetryService = accessor.get(ITelemetryService); type ServerStartClassification = { @@ -811,6 +812,30 @@ export async function createServer(address: string | net.AddressInfo | null, arg codeLoadedTime: vscodeServerCodeLoadedTime, readyTime: currentTime }); + + if (platform.isLinux) { + const logService = accessor.get(ILogService); + const releaseInfo = await getOSReleaseInfo(logService.error.bind(logService)); + if (releaseInfo) { + type ServerPlatformInfoClassification = { + platformId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'A string identifying the operating system without any version information.' }; + platformVersionId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'A string identifying the operating system version excluding any name information or release code.' }; + platformIdLike: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'A string identifying the operating system the current OS derivate is closely related to.' }; + owner: 'deepak1556'; + comment: 'Provides insight into the distro information on Linux.'; + }; + type ServerPlatformInfoEvent = { + platformId: string; + platformVersionId: string | undefined; + platformIdLike: string | undefined; + }; + telemetryService.publicLog2('serverPlatformInfo', { + platformId: releaseInfo.id, + platformVersionId: releaseInfo.version_id, + platformIdLike: releaseInfo.id_like + }); + } + } }); if (args['print-startup-performance']) { From 19b9e08dae35fe29968525e801d45ba0ea771c48 Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Fri, 16 Jun 2023 15:15:05 +0200 Subject: [PATCH 36/69] Pick distinct names for suites (#185332) --- src/vs/editor/test/common/model/intervalTree.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/test/common/model/intervalTree.test.ts b/src/vs/editor/test/common/model/intervalTree.test.ts index 4b19bee62a0..bb94b0db456 100644 --- a/src/vs/editor/test/common/model/intervalTree.test.ts +++ b/src/vs/editor/test/common/model/intervalTree.test.ts @@ -17,7 +17,7 @@ const MAX_INSERTS = 30; const MIN_CHANGE_CNT = 10; const MAX_CHANGE_CNT = 20; -suite('IntervalTree', () => { +suite('IntervalTree 1', () => { class Interval { _intervalBrand: void = undefined; @@ -554,7 +554,7 @@ suite('IntervalTree', () => { }); }); -suite('IntervalTree', () => { +suite('IntervalTree 2', () => { function assertNodeAcceptEdit(msg: string, nodeStart: number, nodeEnd: number, nodeStickiness: TrackedRangeStickiness, start: number, end: number, textLength: number, forceMoveMarkers: boolean, expectedNodeStart: number, expectedNodeEnd: number): void { const node = new IntervalNode('', nodeStart, nodeEnd); setNodeStickiness(node, nodeStickiness); From 26a530f8b4a4cd9bd39b3aa607d764145a26947e Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Fri, 16 Jun 2023 06:18:46 -0700 Subject: [PATCH 37/69] Implement `GlyphMarginWidget`s (#184375) * Implement GlyphMarginWidgets --------- Co-authored-by: Alex Dima --- src/vs/editor/browser/editorBrowser.ts | 53 ++- .../services/abstractCodeEditorService.ts | 2 +- src/vs/editor/browser/view.ts | 106 ++++- .../viewParts/glyphMargin/glyphMargin.ts | 440 +++++++++++++----- .../linesDecorations/linesDecorations.ts | 4 +- .../marginDecorations/marginDecorations.ts | 4 +- .../editor/browser/widget/codeEditorWidget.ts | 49 +- .../editor/common/viewModel/viewModelImpl.ts | 50 +- src/vs/monaco.d.ts | 50 ++ 9 files changed, 595 insertions(+), 163 deletions(-) diff --git a/src/vs/editor/browser/editorBrowser.ts b/src/vs/editor/browser/editorBrowser.ts index c85f63877e5..3f3cdef028d 100644 --- a/src/vs/editor/browser/editorBrowser.ts +++ b/src/vs/editor/browser/editorBrowser.ts @@ -12,7 +12,7 @@ import { IPosition, Position } from 'vs/editor/common/core/position'; import { IRange, Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; import * as editorCommon from 'vs/editor/common/editorCommon'; -import { IIdentifiedSingleEditOperation, IModelDecoration, IModelDeltaDecoration, ITextModel, ICursorStateComputer, PositionAffinity } from 'vs/editor/common/model'; +import { IIdentifiedSingleEditOperation, IModelDecoration, IModelDeltaDecoration, ITextModel, ICursorStateComputer, PositionAffinity, GlyphMarginLane } from 'vs/editor/common/model'; import { IWordAtPosition } from 'vs/editor/common/core/wordHelper'; import { IModelContentChangedEvent, IModelDecorationsChangedEvent, IModelLanguageChangedEvent, IModelLanguageConfigurationChangedEvent, IModelOptionsChangedEvent, IModelTokensChangedEvent } from 'vs/editor/common/textModelEvents'; import { OverviewRulerZone } from 'vs/editor/common/viewModel/overviewZoneManager'; @@ -251,6 +251,43 @@ export interface IOverlayWidget { getPosition(): IOverlayWidgetPosition | null; } +/** + * A glyph margin widget renders in the editor glyph margin. + */ +export interface IGlyphMarginWidget { + /** + * Get a unique identifier of the glyph widget. + */ + getId(): string; + /** + * Get the dom node of the glyph widget. + */ + getDomNode(): HTMLElement; + /** + * Get the placement of the glyph widget. + */ + getPosition(): IGlyphMarginWidgetPosition; +} + +/** + * A position for rendering glyph margin widgets. + */ +export interface IGlyphMarginWidgetPosition { + /** + * The glyph margin lane where the widget should be shown. + */ + lane: GlyphMarginLane; + /** + * The priority order of the widget, used for determining which widget + * to render when there are multiple. + */ + zIndex: number; + /** + * The editor range that this widget applies to. + */ + range: IRange; +} + /** * Type of hit element with the mouse in the editor. */ @@ -993,6 +1030,20 @@ export interface ICodeEditor extends editorCommon.IEditor { */ removeOverlayWidget(widget: IOverlayWidget): void; + /** + * Add a glyph margin widget. Widgets must have unique ids, otherwise they will be overwritten. + */ + addGlyphMarginWidget(widget: IGlyphMarginWidget): void; + /** + * Layout/Reposition a glyph margin widget. This is a ping to the editor to call widget.getPosition() + * and update appropriately. + */ + layoutGlyphMarginWidget(widget: IGlyphMarginWidget): void; + /** + * Remove a glyph margin widget. + */ + removeGlyphMarginWidget(widget: IGlyphMarginWidget): void; + /** * Change the view zones. View zones are lost when a new model is attached to the editor. */ diff --git a/src/vs/editor/browser/services/abstractCodeEditorService.ts b/src/vs/editor/browser/services/abstractCodeEditorService.ts index 62db35d5a0c..cc0f8669a03 100644 --- a/src/vs/editor/browser/services/abstractCodeEditorService.ts +++ b/src/vs/editor/browser/services/abstractCodeEditorService.ts @@ -786,7 +786,7 @@ class DecorationCSSRules { } /** - * Build the CSS for decorations styled via `glpyhMarginClassName`. + * Build the CSS for decorations styled via `glyphMarginClassName`. */ private getCSSTextForModelDecorationGlyphMarginClassName(opts: IThemeDecorationRenderOptions | undefined): string { if (!opts) { diff --git a/src/vs/editor/browser/view.ts b/src/vs/editor/browser/view.ts index 922e0dd6e52..82d1fb7a269 100644 --- a/src/vs/editor/browser/view.ts +++ b/src/vs/editor/browser/view.ts @@ -5,13 +5,14 @@ import * as dom from 'vs/base/browser/dom'; import { Selection } from 'vs/editor/common/core/selection'; +import { Range } from 'vs/editor/common/core/range'; import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode'; import { onUnexpectedError } from 'vs/base/common/errors'; import { IDisposable } from 'vs/base/common/lifecycle'; import { IPointerHandlerHelper } from 'vs/editor/browser/controller/mouseHandler'; import { PointerHandler } from 'vs/editor/browser/controller/pointerHandler'; import { IVisibleRangeProvider, TextAreaHandler } from 'vs/editor/browser/controller/textAreaHandler'; -import { IContentWidget, IContentWidgetPosition, IOverlayWidget, IOverlayWidgetPosition, IMouseTarget, IViewZoneChangeAccessor, IEditorAriaOptions } from 'vs/editor/browser/editorBrowser'; +import { IContentWidget, IContentWidgetPosition, IOverlayWidget, IOverlayWidgetPosition, IMouseTarget, IViewZoneChangeAccessor, IEditorAriaOptions, IGlyphMarginWidget, IGlyphMarginWidgetPosition } from 'vs/editor/browser/editorBrowser'; import { ICommandDelegate, ViewController } from 'vs/editor/browser/view/viewController'; import { ViewUserInputEvents } from 'vs/editor/browser/view/viewUserInputEvents'; import { ContentViewOverlays, MarginViewOverlays } from 'vs/editor/browser/view/viewOverlays'; @@ -20,7 +21,6 @@ import { ViewContentWidgets } from 'vs/editor/browser/viewParts/contentWidgets/c import { CurrentLineHighlightOverlay, CurrentLineMarginHighlightOverlay } from 'vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight'; import { DecorationsOverlay } from 'vs/editor/browser/viewParts/decorations/decorations'; import { EditorScrollbar } from 'vs/editor/browser/viewParts/editorScrollbar/editorScrollbar'; -import { GlyphMarginOverlay } from 'vs/editor/browser/viewParts/glyphMargin/glyphMargin'; import { IndentGuidesOverlay } from 'vs/editor/browser/viewParts/indentGuides/indentGuides'; import { LineNumbersOverlay } from 'vs/editor/browser/viewParts/lineNumbers/lineNumbers'; import { ViewLines } from 'vs/editor/browser/viewParts/lines/viewLines'; @@ -52,6 +52,8 @@ import { BlockDecorations } from 'vs/editor/browser/viewParts/blockDecorations/b import { inputLatency } from 'vs/base/browser/performance'; import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; import { WhitespaceOverlay } from 'vs/editor/browser/viewParts/whitespace/whitespace'; +import { GlyphMarginWidgets } from 'vs/editor/browser/viewParts/glyphMargin/glyphMargin'; +import { GlyphMarginLane } from 'vs/editor/common/model'; export interface IContentWidgetData { @@ -64,6 +66,11 @@ export interface IOverlayWidgetData { position: IOverlayWidgetPosition | null; } +export interface IGlyphMarginWidgetData { + widget: IGlyphMarginWidget; + position: IGlyphMarginWidgetPosition; +} + export class View extends ViewEventHandler { private readonly _scrollbar: EditorScrollbar; @@ -77,6 +84,7 @@ export class View extends ViewEventHandler { private readonly _viewZones: ViewZones; private readonly _contentWidgets: ViewContentWidgets; private readonly _overlayWidgets: ViewOverlayWidgets; + private readonly _glyphMarginWidgets: GlyphMarginWidgets; private readonly _viewCursors: ViewCursors; private readonly _viewParts: ViewPart[]; @@ -89,6 +97,7 @@ export class View extends ViewEventHandler { private readonly _overflowGuardContainer: FastDomNode; // Actual mutable state + private _shouldRecomputeGlyphMarginLanes: boolean = false; private _renderAnimationFrame: IDisposable | null; constructor( @@ -160,14 +169,18 @@ export class View extends ViewEventHandler { const marginViewOverlays = new MarginViewOverlays(this._context); this._viewParts.push(marginViewOverlays); marginViewOverlays.addDynamicOverlay(new CurrentLineMarginHighlightOverlay(this._context)); - marginViewOverlays.addDynamicOverlay(new GlyphMarginOverlay(this._context)); marginViewOverlays.addDynamicOverlay(new MarginViewLineDecorationsOverlay(this._context)); marginViewOverlays.addDynamicOverlay(new LinesDecorationsOverlay(this._context)); marginViewOverlays.addDynamicOverlay(new LineNumbersOverlay(this._context)); + // Glyph margin widgets + this._glyphMarginWidgets = new GlyphMarginWidgets(this._context); + this._viewParts.push(this._glyphMarginWidgets); + const margin = new Margin(this._context); margin.getDomNode().appendChild(this._viewZones.marginDomNode); margin.getDomNode().appendChild(marginViewOverlays.getDomNode()); + margin.getDomNode().appendChild(this._glyphMarginWidgets.domNode); this._viewParts.push(margin); // Content widgets @@ -226,10 +239,70 @@ export class View extends ViewEventHandler { } private _flushAccumulatedAndRenderNow(): void { + if (this._shouldRecomputeGlyphMarginLanes) { + this._shouldRecomputeGlyphMarginLanes = false; + this._context.configuration.setGlyphMarginDecorationLaneCount(this._computeGlyphMarginLaneCount()); + } inputLatency.onRenderStart(); this._renderNow(); } + private _computeGlyphMarginLaneCount(): number { + const model = this._context.viewModel.model; + type Glyph = { range: Range; lane: GlyphMarginLane }; + let glyphs: Glyph[] = []; + + // Add all margin decorations + glyphs = glyphs.concat(model.getAllMarginDecorations().map((decoration) => { + const lane = decoration.options.glyphMargin?.position ?? GlyphMarginLane.Left; + return { range: decoration.range, lane }; + })); + + // Add all glyph margin widgets + glyphs = glyphs.concat(this._glyphMarginWidgets.getWidgets().map((widget) => { + const range = model.validateRange(widget.preference.range); + return { range, lane: widget.preference.lane }; + })); + + // Sorted by their start position + glyphs.sort((a, b) => Range.compareRangesUsingStarts(a.range, b.range)); + + let leftDecRange: Range | null = null; + let rightDecRange: Range | null = null; + for (const decoration of glyphs) { + + if (decoration.lane === GlyphMarginLane.Left && (!leftDecRange || Range.compareRangesUsingEnds(leftDecRange, decoration.range) < 0)) { + // assign only if the range of `decoration` ends after, which means it has a higher chance to overlap with the other lane + leftDecRange = decoration.range; + } + + if (decoration.lane === GlyphMarginLane.Right && (!rightDecRange || Range.compareRangesUsingEnds(rightDecRange, decoration.range) < 0)) { + // assign only if the range of `decoration` ends after, which means it has a higher chance to overlap with the other lane + rightDecRange = decoration.range; + } + + if (leftDecRange && rightDecRange) { + + if (leftDecRange.endLineNumber < rightDecRange.startLineNumber) { + // there's no chance for `leftDecRange` to ever intersect something going further + leftDecRange = null; + continue; + } + + if (rightDecRange.endLineNumber < leftDecRange.startLineNumber) { + // there's no chance for `rightDecRange` to ever intersect something going further + rightDecRange = null; + continue; + } + + // leftDecRange and rightDecRange are intersecting or touching => we need two lanes + return 2; + } + } + + return 1; + } + private _createPointerHandlerHelper(): IPointerHandlerHelper { return { viewDomNode: this.domNode.domNode, @@ -317,6 +390,12 @@ export class View extends ViewEventHandler { this._selections = e.selections; return false; } + public override onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean { + if (e.affectsGlyphMargin) { + this._shouldRecomputeGlyphMarginLanes = true; + } + return false; + } public override onFocusChanged(e: viewEvents.ViewFocusChangedEvent): boolean { this.domNode.setClassName(this._getEditorClassName()); return false; @@ -548,6 +627,27 @@ export class View extends ViewEventHandler { this._scheduleRender(); } + public addGlyphMarginWidget(widgetData: IGlyphMarginWidgetData): void { + this._glyphMarginWidgets.addWidget(widgetData.widget); + this._shouldRecomputeGlyphMarginLanes = true; + this._scheduleRender(); + } + + public layoutGlyphMarginWidget(widgetData: IGlyphMarginWidgetData): void { + const newPreference = widgetData.position; + const shouldRender = this._glyphMarginWidgets.setWidgetPosition(widgetData.widget, newPreference); + if (shouldRender) { + this._shouldRecomputeGlyphMarginLanes = true; + this._scheduleRender(); + } + } + + public removeGlyphMarginWidget(widgetData: IGlyphMarginWidgetData): void { + this._glyphMarginWidgets.removeWidget(widgetData.widget); + this._shouldRecomputeGlyphMarginLanes = true; + this._scheduleRender(); + } + // --- END CodeEditor helpers } diff --git a/src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.ts b/src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.ts index 0b35f4b06ed..919d0aad1f9 100644 --- a/src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.ts +++ b/src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.ts @@ -3,14 +3,22 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode'; +import { ArrayQueue } from 'vs/base/common/arrays'; import 'vs/css!./glyphMargin'; +import { IGlyphMarginWidget, IGlyphMarginWidgetPosition } from 'vs/editor/browser/editorBrowser'; import { DynamicViewOverlay } from 'vs/editor/browser/view/dynamicViewOverlay'; -import { RenderingContext } from 'vs/editor/browser/view/renderingContext'; -import { ViewContext } from 'vs/editor/common/viewModel/viewContext'; -import * as viewEvents from 'vs/editor/common/viewEvents'; +import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/browser/view/renderingContext'; +import { ViewPart } from 'vs/editor/browser/view/viewPart'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; +import { Range } from 'vs/editor/common/core/range'; +import * as viewEvents from 'vs/editor/common/viewEvents'; +import { ViewContext } from 'vs/editor/common/viewModel/viewContext'; - +/** + * Represents a decoration that should be shown along the lines from `startLineNumber` to `endLineNumber`. + * This can end up producing multiple `LineDecorationToRender`. + */ export class DecorationToRender { _decorationToRenderBrand: void = undefined; @@ -18,66 +26,59 @@ export class DecorationToRender { public endLineNumber: number; public className: string; public readonly zIndex: number; - public readonly decorationLane: number; - constructor(startLineNumber: number, endLineNumber: number, className: string, zIndex?: number, decorationLane?: number) { + constructor(startLineNumber: number, endLineNumber: number, className: string, zIndex: number | undefined) { this.startLineNumber = +startLineNumber; this.endLineNumber = +endLineNumber; this.className = String(className); this.zIndex = zIndex ?? 0; - this.decorationLane = decorationLane ?? 1; } } -export class RenderedDecoration { +/** + * A decoration that should be shown along a line. + */ +export class LineDecorationToRender { constructor( public readonly className: string, public readonly zIndex: number, ) { } } -export class LineRenderedDecorations { +/** + * Decorations to render on a visible line. + */ +export class VisibleLineDecorationsToRender { - private readonly lanes: RenderedDecoration[][] = []; + private readonly decorations: LineDecorationToRender[] = []; - public add(lane: number, decoration: RenderedDecoration) { - while (lane >= this.lanes.length) { - this.lanes.push([]); - } - this.lanes[lane].push(decoration); + public add(decoration: LineDecorationToRender) { + this.decorations.push(decoration); } - public getLaneDecorations(laneIndex: number): RenderedDecoration[] { - if (laneIndex < this.lanes.length) { - return this.lanes[laneIndex]; - } - return []; - } - - public isEmpty(): boolean { - for (const lane of this.lanes) { - if (lane.length > 0) { - return false; - } - } - return true; + public getDecorations(): LineDecorationToRender[] { + return this.decorations; } } export abstract class DedupOverlay extends DynamicViewOverlay { - protected _render(visibleStartLineNumber: number, visibleEndLineNumber: number, decorations: DecorationToRender[], decorationLaneCount: number): LineRenderedDecorations[] { + /** + * Returns an array with an element for each visible line number. + */ + protected _render(visibleStartLineNumber: number, visibleEndLineNumber: number, decorations: DecorationToRender[]): VisibleLineDecorationsToRender[] { - const output: LineRenderedDecorations[] = []; + const output: VisibleLineDecorationsToRender[] = []; for (let lineNumber = visibleStartLineNumber; lineNumber <= visibleEndLineNumber; lineNumber++) { const lineIndex = lineNumber - visibleStartLineNumber; - output[lineIndex] = new LineRenderedDecorations(); + output[lineIndex] = new VisibleLineDecorationsToRender(); } if (decorations.length === 0) { return output; } + // Sort decorations by className, then by startLineNumber and then by endLineNumber decorations.sort((a, b) => { if (a.className === b.className) { if (a.startLineNumber === b.startLineNumber) { @@ -96,9 +97,9 @@ export abstract class DedupOverlay extends DynamicViewOverlay { const zIndex = d.zIndex; let startLineIndex = Math.max(d.startLineNumber, visibleStartLineNumber) - visibleStartLineNumber; const endLineIndex = Math.min(d.endLineNumber, visibleEndLineNumber) - visibleStartLineNumber; - const lane = Math.min(d.decorationLane, decorationLaneCount); if (prevClassName === className) { + // Here we avoid rendering the same className multiple times on the same line startLineIndex = Math.max(prevEndLineIndex + 1, startLineIndex); prevEndLineIndex = Math.max(prevEndLineIndex, endLineIndex); } else { @@ -107,7 +108,7 @@ export abstract class DedupOverlay extends DynamicViewOverlay { } for (let i = startLineIndex; i <= prevEndLineIndex; i++) { - output[i].add(lane, new RenderedDecoration(className, zIndex)); + output[i].add(new LineDecorationToRender(className, zIndex)); } } @@ -115,40 +116,54 @@ export abstract class DedupOverlay extends DynamicViewOverlay { } } -export class GlyphMarginOverlay extends DedupOverlay { +export class GlyphMarginWidgets extends ViewPart { + + public domNode: FastDomNode; - private readonly _context: ViewContext; private _lineHeight: number; private _glyphMargin: boolean; private _glyphMarginLeft: number; private _glyphMarginWidth: number; private _glyphMarginDecorationLaneCount: number; - private _renderResult: string[] | null; + + private _managedDomNodes: FastDomNode[]; + private _decorationGlyphsToRender: DecorationBasedGlyph[]; + + private _widgets: { [key: string]: IWidgetData } = {}; constructor(context: ViewContext) { - super(); + super(context); this._context = context; const options = this._context.configuration.options; const layoutInfo = options.get(EditorOption.layoutInfo); + this.domNode = createFastDomNode(document.createElement('div')); + this.domNode.setClassName('glyphMarginWidgets'); + this.domNode.setPosition('absolute'); + this.domNode.setTop(0); + this._lineHeight = options.get(EditorOption.lineHeight); this._glyphMargin = options.get(EditorOption.glyphMargin); this._glyphMarginLeft = layoutInfo.glyphMarginLeft; this._glyphMarginWidth = layoutInfo.glyphMarginWidth; this._glyphMarginDecorationLaneCount = layoutInfo.glyphMarginDecorationLaneCount; - this._renderResult = null; - this._context.addEventHandler(this); + this._managedDomNodes = []; + this._decorationGlyphsToRender = []; } public override dispose(): void { - this._context.removeEventHandler(this); - this._renderResult = null; + this._managedDomNodes = []; + this._decorationGlyphsToRender = []; + this._widgets = {}; super.dispose(); } - // --- begin event handlers + public getWidgets(): IWidgetData[] { + return Object.values(this._widgets); + } + // --- begin event handlers public override onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { const options = this._context.configuration.options; const layoutInfo = options.get(EditorOption.layoutInfo); @@ -184,85 +199,302 @@ export class GlyphMarginOverlay extends DedupOverlay { // --- end event handlers - protected _getDecorations(ctx: RenderingContext): DecorationToRender[] { - const decorations = ctx.getDecorationsInViewport(); - const r: DecorationToRender[] = []; - let rLen = 0; - for (let i = 0, len = decorations.length; i < len; i++) { - const d = decorations[i]; - const glyphMarginClassName = d.options.glyphMarginClassName; - const zIndex = d.options.zIndex; - const lane = d.options.glyphMargin?.position; - if (glyphMarginClassName) { - r[rLen++] = new DecorationToRender(d.range.startLineNumber, d.range.endLineNumber, glyphMarginClassName, zIndex, lane); - } - } - return r; + // --- begin widget management + + public addWidget(widget: IGlyphMarginWidget): void { + const domNode = createFastDomNode(widget.getDomNode()); + + this._widgets[widget.getId()] = { + widget: widget, + preference: widget.getPosition(), + domNode: domNode, + renderInfo: null + }; + + domNode.setPosition('absolute'); + domNode.setDisplay('none'); + domNode.setAttribute('widgetId', widget.getId()); + this.domNode.appendChild(domNode); + + this.setShouldRender(); } + public setWidgetPosition(widget: IGlyphMarginWidget, preference: IGlyphMarginWidgetPosition): boolean { + const myWidget = this._widgets[widget.getId()]; + if (myWidget.preference.lane === preference.lane + && myWidget.preference.zIndex === preference.zIndex + && Range.equalsRange(myWidget.preference.range, preference.range)) { + return false; + } + + myWidget.preference = preference; + this.setShouldRender(); + + return true; + } + + public removeWidget(widget: IGlyphMarginWidget): void { + const widgetId = widget.getId(); + if (this._widgets[widgetId]) { + const widgetData = this._widgets[widgetId]; + const domNode = widgetData.domNode.domNode; + delete this._widgets[widgetId]; + + domNode.parentNode?.removeChild(domNode); + this.setShouldRender(); + } + } + + // --- end widget management + + private _collectDecorationBasedGlyphRenderRequest(ctx: RenderingContext, requests: GlyphRenderRequest[]): void { + const visibleStartLineNumber = ctx.visibleRange.startLineNumber; + const visibleEndLineNumber = ctx.visibleRange.endLineNumber; + const decorations = ctx.getDecorationsInViewport(); + + for (const d of decorations) { + const glyphMarginClassName = d.options.glyphMarginClassName; + if (!glyphMarginClassName) { + continue; + } + + const startLineNumber = Math.max(d.range.startLineNumber, visibleStartLineNumber); + const endLineNumber = Math.min(d.range.endLineNumber, visibleEndLineNumber); + const lane = Math.min(d.options.glyphMargin?.position ?? 1, this._glyphMarginDecorationLaneCount); + const zIndex = d.options.zIndex ?? 0; + + for (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) { + requests.push(new DecorationBasedGlyphRenderRequest(lineNumber, lane, zIndex, glyphMarginClassName)); + } + } + } + + private _collectWidgetBasedGlyphRenderRequest(ctx: RenderingContext, requests: GlyphRenderRequest[]): void { + const visibleStartLineNumber = ctx.visibleRange.startLineNumber; + const visibleEndLineNumber = ctx.visibleRange.endLineNumber; + + for (const widget of Object.values(this._widgets)) { + const range = widget.preference.range; + if (range.endLineNumber < visibleStartLineNumber || range.startLineNumber > visibleEndLineNumber) { + // The widget is not in the viewport + continue; + } + + // The widget is in the viewport, find a good line for it + const widgetLineNumber = Math.max(range.startLineNumber, visibleStartLineNumber); + const lane = Math.min(widget.preference.lane, this._glyphMarginDecorationLaneCount); + requests.push(new WidgetBasedGlyphRenderRequest(widgetLineNumber, lane, widget.preference.zIndex, widget)); + } + } + + private _collectSortedGlyphRenderRequests(ctx: RenderingContext): GlyphRenderRequest[] { + + const requests: GlyphRenderRequest[] = []; + + this._collectDecorationBasedGlyphRenderRequest(ctx, requests); + this._collectWidgetBasedGlyphRenderRequest(ctx, requests); + + // sort requests by lineNumber ASC, lane ASC, zIndex DESC, type DESC (widgets first), className ASC + // don't change this sort unless you understand `prepareRender` below. + requests.sort((a, b) => { + if (a.lineNumber === b.lineNumber) { + if (a.lane === b.lane) { + if (a.zIndex === b.zIndex) { + if (b.type === a.type) { + if (a.type === GlyphRenderRequestType.Decoration && b.type === GlyphRenderRequestType.Decoration) { + return (a.className < b.className ? -1 : 1); + } + return 0; + } + return b.type - a.type; + } + return b.zIndex - a.zIndex; + } + return a.lane - b.lane; + } + return a.lineNumber - b.lineNumber; + }); + + return requests; + } + + /** + * Will store render information in each widget's renderInfo and in `_decorationGlyphsToRender`. + */ public prepareRender(ctx: RenderingContext): void { if (!this._glyphMargin) { - this._renderResult = null; + this._decorationGlyphsToRender = []; return; } - const visibleStartLineNumber = ctx.visibleRange.startLineNumber; - const visibleEndLineNumber = ctx.visibleRange.endLineNumber; - const decorationsToRender = this._getDecorations(ctx); - const toRender = this._render(visibleStartLineNumber, visibleEndLineNumber, decorationsToRender, this._glyphMarginDecorationLaneCount); + for (const widget of Object.values(this._widgets)) { + widget.renderInfo = null; + } - const lineHeight = this._lineHeight.toString(); - const width = (Math.round(this._glyphMarginWidth / this._glyphMarginDecorationLaneCount)).toString(); - const common = '" style="width:' + width + 'px' + ';height:' + lineHeight + 'px;'; + const requests = new ArrayQueue(this._collectSortedGlyphRenderRequests(ctx)); + const decorationGlyphsToRender: DecorationBasedGlyph[] = []; + while (requests.length > 0) { + const first = requests.peek(); + if (!first) { + // not possible + break; + } - const output: string[] = []; - for (let lineNumber = visibleStartLineNumber; lineNumber <= visibleEndLineNumber; lineNumber++) { - const lineIndex = lineNumber - visibleStartLineNumber; - const renderInfo = toRender[lineIndex]; + // Requests are sorted by lineNumber and lane, so we read all requests for this particular location + const requestsAtLocation = requests.takeWhile((el) => el.lineNumber === first.lineNumber && el.lane === first.lane); + if (!requestsAtLocation || requestsAtLocation.length === 0) { + // not possible + break; + } - if (renderInfo.isEmpty()) { - output[lineIndex] = ''; - } else { - let css = ''; - for (let lane = 1; lane <= this._glyphMarginDecorationLaneCount; lane += 1) { - const decorations = renderInfo.getLaneDecorations(lane); - if (decorations.length === 0) { - continue; + const winner = requestsAtLocation[0]; + if (winner.type === GlyphRenderRequestType.Decoration) { + // combine all decorations with the same z-index + + const classNames: string[] = []; + // requests are sorted by zIndex, type, and className so we can dedup className by looking at the previous one + for (const request of requestsAtLocation) { + if (request.zIndex !== winner.zIndex || request.type !== winner.type) { + break; } - decorations.sort((a, b) => b.zIndex - a.zIndex); - // Render winning decorations with the same zIndex together - const winningDecoration: RenderedDecoration = decorations[0]; - const winningDecorationClassNames = [winningDecoration.className]; - for (let i = 1; i < decorations.length; i += 1) { - const decoration = decorations[i]; - if (decoration.zIndex !== winningDecoration.zIndex) { - break; - } - winningDecorationClassNames.push(decoration.className); + if (classNames.length === 0 || classNames[classNames.length - 1] !== request.className) { + classNames.push(request.className); } - const left = (this._glyphMarginLeft + (lane - 1) * this._lineHeight).toString(); - css += ( - '
' - ); } - output[lineIndex] = css; + + decorationGlyphsToRender.push(winner.accept(classNames.join(' '))); // TODO@joyceerhl Implement overflow for remaining decorations + } else { + // widgets cannot be combined + winner.widget.renderInfo = { + lineNumber: winner.lineNumber, + lane: winner.lane, + }; + } + } + this._decorationGlyphsToRender = decorationGlyphsToRender; + } + + public render(ctx: RestrictedRenderingContext): void { + if (!this._glyphMargin) { + for (const widget of Object.values(this._widgets)) { + widget.domNode.setDisplay('none'); + } + while (this._managedDomNodes.length > 0) { + const domNode = this._managedDomNodes.pop(); + domNode?.domNode.remove(); + } + return; + } + + const width = (Math.round(this._glyphMarginWidth / this._glyphMarginDecorationLaneCount)); + + // Render widgets + for (const widget of Object.values(this._widgets)) { + if (!widget.renderInfo) { + // this widget is not visible + widget.domNode.setDisplay('none'); + } else { + const top = ctx.viewportData.relativeVerticalOffset[widget.renderInfo.lineNumber - ctx.viewportData.startLineNumber]; + const left = this._glyphMarginLeft + (widget.renderInfo.lane - 1) * this._lineHeight; + + widget.domNode.setDisplay('block'); + widget.domNode.setTop(top); + widget.domNode.setLeft(left); + widget.domNode.setWidth(width); + widget.domNode.setHeight(this._lineHeight); } } - this._renderResult = output; - } + // Render decorations, reusing previous dom nodes as possible + for (let i = 0; i < this._decorationGlyphsToRender.length; i++) { + const dec = this._decorationGlyphsToRender[i]; + const top = ctx.viewportData.relativeVerticalOffset[dec.lineNumber - ctx.viewportData.startLineNumber]; + const left = this._glyphMarginLeft + (dec.lane - 1) * this._lineHeight; - public render(startLineNumber: number, lineNumber: number): string { - if (!this._renderResult) { - return ''; + let domNode: FastDomNode; + if (i < this._managedDomNodes.length) { + domNode = this._managedDomNodes[i]; + } else { + domNode = createFastDomNode(document.createElement('div')); + this._managedDomNodes.push(domNode); + this.domNode.appendChild(domNode); + } + + domNode.setClassName(`cgmr codicon ` + dec.combinedClassName); + domNode.setPosition(`absolute`); + domNode.setTop(top); + domNode.setLeft(left); + domNode.setWidth(width); + domNode.setHeight(this._lineHeight); } - const lineIndex = lineNumber - startLineNumber; - if (lineIndex < 0 || lineIndex >= this._renderResult.length) { - return ''; + + // remove extra dom nodes + while (this._managedDomNodes.length > this._decorationGlyphsToRender.length) { + const domNode = this._managedDomNodes.pop(); + domNode?.domNode.remove(); } - return this._renderResult[lineIndex]; } } + +export interface IWidgetData { + widget: IGlyphMarginWidget; + preference: IGlyphMarginWidgetPosition; + domNode: FastDomNode; + /** + * it will contain the location where to render the widget + * or null if the widget is not visible + */ + renderInfo: IRenderInfo | null; +} + +export interface IRenderInfo { + lineNumber: number; + lane: number; +} + +const enum GlyphRenderRequestType { + Decoration = 0, + Widget = 1 +} + +/** + * A request to render a decoration in the glyph margin at a certain location. + */ +class DecorationBasedGlyphRenderRequest { + public readonly type = GlyphRenderRequestType.Decoration; + + constructor( + public readonly lineNumber: number, + public readonly lane: number, + public readonly zIndex: number, + public readonly className: string, + ) { } + + accept(combinedClassName: string): DecorationBasedGlyph { + return new DecorationBasedGlyph(this.lineNumber, this.lane, combinedClassName); + } +} + +/** + * A request to render a widget in the glyph margin at a certain location. + */ +class WidgetBasedGlyphRenderRequest { + public readonly type = GlyphRenderRequestType.Widget; + + constructor( + public readonly lineNumber: number, + public readonly lane: number, + public readonly zIndex: number, + public readonly widget: IWidgetData, + ) { } +} + +type GlyphRenderRequest = DecorationBasedGlyphRenderRequest | WidgetBasedGlyphRenderRequest; + +class DecorationBasedGlyph { + constructor( + public readonly lineNumber: number, + public readonly lane: number, + public readonly combinedClassName: string + ) { } +} diff --git a/src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.ts b/src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.ts index 9ed72e6acf0..95d8caaed51 100644 --- a/src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.ts +++ b/src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.ts @@ -91,7 +91,7 @@ export class LinesDecorationsOverlay extends DedupOverlay { public prepareRender(ctx: RenderingContext): void { const visibleStartLineNumber = ctx.visibleRange.startLineNumber; const visibleEndLineNumber = ctx.visibleRange.endLineNumber; - const toRender = this._render(visibleStartLineNumber, visibleEndLineNumber, this._getDecorations(ctx), 1); + const toRender = this._render(visibleStartLineNumber, visibleEndLineNumber, this._getDecorations(ctx)); const left = this._decorationsLeft.toString(); const width = this._decorationsWidth.toString(); @@ -100,7 +100,7 @@ export class LinesDecorationsOverlay extends DedupOverlay { const output: string[] = []; for (let lineNumber = visibleStartLineNumber; lineNumber <= visibleEndLineNumber; lineNumber++) { const lineIndex = lineNumber - visibleStartLineNumber; - const decorations = toRender[lineIndex].getLaneDecorations(1); // there is only one lane, see _render call above + const decorations = toRender[lineIndex].getDecorations(); let lineOutput = ''; for (const decoration of decorations) { lineOutput += '
'; diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index dedb0237589..d970536c421 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -21,7 +21,7 @@ import * as editorBrowser from 'vs/editor/browser/editorBrowser'; import { EditorExtensionsRegistry, IEditorContributionDescription } from 'vs/editor/browser/editorExtensions'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { ICommandDelegate } from 'vs/editor/browser/view/viewController'; -import { IContentWidgetData, IOverlayWidgetData, View } from 'vs/editor/browser/view'; +import { IContentWidgetData, IGlyphMarginWidgetData, IOverlayWidgetData, View } from 'vs/editor/browser/view'; import { ViewUserInputEvents } from 'vs/editor/browser/view/viewUserInputEvents'; import { ConfigurationChangedEvent, EditorLayoutInfo, IEditorOptions, EditorOption, IComputedEditorOptions, FindComputedEditorOptionValueById, filterValidationDecorations } from 'vs/editor/common/config/editorOptions'; import { CursorColumns } from 'vs/editor/common/core/cursorColumns'; @@ -255,6 +255,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE private _contentWidgets: { [key: string]: IContentWidgetData }; private _overlayWidgets: { [key: string]: IOverlayWidgetData }; + private _glyphMarginWidgets: { [key: string]: IGlyphMarginWidgetData }; /** * map from "parent" decoration type to live decoration ids. @@ -323,6 +324,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE this._contentWidgets = {}; this._overlayWidgets = {}; + this._glyphMarginWidgets = {}; let contributions: IEditorContributionDescription[]; if (Array.isArray(codeEditorWidgetOptions.contributions)) { @@ -1510,6 +1512,45 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE } } + public addGlyphMarginWidget(widget: editorBrowser.IGlyphMarginWidget): void { + const widgetData: IGlyphMarginWidgetData = { + widget: widget, + position: widget.getPosition() + }; + + if (this._glyphMarginWidgets.hasOwnProperty(widget.getId())) { + console.warn('Overwriting a glyph margin widget with the same id.'); + } + + this._glyphMarginWidgets[widget.getId()] = widgetData; + + if (this._modelData && this._modelData.hasRealView) { + this._modelData.view.addGlyphMarginWidget(widgetData); + } + } + + public layoutGlyphMarginWidget(widget: editorBrowser.IGlyphMarginWidget): void { + const widgetId = widget.getId(); + if (this._glyphMarginWidgets.hasOwnProperty(widgetId)) { + const widgetData = this._glyphMarginWidgets[widgetId]; + widgetData.position = widget.getPosition(); + if (this._modelData && this._modelData.hasRealView) { + this._modelData.view.layoutGlyphMarginWidget(widgetData); + } + } + } + + public removeGlyphMarginWidget(widget: editorBrowser.IGlyphMarginWidget): void { + const widgetId = widget.getId(); + if (this._glyphMarginWidgets.hasOwnProperty(widgetId)) { + const widgetData = this._glyphMarginWidgets[widgetId]; + delete this._glyphMarginWidgets[widgetId]; + if (this._modelData && this._modelData.hasRealView) { + this._modelData.view.removeGlyphMarginWidget(widgetData); + } + } + } + public changeViewZones(callback: (accessor: editorBrowser.IViewZoneChangeAccessor) => void): void { if (!this._modelData || !this._modelData.hasRealView) { return; @@ -1718,6 +1759,12 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE view.addOverlayWidget(this._overlayWidgets[widgetId]); } + keys = Object.keys(this._glyphMarginWidgets); + for (let i = 0, len = keys.length; i < len; i++) { + const widgetId = keys[i]; + view.addGlyphMarginWidget(this._glyphMarginWidgets[widgetId]); + } + view.render(false, true); view.domNode.domNode.setAttribute('data-uri', model.uri.toString()); } diff --git a/src/vs/editor/common/viewModel/viewModelImpl.ts b/src/vs/editor/common/viewModel/viewModelImpl.ts index cf61c0bac20..eb18dced3c1 100644 --- a/src/vs/editor/common/viewModel/viewModelImpl.ts +++ b/src/vs/editor/common/viewModel/viewModelImpl.ts @@ -19,7 +19,7 @@ import { Range } from 'vs/editor/common/core/range'; import { ISelection, Selection } from 'vs/editor/common/core/selection'; import { ICommand, ICursorState, IViewState, ScrollType } from 'vs/editor/common/editorCommon'; import { IEditorConfiguration } from 'vs/editor/common/config/editorConfiguration'; -import { EndOfLinePreference, GlyphMarginLane, IAttachedView, ICursorStateComputer, IIdentifiedSingleEditOperation, ITextModel, PositionAffinity, TrackedRangeStickiness } from 'vs/editor/common/model'; +import { EndOfLinePreference, IAttachedView, ICursorStateComputer, IIdentifiedSingleEditOperation, ITextModel, PositionAffinity, TrackedRangeStickiness } from 'vs/editor/common/model'; import { IActiveIndentGuideInfo, BracketGuideOptions, IndentGuide } from 'vs/editor/common/textModelGuides'; import { ModelDecorationMinimapOptions, ModelDecorationOptions, ModelDecorationOverviewRulerOptions } from 'vs/editor/common/model/textModel'; import * as textModelEvents from 'vs/editor/common/textModelEvents'; @@ -459,54 +459,6 @@ export class ViewModel extends Disposable implements IViewModel { this._register(this.model.onDidChangeDecorations((e) => { this._decorations.onModelDecorationsChanged(); - - // Determine whether we need to resize the glyph margin - if (e.affectsGlyphMargin) { - const decorations = this.model.getAllMarginDecorations(); - - let hasTwoLanes = false; - - // Decorations are already sorted by their start position, but protect against future changes - decorations.sort((a, b) => Range.compareRangesUsingStarts(a.range, b.range)); - - let leftDecRange: Range | null = null; - let rightDecRange: Range | null = null; - for (const decoration of decorations) { - const position = decoration.options.glyphMargin?.position ?? GlyphMarginLane.Left; - - if (position === GlyphMarginLane.Left && (!leftDecRange || Range.compareRangesUsingEnds(leftDecRange, decoration.range) < 0)) { - // assign only if the range of `decoration` ends after, which means it has a higher chance to overlap with the other lane - leftDecRange = decoration.range; - } - - if (position === GlyphMarginLane.Right && (!rightDecRange || Range.compareRangesUsingEnds(rightDecRange, decoration.range) < 0)) { - // assign only if the range of `decoration` ends after, which means it has a higher chance to overlap with the other lane - rightDecRange = decoration.range; - } - - if (leftDecRange && rightDecRange) { - - if (leftDecRange.endLineNumber < rightDecRange.startLineNumber) { - // there's no chance for `leftDecRange` to ever intersect something going further - leftDecRange = null; - continue; - } - - if (rightDecRange.endLineNumber < leftDecRange.startLineNumber) { - // there's no chance for `rightDecRange` to ever intersect something going further - rightDecRange = null; - continue; - } - - // leftDecRange and rightDecRange are intersecting or touching => we need two lanes - hasTwoLanes = true; - break; - } - } - - this._configuration.setGlyphMarginDecorationLaneCount(hasTwoLanes ? 2 : 1); - } - this._eventDispatcher.emitSingleViewEvent(new viewEvents.ViewDecorationsChangedEvent(e)); this._eventDispatcher.emitOutgoingEvent(new ModelDecorationsChangedEvent(e)); })); diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 07aec862a82..71cbeb1eca3 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -5389,6 +5389,43 @@ declare namespace monaco.editor { getPosition(): IOverlayWidgetPosition | null; } + /** + * A glyph margin widget renders in the editor glyph margin. + */ + export interface IGlyphMarginWidget { + /** + * Get a unique identifier of the glyph widget. + */ + getId(): string; + /** + * Get the dom node of the glyph widget. + */ + getDomNode(): HTMLElement; + /** + * Get the placement of the glyph widget. + */ + getPosition(): IGlyphMarginWidgetPosition; + } + + /** + * A position for rendering glyph margin widgets. + */ + export interface IGlyphMarginWidgetPosition { + /** + * The glyph margin lane where the widget should be shown. + */ + lane: GlyphMarginLane; + /** + * The priority order of the widget, used for determining which widget + * to render when there are multiple. + */ + zIndex: number; + /** + * The editor range that this widget applies to. + */ + range: IRange; + } + /** * Type of hit element with the mouse in the editor. */ @@ -5961,6 +5998,19 @@ declare namespace monaco.editor { * Remove an overlay widget. */ removeOverlayWidget(widget: IOverlayWidget): void; + /** + * Add a glyph margin widget. Widgets must have unique ids, otherwise they will be overwritten. + */ + addGlyphMarginWidget(widget: IGlyphMarginWidget): void; + /** + * Layout/Reposition a glyph margin widget. This is a ping to the editor to call widget.getPosition() + * and update appropriately. + */ + layoutGlyphMarginWidget(widget: IGlyphMarginWidget): void; + /** + * Remove a glyph margin widget. + */ + removeGlyphMarginWidget(widget: IGlyphMarginWidget): void; /** * Change the view zones. View zones are lost when a new model is attached to the editor. */ From e4324a5cb61d439631ed640c15f36b35e511d632 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 16 Jun 2023 16:34:52 +0200 Subject: [PATCH 38/69] chore - StopWatch sugar, make high-res the default, use `globalThis`, faster `_now` function (#185330) * chore - StopWatch sugar, make high-res the default, use `globalThis`, faster `_now` function * d'oh * make layerscheck happy --- src/vs/base/common/event.ts | 2 +- src/vs/base/common/stopwatch.ts | 18 ++++++++---------- src/vs/base/test/common/skipList.test.ts | 16 ++++++++-------- .../base/test/common/ternarySearchtree.test.ts | 2 +- .../browser/services/editorWorkerService.ts | 4 ++-- .../widget/workerBasedDocumentDiffProvider.ts | 2 +- .../common/services/editorSimpleWorker.ts | 2 +- .../editor/contrib/folding/browser/folding.ts | 3 +-- .../editor/contrib/suggest/browser/suggest.ts | 6 +++--- .../suggest/browser/suggestController.ts | 2 +- .../tokenization/browser/tokenization.ts | 2 +- .../api/browser/mainThreadNotebook.ts | 4 ++-- .../api/browser/mainThreadTerminalService.ts | 2 +- .../api/common/extHostLanguageFeatures.ts | 2 +- .../browser/snippetCompletionProvider.ts | 2 +- .../extensions/common/extensionHostManager.ts | 6 +++--- .../browser/languageDetectionSimpleWorker.ts | 2 +- 17 files changed, 37 insertions(+), 40 deletions(-) diff --git a/src/vs/base/common/event.ts b/src/vs/base/common/event.ts index 24547947c56..ef9e64c0aaf 100644 --- a/src/vs/base/common/event.ts +++ b/src/vs/base/common/event.ts @@ -755,7 +755,7 @@ export class EventProfiling { } start(listenerCount: number): void { - this._stopWatch = new StopWatch(true); + this._stopWatch = new StopWatch(); this.listenerCount = listenerCount; } diff --git a/src/vs/base/common/stopwatch.ts b/src/vs/base/common/stopwatch.ts index f38627afedb..e32c0dd9d91 100644 --- a/src/vs/base/common/stopwatch.ts +++ b/src/vs/base/common/stopwatch.ts @@ -3,22 +3,24 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { globals } from 'vs/base/common/platform'; +// fake definition so that the valid layers check won't trip on this +declare const globalThis: { performance?: { now(): number } }; -const hasPerformanceNow = (globals.performance && typeof globals.performance.now === 'function'); +const hasPerformanceNow = (globalThis.performance && typeof globalThis.performance.now === 'function'); export class StopWatch { - private _highResolution: boolean; private _startTime: number; private _stopTime: number; - public static create(highResolution: boolean = true): StopWatch { + private readonly _now: () => number; + + public static create(highResolution?: boolean): StopWatch { return new StopWatch(highResolution); } - constructor(highResolution: boolean) { - this._highResolution = hasPerformanceNow && highResolution; + constructor(highResolution?: boolean) { + this._now = hasPerformanceNow && highResolution === false ? Date.now : globalThis.performance!.now.bind(globalThis.performance); this._startTime = this._now(); this._stopTime = -1; } @@ -38,8 +40,4 @@ export class StopWatch { } return this._now() - this._startTime; } - - private _now(): number { - return this._highResolution ? globals.performance.now() : Date.now(); - } } diff --git a/src/vs/base/test/common/skipList.test.ts b/src/vs/base/test/common/skipList.test.ts index 9712f498f20..d9c75702f1c 100644 --- a/src/vs/base/test/common/skipList.test.ts +++ b/src/vs/base/test/common/skipList.test.ts @@ -154,18 +154,18 @@ suite('SkipList', function () { // init const list = new SkipList(cmp, max); - let sw = new StopWatch(true); + let sw = new StopWatch(); values.forEach(value => list.set(value, true)); sw.stop(); console.log(`[LIST] ${list.size} elements after ${sw.elapsed()}ms`); let array: number[] = []; - sw = new StopWatch(true); + sw = new StopWatch(); values.forEach(value => array = insertArraySorted(array, value)); sw.stop(); console.log(`[ARRAY] ${array.length} elements after ${sw.elapsed()}ms`); // get - sw = new StopWatch(true); + sw = new StopWatch(); const someValues = [...values].slice(0, values.size / 4); someValues.forEach(key => { const value = list.get(key); // find @@ -174,7 +174,7 @@ suite('SkipList', function () { }); sw.stop(); console.log(`[LIST] retrieve ${sw.elapsed()}ms (${(sw.elapsed() / (someValues.length * 2)).toPrecision(4)}ms/op)`); - sw = new StopWatch(true); + sw = new StopWatch(); someValues.forEach(key => { const idx = binarySearch(array, key, cmp); // find console.assert(idx >= 0, '[ARRAY] must have ' + key); @@ -185,13 +185,13 @@ suite('SkipList', function () { // insert - sw = new StopWatch(true); + sw = new StopWatch(); someValues.forEach(key => { list.set(-key, false); }); sw.stop(); console.log(`[LIST] insert ${sw.elapsed()}ms (${(sw.elapsed() / someValues.length).toPrecision(4)}ms/op)`); - sw = new StopWatch(true); + sw = new StopWatch(); someValues.forEach(key => { array = insertArraySorted(array, -key); }); @@ -199,14 +199,14 @@ suite('SkipList', function () { console.log(`[ARRAY] insert ${sw.elapsed()}ms (${(sw.elapsed() / someValues.length).toPrecision(4)}ms/op)`); // delete - sw = new StopWatch(true); + sw = new StopWatch(); someValues.forEach(key => { list.delete(key); // find list.delete(-key); // miss }); sw.stop(); console.log(`[LIST] delete ${sw.elapsed()}ms (${(sw.elapsed() / (someValues.length * 2)).toPrecision(4)}ms/op)`); - sw = new StopWatch(true); + sw = new StopWatch(); someValues.forEach(key => { array = delArraySorted(array, key); // find array = delArraySorted(array, -key); // miss diff --git a/src/vs/base/test/common/ternarySearchtree.test.ts b/src/vs/base/test/common/ternarySearchtree.test.ts index 4ad5d8bbebd..c2f27122730 100644 --- a/src/vs/base/test/common/ternarySearchtree.test.ts +++ b/src/vs/base/test/common/ternarySearchtree.test.ts @@ -961,7 +961,7 @@ suite.skip('TST, perf', function () { function perfTest(name: string, callback: Function) { test(name, function () { if (_profile) { console.profile(name); } - const sw = new StopWatch(true); + const sw = new StopWatch(); callback(); console.log(name, sw.elapsed()); if (_profile) { console.profileEnd(); } diff --git a/src/vs/editor/browser/services/editorWorkerService.ts b/src/vs/editor/browser/services/editorWorkerService.ts index ba5739df58e..a4ffe3053b5 100644 --- a/src/vs/editor/browser/services/editorWorkerService.ts +++ b/src/vs/editor/browser/services/editorWorkerService.ts @@ -143,7 +143,7 @@ export class EditorWorkerService extends Disposable implements IEditorWorkerServ if (!canSyncModel(this._modelService, resource)) { return Promise.resolve(edits); // File too large } - const sw = StopWatch.create(true); + const sw = StopWatch.create(); const result = this._workerManager.withWorker().then(client => client.computeMoreMinimalEdits(resource, edits, pretty)); result.finally(() => this._logService.trace('FORMAT#computeMoreMinimalEdits', resource.toString(true), sw.elapsed())); return Promise.race([result, timeout(1000).then(() => edits)]); @@ -158,7 +158,7 @@ export class EditorWorkerService extends Disposable implements IEditorWorkerServ if (!canSyncModel(this._modelService, resource)) { return Promise.resolve(edits); // File too large } - const sw = StopWatch.create(true); + const sw = StopWatch.create(); const result = this._workerManager.withWorker().then(client => client.computeHumanReadableDiff(resource, edits, { ignoreTrimWhitespace: false, maxComputationTimeMs: 1000, computeMoves: false, })).catch((err) => { onUnexpectedError(err); diff --git a/src/vs/editor/browser/widget/workerBasedDocumentDiffProvider.ts b/src/vs/editor/browser/widget/workerBasedDocumentDiffProvider.ts index eddfb9c0ad9..385b3686e9c 100644 --- a/src/vs/editor/browser/widget/workerBasedDocumentDiffProvider.ts +++ b/src/vs/editor/browser/widget/workerBasedDocumentDiffProvider.ts @@ -67,7 +67,7 @@ export class WorkerBasedDocumentDiffProvider implements IDocumentDiffProvider, I return c.result; } - const sw = StopWatch.create(true); + const sw = StopWatch.create(); const result = await this.editorWorkerService.computeDiff(original.uri, modified.uri, options, this.diffAlgorithm); const timeMs = sw.elapsed(); diff --git a/src/vs/editor/common/services/editorSimpleWorker.ts b/src/vs/editor/common/services/editorSimpleWorker.ts index 298a16f44b4..c8cddbcc6c9 100644 --- a/src/vs/editor/common/services/editorSimpleWorker.ts +++ b/src/vs/editor/common/services/editorSimpleWorker.ts @@ -685,7 +685,7 @@ export class EditorSimpleWorker implements IRequestHandler, IDisposable { public async textualSuggest(modelUrls: string[], leadingWord: string | undefined, wordDef: string, wordDefFlags: string): Promise<{ words: string[]; duration: number } | null> { - const sw = new StopWatch(true); + const sw = new StopWatch(); const wordDefRegExp = new RegExp(wordDef, wordDefFlags); const seen = new Set(); diff --git a/src/vs/editor/contrib/folding/browser/folding.ts b/src/vs/editor/contrib/folding/browser/folding.ts index d87acd50139..8fe86b49ed8 100644 --- a/src/vs/editor/contrib/folding/browser/folding.ts +++ b/src/vs/editor/contrib/folding/browser/folding.ts @@ -311,7 +311,7 @@ export class FoldingController extends Disposable implements IEditorContribution if (!foldingModel) { // null if editor has been disposed, or folding turned off return null; } - const sw = new StopWatch(true); + const sw = new StopWatch(); const provider = this.getRangeProvider(foldingModel.textModel); const foldingRegionPromise = this.foldingRegionPromise = createCancelablePromise(token => provider.compute(token)); return foldingRegionPromise.then(foldingRanges => { @@ -1269,4 +1269,3 @@ CommandsRegistry.registerCommand('_executeFoldingRangeProvider', async function rangeProvider.dispose(); } }); - diff --git a/src/vs/editor/contrib/suggest/browser/suggest.ts b/src/vs/editor/contrib/suggest/browser/suggest.ts index 8e4d8326d52..9e8fbaee192 100644 --- a/src/vs/editor/contrib/suggest/browser/suggest.ts +++ b/src/vs/editor/contrib/suggest/browser/suggest.ts @@ -218,7 +218,7 @@ export async function provideSuggestionItems( token: CancellationToken = CancellationToken.None ): Promise { - const sw = new StopWatch(true); + const sw = new StopWatch(); position = position.clone(); const word = model.getWordAtPosition(position); @@ -280,7 +280,7 @@ export async function provideSuggestionItems( if (options.providerFilter.size > 0 && !options.providerFilter.has(_snippetSuggestSupport)) { return; } - const sw = new StopWatch(true); + const sw = new StopWatch(); const list = await _snippetSuggestSupport.provideCompletionItems(model, position, context, token); onCompletionList(_snippetSuggestSupport, list, sw); })(); @@ -305,7 +305,7 @@ export async function provideSuggestionItems( return; } try { - const sw = new StopWatch(true); + const sw = new StopWatch(); const list = await provider.provideCompletionItems(model, position, context, token); didAddResult = onCompletionList(provider, list, sw) || didAddResult; } catch (err) { diff --git a/src/vs/editor/contrib/suggest/browser/suggestController.ts b/src/vs/editor/contrib/suggest/browser/suggestController.ts index 68f9b0fb155..390faf46a08 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestController.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestController.ts @@ -349,7 +349,7 @@ export class SuggestController implements IEditorContribution { } else if (!isResolved) { // async additional edits - const sw = new StopWatch(true); + const sw = new StopWatch(); let position: IPosition | undefined; const docListener = model.onDidChangeContent(e => { diff --git a/src/vs/editor/contrib/tokenization/browser/tokenization.ts b/src/vs/editor/contrib/tokenization/browser/tokenization.ts index 8e673149542..800f950ad29 100644 --- a/src/vs/editor/contrib/tokenization/browser/tokenization.ts +++ b/src/vs/editor/contrib/tokenization/browser/tokenization.ts @@ -24,7 +24,7 @@ class ForceRetokenizeAction extends EditorAction { } const model = editor.getModel(); model.tokenization.resetTokenization(); - const sw = new StopWatch(true); + const sw = new StopWatch(); model.tokenization.forceTokenization(model.getLineCount()); sw.stop(); console.log(`tokenization took ${sw.elapsed()}`); diff --git a/src/vs/workbench/api/browser/mainThreadNotebook.ts b/src/vs/workbench/api/browser/mainThreadNotebook.ts index 741ea086118..0d73d9b454e 100644 --- a/src/vs/workbench/api/browser/mainThreadNotebook.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebook.ts @@ -49,7 +49,7 @@ export class MainThreadNotebooks implements MainThreadNotebookShape { disposables.add(this._notebookService.registerNotebookSerializer(viewType, extension, { options, dataToNotebook: async (data: VSBuffer): Promise => { - const sw = new StopWatch(true); + const sw = new StopWatch(); const dto = await this._proxy.$dataToNotebook(handle, data, CancellationToken.None); const result = NotebookDto.fromNotebookDataDto(dto.value); this._logService.trace(`[NotebookSerializer] dataToNotebook DONE after ${sw.elapsed()}ms`, { @@ -59,7 +59,7 @@ export class MainThreadNotebooks implements MainThreadNotebookShape { return result; }, notebookToData: (data: NotebookData): Promise => { - const sw = new StopWatch(true); + const sw = new StopWatch(); const result = this._proxy.$notebookToData(handle, new SerializableObjectWithBuffers(NotebookDto.toNotebookDataDto(data)), CancellationToken.None); this._logService.trace(`[NotebookSerializer] notebookToData DONE after ${sw.elapsed()}`, { viewType, diff --git a/src/vs/workbench/api/browser/mainThreadTerminalService.ts b/src/vs/workbench/api/browser/mainThreadTerminalService.ts index c00e070b0f7..cedec7ba50a 100644 --- a/src/vs/workbench/api/browser/mainThreadTerminalService.ts +++ b/src/vs/workbench/api/browser/mainThreadTerminalService.ts @@ -391,7 +391,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape const COUNT = 2; let sum = 0; for (let i = 0; i < COUNT; i++) { - const sw = StopWatch.create(true); + const sw = StopWatch.create(); await this._proxy.$acceptProcessRequestLatency(terminalId); sw.stop(); sum += sw.elapsed(); diff --git a/src/vs/workbench/api/common/extHostLanguageFeatures.ts b/src/vs/workbench/api/common/extHostLanguageFeatures.ts index 8333762f6a7..f578d4b61b8 100644 --- a/src/vs/workbench/api/common/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/common/extHostLanguageFeatures.ts @@ -982,7 +982,7 @@ class CompletionsAdapter { const replaceRange = doc.getWordRangeAtPosition(pos) || new Range(pos, pos); const insertRange = replaceRange.with({ end: pos }); - const sw = new StopWatch(true); + const sw = new StopWatch(); const itemsOrList = await this._provider.provideCompletionItems(doc, pos, token, typeConvert.CompletionContext.to(context)); if (!itemsOrList) { diff --git a/src/vs/workbench/contrib/snippets/browser/snippetCompletionProvider.ts b/src/vs/workbench/contrib/snippets/browser/snippetCompletionProvider.ts index 39ed50f4814..c3b6b486a9f 100644 --- a/src/vs/workbench/contrib/snippets/browser/snippetCompletionProvider.ts +++ b/src/vs/workbench/contrib/snippets/browser/snippetCompletionProvider.ts @@ -84,7 +84,7 @@ export class SnippetCompletionProvider implements CompletionItemProvider { async provideCompletionItems(model: ITextModel, position: Position, context: CompletionContext): Promise { - const sw = new StopWatch(true); + const sw = new StopWatch(); const languageId = this._getLanguageIdAtPosition(model, position); const languageConfig = this._languageConfigurationService.getLanguageConfiguration(languageId); const snippets = new Set(await this._snippets.getSnippets(languageId)); diff --git a/src/vs/workbench/services/extensions/common/extensionHostManager.ts b/src/vs/workbench/services/extensions/common/extensionHostManager.ts index d4db167e5e5..59c293fa8b1 100644 --- a/src/vs/workbench/services/extensions/common/extensionHostManager.ts +++ b/src/vs/workbench/services/extensions/common/extensionHostManager.ts @@ -228,7 +228,7 @@ class ExtensionHostManager extends Disposable implements IExtensionHostManager { let sum = 0; for (let i = 0; i < COUNT; i++) { - const sw = StopWatch.create(true); + const sw = StopWatch.create(); await proxy.test_latency(i); sw.stop(); sum += sw.elapsed(); @@ -248,7 +248,7 @@ class ExtensionHostManager extends Disposable implements IExtensionHostManager { for (let i = 0; i < buff.byteLength; i++) { buff.writeUInt8(i, value); } - const sw = StopWatch.create(true); + const sw = StopWatch.create(); await proxy.test_up(buff); sw.stop(); return ExtensionHostManager._convert(SIZE, sw.elapsed()); @@ -257,7 +257,7 @@ class ExtensionHostManager extends Disposable implements IExtensionHostManager { private async _measureDown(proxy: IExtensionHostProxy): Promise { const SIZE = 10 * 1024 * 1024; // 10MB - const sw = StopWatch.create(true); + const sw = StopWatch.create(); await proxy.test_down(SIZE); sw.stop(); return ExtensionHostManager._convert(SIZE, sw.elapsed()); diff --git a/src/vs/workbench/services/languageDetection/browser/languageDetectionSimpleWorker.ts b/src/vs/workbench/services/languageDetection/browser/languageDetectionSimpleWorker.ts index 59d8bf7ef8b..e8c8239b35f 100644 --- a/src/vs/workbench/services/languageDetection/browser/languageDetectionSimpleWorker.ts +++ b/src/vs/workbench/services/languageDetection/browser/languageDetectionSimpleWorker.ts @@ -39,7 +39,7 @@ export class LanguageDetectionSimpleWorker extends EditorSimpleWorker { public async detectLanguage(uri: string, langBiases: Record | undefined, preferHistory: boolean, supportedLangs?: string[]): Promise { const languages: string[] = []; const confidences: number[] = []; - const stopWatch = new StopWatch(true); + const stopWatch = new StopWatch(); const documentTextSample = this.getTextForDetection(uri); if (!documentTextSample) { return; } From 72e2af69c96e209dbb38ac60ecc541bf1870404b Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 16 Jun 2023 16:45:44 +0200 Subject: [PATCH 39/69] joh/high loon (#185337) * allow session creation to be cancelled * define background colors, make sure to reshow after session is ready, reset selection style on hide --- .../lib/stylelint/vscode-known-variables.json | 1 + .../contrib/inlineChat/browser/inlineChat.css | 1 + .../browser/inlineChatController.ts | 24 +++++++++++-------- .../inlineChat/browser/inlineChatSession.ts | 7 ++++-- .../inlineChat/browser/inlineChatWidget.ts | 3 ++- .../contrib/inlineChat/common/inlineChat.ts | 4 +++- 6 files changed, 26 insertions(+), 14 deletions(-) diff --git a/build/lib/stylelint/vscode-known-variables.json b/build/lib/stylelint/vscode-known-variables.json index 0372acdc768..8cbd2d9a8f4 100644 --- a/build/lib/stylelint/vscode-known-variables.json +++ b/build/lib/stylelint/vscode-known-variables.json @@ -312,6 +312,7 @@ "--vscode-inputValidation-warningBackground", "--vscode-inputValidation-warningBorder", "--vscode-inputValidation-warningForeground", + "--vscode-inlineChat-background", "--vscode-inlineChat-border", "--vscode-inlineChat-regionHighlight", "--vscode-inlineChat-shadow", diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChat.css b/src/vs/workbench/contrib/inlineChat/browser/inlineChat.css index 162db7cf436..21227772d42 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChat.css +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChat.css @@ -17,6 +17,7 @@ border-radius: 6px; border: 1px solid var(--vscode-inlineChat-border); box-shadow: 0 4px 8px var(--vscode-inlineChat-shadow); + background: var(--vscode-inlineChat-background); } /* body */ diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts index 21fa4aa01f3..6f999737c01 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts @@ -223,7 +223,7 @@ export class InlineChatController implements IEditorContribution { } } - private async [State.CREATE_SESSION](options: InlineChatRunOptions): Promise { + private async [State.CREATE_SESSION](options: InlineChatRunOptions): Promise { assertType(this._activeSession === undefined); assertType(this._editor.hasModel()); @@ -255,6 +255,10 @@ export class InlineChatController implements IEditorContribution { createSessionCts.dispose(); msgListener.dispose(); + + if (createSessionCts.token.isCancellationRequested) { + return State.PAUSE; + } } delete options.initialRange; @@ -308,6 +312,7 @@ export class InlineChatController implements IEditorContribution { this._zone.value.widget.value = this._activeSession.lastInput?.value ?? this._zone.value.widget.value; this._zone.value.widget.updateInfo(this._activeSession.session.message ?? localize('welcome.1', "AI-generated code may be incorrect")); this._zone.value.widget.preferredExpansionState = this._activeSession.lastExpansionState; + this._showWidget(false); this._sessionStore.add(this._editor.onDidChangeModel((e) => { const msg = this._activeSession?.lastExchange @@ -622,7 +627,6 @@ export class InlineChatController implements IEditorContribution { } private async [State.PAUSE]() { - assertType(this._activeSession); this._ctxDidEdit.reset(); this._ctxLastResponseType.reset(); @@ -763,17 +767,17 @@ export class InlineChatController implements IEditorContribution { } cancelSession() { - if (!this._strategy || !this._activeSession) { - return undefined; - } - - const changedText = this._activeSession.asChangedText(); - if (changedText && this._activeSession?.lastExchange?.response instanceof EditResponse) { - this._activeSession.provider.handleInlineChatResponseFeedback?.(this._activeSession.session, this._activeSession.lastExchange.response.raw, InlineChatResponseFeedbackKind.Undone); + let result: string | undefined; + if (this._strategy && this._activeSession) { + const changedText = this._activeSession.asChangedText(); + if (changedText && this._activeSession?.lastExchange?.response instanceof EditResponse) { + this._activeSession.provider.handleInlineChatResponseFeedback?.(this._activeSession.session, this._activeSession.lastExchange.response.raw, InlineChatResponseFeedbackKind.Undone); + } + result = changedText; } this._messages.fire(Message.CANCEL_SESSION); - return changedText; + return result; } unstashLastSession(): Session | undefined { diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts index 293cac5c336..d39710a45ce 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatSession.ts @@ -25,6 +25,7 @@ import { toErrorMessage } from 'vs/base/common/errorMessage'; import { isCancellationError } from 'vs/base/common/errors'; import { LineRangeMapping } from 'vs/editor/common/diff/linesDiffComputer'; import { ISingleEditOperation } from 'vs/editor/common/core/editOperation'; +import { raceCancellation } from 'vs/base/common/async'; export type Recording = { when: Date; @@ -403,7 +404,6 @@ export class InlineChatSessionService implements IInlineChatSessionService { this._sessions.clear(); } - async createSession(editor: IActiveCodeEditor, options: { editMode: EditMode; wholeRange?: Range }, token: CancellationToken): Promise { const provider = Iterable.first(this._inlineChatService.getAllProvider()); @@ -418,7 +418,10 @@ export class InlineChatSessionService implements IInlineChatSessionService { const selection = editor.getSelection(); let raw: IInlineChatSession | undefined | null; try { - raw = await provider.prepareInlineChatSession(textModel, selection, token); + raw = await raceCancellation( + Promise.resolve(provider.prepareInlineChatSession(textModel, selection, token)), + token + ); } catch (error) { this._logService.error('[IE] FAILED to prepare session', provider.debugName); this._logService.error(error); diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts index 84a44857e19..36ecb9beb0a 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts @@ -777,7 +777,7 @@ export class InlineChatZoneWidget extends ZoneWidget { return info.width - info.minimap.minimapWidth; } - public updateBackgroundColor(position: Position, selection: IRange) { + updateBackgroundColor(position: Position, selection: IRange) { if (!this.container) { return; } @@ -828,6 +828,7 @@ export class InlineChatZoneWidget extends ZoneWidget { } override hide(): void { + this.container!.classList.remove('inside-selection'); this._ctxVisible.reset(); this._ctxCursorPosition.reset(); this.widget.reset(); diff --git a/src/vs/workbench/contrib/inlineChat/common/inlineChat.ts b/src/vs/workbench/contrib/inlineChat/common/inlineChat.ts index 527416b8868..4b8d1f12789 100644 --- a/src/vs/workbench/contrib/inlineChat/common/inlineChat.ts +++ b/src/vs/workbench/contrib/inlineChat/common/inlineChat.ts @@ -16,7 +16,7 @@ import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/co import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { Registry } from 'vs/platform/registry/common/platform'; -import { diffInserted, diffRemoved, editorHoverHighlight, editorWidgetBorder, focusBorder, inputBackground, inputPlaceholderForeground, registerColor, transparent, widgetShadow } from 'vs/platform/theme/common/colorRegistry'; +import { diffInserted, diffRemoved, editorHoverHighlight, editorWidgetBackground, editorWidgetBorder, focusBorder, inputBackground, inputPlaceholderForeground, registerColor, transparent, widgetShadow } from 'vs/platform/theme/common/colorRegistry'; import { Extensions as ExtensionsMigration, IConfigurationMigrationRegistry } from 'vs/workbench/common/configuration'; export interface IInlineChatSlashCommand { @@ -134,6 +134,8 @@ export const MENU_INLINE_CHAT_WIDGET_DISCARD = MenuId.for('inlineChatWidget.undo // --- colors + +export const inlineChatBackground = registerColor('inlineChat.background', { dark: editorWidgetBackground, light: editorWidgetBackground, hcDark: editorWidgetBackground, hcLight: editorWidgetBackground }, localize('inlineChat.background', "Background color of the interactive editor widget")); export const inlineChatBorder = registerColor('inlineChat.border', { dark: editorWidgetBorder, light: editorWidgetBorder, hcDark: editorWidgetBorder, hcLight: editorWidgetBorder }, localize('inlineChat.border', "Border color of the interactive editor widget")); export const inlineChatShadow = registerColor('inlineChat.shadow', { dark: widgetShadow, light: widgetShadow, hcDark: widgetShadow, hcLight: widgetShadow }, localize('inlineChat.shadow', "Shadow color of the interactive editor widget")); export const inlineChatRegionHighlight = registerColor('inlineChat.regionHighlight', { dark: editorHoverHighlight, light: editorHoverHighlight, hcDark: editorHoverHighlight, hcLight: editorHoverHighlight }, localize('inlineChat.regionHighlight', "Background highlighting of the current interactive region. Must be transparent."), true); From 3b2671fe9b15c6ef39f537fb0a1dd11f17807058 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Fri, 16 Jun 2023 16:56:31 +0200 Subject: [PATCH 40/69] Fixes bug when innerChanges is not defined. (#185340) --- .../widget/diffEditorWidget2/diffModel.ts | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/vs/editor/browser/widget/diffEditorWidget2/diffModel.ts b/src/vs/editor/browser/widget/diffEditorWidget2/diffModel.ts index 6094cee8684..9a7a0a72073 100644 --- a/src/vs/editor/browser/widget/diffEditorWidget2/diffModel.ts +++ b/src/vs/editor/browser/widget/diffEditorWidget2/diffModel.ts @@ -55,9 +55,11 @@ export class DiffModel extends Disposable implements IDiffEditorViewModel { if (!diff) { return; } - if (!this._showMoves.get()) { - const textEdits = TextEditInfo.fromModelContentChanges(e.changes); - this._lastDiff = applyModifiedEdits(this._lastDiff!, textEdits, model.original, model.modified); + + const textEdits = TextEditInfo.fromModelContentChanges(e.changes); + const result = applyModifiedEdits(this._lastDiff!, textEdits, model.original, model.modified); + if (result) { + this._lastDiff = result; this._diff.set(DiffState.fromDiffResult(this._lastDiff), undefined); const currentSyncedMovedText = this.syncedMovedTexts.get(); this.syncedMovedTexts.set(currentSyncedMovedText ? this._lastDiff.moves.find(m => m.lineRangeMapping.modifiedRange.intersect(currentSyncedMovedText.lineRangeMapping.modifiedRange)) : undefined, undefined); @@ -70,13 +72,16 @@ export class DiffModel extends Disposable implements IDiffEditorViewModel { if (!diff) { return; } - if (!this._showMoves.get()) { - const textEdits = TextEditInfo.fromModelContentChanges(e.changes); - this._lastDiff = applyOriginalEdits(this._lastDiff!, textEdits, model.original, model.modified); + + const textEdits = TextEditInfo.fromModelContentChanges(e.changes); + const result = applyModifiedEdits(this._lastDiff!, textEdits, model.original, model.modified); + if (result) { + this._lastDiff = result; this._diff.set(DiffState.fromDiffResult(this._lastDiff), undefined); const currentSyncedMovedText = this.syncedMovedTexts.get(); this.syncedMovedTexts.set(currentSyncedMovedText ? this._lastDiff.moves.find(m => m.lineRangeMapping.modifiedRange.intersect(currentSyncedMovedText.lineRangeMapping.modifiedRange)) : undefined, undefined); } + debouncer.schedule(); })); @@ -107,8 +112,8 @@ export class DiffModel extends Disposable implements IDiffEditorViewModel { computeMoves: this._showMoves.read(reader), }); - result = applyOriginalEdits(result, originalTextEditInfos, model.original, model.modified); - result = applyModifiedEdits(result, modifiedTextEditInfos, model.original, model.modified); + result = applyOriginalEdits(result, originalTextEditInfos, model.original, model.modified) ?? result; + result = applyModifiedEdits(result, modifiedTextEditInfos, model.original, model.modified) ?? result; const newUnchangedRegions = UnchangedRegion.fromDiffs(result.changes, model.original.getLineCount(), model.modified.getLineCount()); @@ -327,13 +332,16 @@ export class UnchangedRegion { } } -function applyOriginalEdits(diff: IDocumentDiff, textEdits: TextEditInfo[], originalTextModel: ITextModel, modifiedTextModel: ITextModel): IDocumentDiff { +function applyOriginalEdits(diff: IDocumentDiff, textEdits: TextEditInfo[], originalTextModel: ITextModel, modifiedTextModel: ITextModel): IDocumentDiff | undefined { if (textEdits.length === 0) { return diff; } const diff2 = flip(diff); const diff3 = applyModifiedEdits(diff2, textEdits, modifiedTextModel, originalTextModel); + if (!diff3) { + return undefined; + } return flip(diff3); } @@ -346,10 +354,14 @@ function flip(diff: IDocumentDiff): IDocumentDiff { }; } -function applyModifiedEdits(diff: IDocumentDiff, textEdits: TextEditInfo[], originalTextModel: ITextModel, modifiedTextModel: ITextModel): IDocumentDiff { +function applyModifiedEdits(diff: IDocumentDiff, textEdits: TextEditInfo[], originalTextModel: ITextModel, modifiedTextModel: ITextModel): IDocumentDiff | undefined { if (textEdits.length === 0) { return diff; } + if (diff.changes.some(c => !c.innerChanges) || diff.moves.length > 0) { + // TODO support these cases + return undefined; + } const changes = applyModifiedEditsToLineRangeMappings(diff.changes, textEdits, originalTextModel, modifiedTextModel); From bcd19281bb76644760b4cfbb1c793a790a835072 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 16 Jun 2023 08:01:58 -0700 Subject: [PATCH 41/69] Suppress UI label-related codeql report --- .../contrib/terminal/browser/terminalProfileQuickpick.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProfileQuickpick.ts b/src/vs/workbench/contrib/terminal/browser/terminalProfileQuickpick.ts index b1635689574..5701de1746e 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProfileQuickpick.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProfileQuickpick.ts @@ -266,7 +266,7 @@ export class TerminalProfileQuickpick { } const argsString = profile.args.map(e => { if (e.includes(' ')) { - return `"${e.replace(/"/g, '\\"')}"`; + return `"${e.replace(/"/g, '\\"')}"`; // CodeQL [SM02383] js/incomplete-sanitization This is only used as a label on the UI so this isn't a problem } return e; }).join(' '); From 4a395962a67c2d714552844010205b8d90f3e365 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Fri, 16 Jun 2023 17:10:57 +0200 Subject: [PATCH 42/69] GitHub - basic handling of push errors due to GHAS push protection (#185344) --- extensions/github/src/pushErrorHandler.ts | 331 +++++++++++++--------- 1 file changed, 196 insertions(+), 135 deletions(-) diff --git a/extensions/github/src/pushErrorHandler.ts b/extensions/github/src/pushErrorHandler.ts index 6d4b4112811..fd0a6782837 100644 --- a/extensions/github/src/pushErrorHandler.ts +++ b/extensions/github/src/pushErrorHandler.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { TextDecoder } from 'util'; -import { commands, env, ProgressLocation, Uri, window, workspace, QuickPickOptions, FileType, l10n } from 'vscode'; +import { commands, env, ProgressLocation, Uri, window, workspace, QuickPickOptions, FileType, l10n, Disposable, TextDocumentContentProvider } from 'vscode'; import { getOctokit } from './auth'; import { GitErrorCodes, PushErrorHandler, Remote, Repository } from './typings/git'; import * as path from 'path'; @@ -15,136 +15,6 @@ export function isInCodespaces(): boolean { return env.remoteName === 'codespaces'; } -async function handlePushError(repository: Repository, remote: Remote, refspec: string, owner: string, repo: string): Promise { - const yes = l10n.t('Create Fork'); - const no = l10n.t('No'); - const askFork = l10n.t('You don\'t have permissions to push to "{0}/{1}" on GitHub. Would you like to create a fork and push to it instead?', owner, repo); - - const answer = await window.showWarningMessage(askFork, { modal: true }, yes, no); - if (answer !== yes) { - return; - } - - const match = /^([^:]*):([^:]*)$/.exec(refspec); - const localName = match ? match[1] : refspec; - let remoteName = match ? match[2] : refspec; - - const [octokit, ghRepository] = await window.withProgress({ location: ProgressLocation.Notification, cancellable: false, title: l10n.t('Create GitHub fork') }, async progress => { - progress.report({ message: l10n.t('Forking "{0}/{1}"...', owner, repo), increment: 33 }); - - const octokit = await getOctokit(); - - type CreateForkResponseData = Awaited>['data']; - - // Issue: what if the repo already exists? - let ghRepository: CreateForkResponseData; - try { - if (isInCodespaces()) { - // Call into the codespaces extension to fork the repository - const resp = await commands.executeCommand<{ repository: CreateForkResponseData; ref: string }>('github.codespaces.forkRepository'); - if (!resp) { - throw new Error('Unable to fork respository'); - } - - ghRepository = resp.repository; - - if (resp.ref) { - let ref = resp.ref; - if (ref.startsWith('refs/heads/')) { - ref = ref.substr(11); - } - - remoteName = ref; - } - } else { - const resp = await octokit.repos.createFork({ owner, repo }); - ghRepository = resp.data; - } - } catch (ex) { - console.error(ex); - throw ex; - } - - progress.report({ message: l10n.t('Pushing changes...'), increment: 33 }); - - // Issue: what if there's already an `upstream` repo? - await repository.renameRemote(remote.name, 'upstream'); - - // Issue: what if there's already another `origin` repo? - const protocol = workspace.getConfiguration('github').get<'https' | 'ssh'>('gitProtocol'); - const remoteUrl = protocol === 'https' ? ghRepository.clone_url : ghRepository.ssh_url; - await repository.addRemote('origin', remoteUrl); - - try { - await repository.fetch('origin', remoteName); - await repository.setBranchUpstream(localName, `origin/${remoteName}`); - } catch { - // noop - } - - await repository.push('origin', localName, true); - - return [octokit, ghRepository] as const; - }); - - // yield - (async () => { - const openOnGitHub = l10n.t('Open on GitHub'); - const createPR = l10n.t('Create PR'); - const action = await window.showInformationMessage(l10n.t('The fork "{0}" was successfully created on GitHub.', ghRepository.full_name), openOnGitHub, createPR); - - if (action === openOnGitHub) { - await commands.executeCommand('vscode.open', Uri.parse(ghRepository.html_url)); - } else if (action === createPR) { - const pr = await window.withProgress({ location: ProgressLocation.Notification, cancellable: false, title: l10n.t('Creating GitHub Pull Request...') }, async _ => { - let title = `Update ${remoteName}`; - const head = repository.state.HEAD?.name; - - let body: string | undefined; - - if (head) { - const commit = await repository.getCommit(head); - title = commit.message.split('\n')[0]; - body = commit.message.slice(title.length + 1).trim(); - } - - const templates = await findPullRequestTemplates(repository.rootUri); - if (templates.length > 0) { - templates.sort((a, b) => a.path.localeCompare(b.path)); - - const template = await pickPullRequestTemplate(repository.rootUri, templates); - - if (template) { - body = new TextDecoder('utf-8').decode(await workspace.fs.readFile(template)); - } - } - - const { data: pr } = await octokit.pulls.create({ - owner, - repo, - title, - body, - head: `${ghRepository.owner.login}:${remoteName}`, - base: ghRepository.default_branch - }); - - await repository.setConfig(`branch.${localName}.remote`, 'upstream'); - await repository.setConfig(`branch.${localName}.merge`, `refs/heads/${remoteName}`); - await repository.setConfig(`branch.${localName}.github-pr-owner-number`, `${owner}#${repo}#${pr.number}`); - - return pr; - }); - - const openPR = l10n.t('Open PR'); - const action = await window.showInformationMessage(l10n.t('The PR "{0}/{1}#{2}" was successfully created on GitHub.', owner, repo, pr.number), openPR); - - if (action === openPR) { - await commands.executeCommand('vscode.open', Uri.parse(pr.html_url)); - } - } - })(); -} - const PR_TEMPLATE_FILES = [ { dir: '.', files: ['pull_request_template.md', 'PULL_REQUEST_TEMPLATE.md'] }, { dir: 'docs', files: ['pull_request_template.md', 'PULL_REQUEST_TEMPLATE.md'] }, @@ -207,10 +77,34 @@ export async function pickPullRequestTemplate(repositoryRootUri: Uri, templates: return pickedTemplate?.template; } +class CommandErrorOutputTextDocumentContentProvider implements TextDocumentContentProvider { + + private items = new Map(); + + set(uri: Uri, contents: string): void { + this.items.set(uri.path, contents); + } + + delete(uri: Uri): void { + this.items.delete(uri.path); + } + + provideTextDocumentContent(uri: Uri): string | undefined { + return this.items.get(uri.path); + } +} + export class GithubPushErrorHandler implements PushErrorHandler { - async handlePushError(repository: Repository, remote: Remote, refspec: string, error: Error & { gitErrorCode: GitErrorCodes }): Promise { - if (error.gitErrorCode !== GitErrorCodes.PermissionDenied) { + private disposables: Disposable[] = []; + private commandErrors = new CommandErrorOutputTextDocumentContentProvider(); + + constructor() { + this.disposables.push(workspace.registerTextDocumentContentProvider('github-output', this.commandErrors)); + } + + async handlePushError(repository: Repository, remote: Remote, refspec: string, error: Error & { stderr: string; gitErrorCode: GitErrorCodes }): Promise { + if (error.gitErrorCode !== GitErrorCodes.PermissionDenied && error.gitErrorCode !== GitErrorCodes.PushRejected) { return false; } @@ -229,8 +123,175 @@ export class GithubPushErrorHandler implements PushErrorHandler { } const [, owner, repo] = match; - await handlePushError(repository, remote, refspec, owner, repo); - return true; + if (error.gitErrorCode === GitErrorCodes.PermissionDenied) { + await this.handlePermissionDeniedError(repository, remote, refspec, owner, repo); + return true; + } + + // Push protection + if (/GH009: Secrets detected!/i.test(error.stderr)) { + await this.handlePushProtectionError(owner, repo, error.stderr); + return true; + } + + return false; + } + + private async handlePermissionDeniedError(repository: Repository, remote: Remote, refspec: string, owner: string, repo: string): Promise { + const yes = l10n.t('Create Fork'); + const no = l10n.t('No'); + const askFork = l10n.t('You don\'t have permissions to push to "{0}/{1}" on GitHub. Would you like to create a fork and push to it instead?', owner, repo); + + const answer = await window.showWarningMessage(askFork, { modal: true }, yes, no); + if (answer !== yes) { + return; + } + + const match = /^([^:]*):([^:]*)$/.exec(refspec); + const localName = match ? match[1] : refspec; + let remoteName = match ? match[2] : refspec; + + const [octokit, ghRepository] = await window.withProgress({ location: ProgressLocation.Notification, cancellable: false, title: l10n.t('Create GitHub fork') }, async progress => { + progress.report({ message: l10n.t('Forking "{0}/{1}"...', owner, repo), increment: 33 }); + + const octokit = await getOctokit(); + + type CreateForkResponseData = Awaited>['data']; + + // Issue: what if the repo already exists? + let ghRepository: CreateForkResponseData; + try { + if (isInCodespaces()) { + // Call into the codespaces extension to fork the repository + const resp = await commands.executeCommand<{ repository: CreateForkResponseData; ref: string }>('github.codespaces.forkRepository'); + if (!resp) { + throw new Error('Unable to fork respository'); + } + + ghRepository = resp.repository; + + if (resp.ref) { + let ref = resp.ref; + if (ref.startsWith('refs/heads/')) { + ref = ref.substr(11); + } + + remoteName = ref; + } + } else { + const resp = await octokit.repos.createFork({ owner, repo }); + ghRepository = resp.data; + } + } catch (ex) { + console.error(ex); + throw ex; + } + + progress.report({ message: l10n.t('Pushing changes...'), increment: 33 }); + + // Issue: what if there's already an `upstream` repo? + await repository.renameRemote(remote.name, 'upstream'); + + // Issue: what if there's already another `origin` repo? + const protocol = workspace.getConfiguration('github').get<'https' | 'ssh'>('gitProtocol'); + const remoteUrl = protocol === 'https' ? ghRepository.clone_url : ghRepository.ssh_url; + await repository.addRemote('origin', remoteUrl); + + try { + await repository.fetch('origin', remoteName); + await repository.setBranchUpstream(localName, `origin/${remoteName}`); + } catch { + // noop + } + + await repository.push('origin', localName, true); + + return [octokit, ghRepository] as const; + }); + + // yield + (async () => { + const openOnGitHub = l10n.t('Open on GitHub'); + const createPR = l10n.t('Create PR'); + const action = await window.showInformationMessage(l10n.t('The fork "{0}" was successfully created on GitHub.', ghRepository.full_name), openOnGitHub, createPR); + + if (action === openOnGitHub) { + await commands.executeCommand('vscode.open', Uri.parse(ghRepository.html_url)); + } else if (action === createPR) { + const pr = await window.withProgress({ location: ProgressLocation.Notification, cancellable: false, title: l10n.t('Creating GitHub Pull Request...') }, async _ => { + let title = `Update ${remoteName}`; + const head = repository.state.HEAD?.name; + + let body: string | undefined; + + if (head) { + const commit = await repository.getCommit(head); + title = commit.message.split('\n')[0]; + body = commit.message.slice(title.length + 1).trim(); + } + + const templates = await findPullRequestTemplates(repository.rootUri); + if (templates.length > 0) { + templates.sort((a, b) => a.path.localeCompare(b.path)); + + const template = await pickPullRequestTemplate(repository.rootUri, templates); + + if (template) { + body = new TextDecoder('utf-8').decode(await workspace.fs.readFile(template)); + } + } + + const { data: pr } = await octokit.pulls.create({ + owner, + repo, + title, + body, + head: `${ghRepository.owner.login}:${remoteName}`, + base: ghRepository.default_branch + }); + + await repository.setConfig(`branch.${localName}.remote`, 'upstream'); + await repository.setConfig(`branch.${localName}.merge`, `refs/heads/${remoteName}`); + await repository.setConfig(`branch.${localName}.github-pr-owner-number`, `${owner}#${repo}#${pr.number}`); + + return pr; + }); + + const openPR = l10n.t('Open PR'); + const action = await window.showInformationMessage(l10n.t('The PR "{0}/{1}#{2}" was successfully created on GitHub.', owner, repo, pr.number), openPR); + + if (action === openPR) { + await commands.executeCommand('vscode.open', Uri.parse(pr.html_url)); + } + } + })(); + } + + private async handlePushProtectionError(owner: string, repo: string, stderr: string): Promise { + // Open command output in an editor + const timestamp = new Date().getTime(); + const uri = Uri.parse(`github-output:/github-error-${timestamp}`); + this.commandErrors.set(uri, stderr); + + try { + const doc = await workspace.openTextDocument(uri); + await window.showTextDocument(doc); + } + finally { + this.commandErrors.set(uri, stderr); + } + + // Show dialog + const learnMore = l10n.t('Learn More'); + const message = l10n.t('Your push to "{0}/{1}" was rejected by GitHub because push protection is enabled and one or more secrets were detected.', owner, repo); + const answer = await window.showWarningMessage(message, { modal: true }, learnMore); + if (answer === learnMore) { + commands.executeCommand('vscode.open', 'https://aka.ms/vscode-github-push-protection'); + } + } + + dispose() { + this.disposables.forEach(d => d.dispose()); } } From aedd8038a22af622d3502775cc7d2638d491681d Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 16 Jun 2023 17:28:23 +0200 Subject: [PATCH 43/69] suppress warnings from codeql (#185348) https://github.com/microsoft/vscode-internalbacklog/issues/4378#issuecomment-1594839449 --- .../editor/contrib/smartSelect/test/browser/smartSelect.test.ts | 2 +- src/vs/workbench/api/worker/extHostExtensionService.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/contrib/smartSelect/test/browser/smartSelect.test.ts b/src/vs/editor/contrib/smartSelect/test/browser/smartSelect.test.ts index c3c33eca509..b06590e3255 100644 --- a/src/vs/editor/contrib/smartSelect/test/browser/smartSelect.test.ts +++ b/src/vs/editor/contrib/smartSelect/test/browser/smartSelect.test.ts @@ -211,7 +211,7 @@ suite('SmartSelect', () => { async function assertRanges(provider: SelectionRangeProvider, value: string, ...expected: IRange[]): Promise { const index = value.indexOf('|'); - value = value.replace('|', ''); + value = value.replace('|', ''); // CodeQL [SM02383] js/incomplete-sanitization this is purpose only the first | character const model = modelService.createModel(value, new StaticLanguageSelector(languageId), URI.parse('fake:lang')); const pos = model.getPositionAt(index); diff --git a/src/vs/workbench/api/worker/extHostExtensionService.ts b/src/vs/workbench/api/worker/extHostExtensionService.ts index 65417c948d3..b83a462131d 100644 --- a/src/vs/workbench/api/worker/extHostExtensionService.ts +++ b/src/vs/workbench/api/worker/extHostExtensionService.ts @@ -83,7 +83,7 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { const fullSource = `${source}\n//# sourceURL=${sourceURL}`; let initFn: Function; try { - initFn = new Function('module', 'exports', 'require', fullSource); + initFn = new Function('module', 'exports', 'require', fullSource); // CodeQL [SM01632] js/eval-call there is no alternative until we move to ESM } catch (err) { if (extensionId) { console.error(`Loading code for extension ${extensionId} failed: ${err.message}`); From 5fbb86ad46ca0be34e0a2f9f07d770e5a627947b Mon Sep 17 00:00:00 2001 From: Johannes Date: Fri, 16 Jun 2023 17:41:59 +0200 Subject: [PATCH 44/69] stop before using other ranges --- src/vs/editor/contrib/wordHighlighter/browser/wordHighlighter.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/editor/contrib/wordHighlighter/browser/wordHighlighter.ts b/src/vs/editor/contrib/wordHighlighter/browser/wordHighlighter.ts index 324ddc6f09d..a11868bc8cb 100644 --- a/src/vs/editor/contrib/wordHighlighter/browser/wordHighlighter.ts +++ b/src/vs/editor/contrib/wordHighlighter/browser/wordHighlighter.ts @@ -461,6 +461,7 @@ class WordHighlighter { // update decorators of friends for (const other of this.linkedHighlighters()) { if (other?.editor.getModel() === this.editor.getModel()) { + other._stopAll(); other.decorations.set(decorations); other._hasWordHighlights.set(other.hasDecorations()); } From 6287e1f583f38d341b882e7fca47a8a0f3d9e373 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 16 Jun 2023 09:51:41 -0700 Subject: [PATCH 45/69] Replace escape sequence logging with terminal log channel Fixes #185349 --- package.json | 14 ++--- remote/package.json | 12 ++-- remote/web/package.json | 8 +-- remote/web/yarn.lock | 32 +++++------ remote/yarn.lock | 48 ++++++++-------- .../contrib/terminal/browser/terminal.ts | 8 --- .../terminal/browser/terminalActions.ts | 7 --- .../terminal/browser/terminalInstance.ts | 6 -- .../terminal/browser/terminalService.ts | 19 ------- .../terminal/browser/xterm/xtermTerminal.ts | 57 ++++++++++++------- .../contrib/terminal/common/terminal.ts | 1 - .../terminalNativeContribution.ts | 4 +- yarn.lock | 48 ++++++++-------- 13 files changed, 119 insertions(+), 145 deletions(-) diff --git a/package.json b/package.json index 9de4de7a356..ade6173707b 100644 --- a/package.json +++ b/package.json @@ -92,14 +92,14 @@ "vscode-oniguruma": "1.7.0", "vscode-regexpp": "^3.1.0", "vscode-textmate": "9.0.0", - "xterm": "5.3.0-beta.1", - "xterm-addon-canvas": "0.5.0-beta.1", + "xterm": "5.3.0-beta.3", + "xterm-addon-canvas": "0.5.0-beta.2", "xterm-addon-image": "0.4.1", - "xterm-addon-search": "0.13.0-beta.1", - "xterm-addon-serialize": "0.11.0-beta.1", + "xterm-addon-search": "0.13.0-beta.2", + "xterm-addon-serialize": "0.11.0-beta.2", "xterm-addon-unicode11": "0.5.0", - "xterm-addon-webgl": "0.16.0-beta.1", - "xterm-headless": "5.3.0-beta.1", + "xterm-addon-webgl": "0.16.0-beta.2", + "xterm-headless": "5.3.0-beta.3", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, @@ -230,4 +230,4 @@ "optionalDependencies": { "windows-foreground-love": "0.5.0" } -} \ No newline at end of file +} diff --git a/remote/package.json b/remote/package.json index 72ea3dca606..b6f21703ca4 100644 --- a/remote/package.json +++ b/remote/package.json @@ -26,14 +26,14 @@ "vscode-oniguruma": "1.7.0", "vscode-regexpp": "^3.1.0", "vscode-textmate": "9.0.0", - "xterm": "5.3.0-beta.1", - "xterm-addon-canvas": "0.5.0-beta.1", + "xterm": "5.3.0-beta.3", + "xterm-addon-canvas": "0.5.0-beta.2", "xterm-addon-image": "0.4.1", - "xterm-addon-search": "0.13.0-beta.1", - "xterm-addon-serialize": "0.11.0-beta.1", + "xterm-addon-search": "0.13.0-beta.2", + "xterm-addon-serialize": "0.11.0-beta.2", "xterm-addon-unicode11": "0.5.0", - "xterm-addon-webgl": "0.16.0-beta.1", - "xterm-headless": "5.3.0-beta.1", + "xterm-addon-webgl": "0.16.0-beta.2", + "xterm-headless": "5.3.0-beta.3", "yauzl": "^2.9.2", "yazl": "^2.4.3" } diff --git a/remote/web/package.json b/remote/web/package.json index fb573e7a0e9..db7baab82d3 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -11,11 +11,11 @@ "tas-client-umd": "0.1.8", "vscode-oniguruma": "1.7.0", "vscode-textmate": "9.0.0", - "xterm": "5.3.0-beta.1", - "xterm-addon-canvas": "0.5.0-beta.1", + "xterm": "5.3.0-beta.3", + "xterm-addon-canvas": "0.5.0-beta.2", "xterm-addon-image": "0.4.1", - "xterm-addon-search": "0.13.0-beta.1", + "xterm-addon-search": "0.13.0-beta.2", "xterm-addon-unicode11": "0.5.0", - "xterm-addon-webgl": "0.16.0-beta.1" + "xterm-addon-webgl": "0.16.0-beta.2" } } diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index 325be24ac89..2f879c22bf6 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -68,32 +68,32 @@ vscode-textmate@9.0.0: resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-9.0.0.tgz#313c6c8792b0507aef35aeb81b6b370b37c44d6c" integrity sha512-Cl65diFGxz7gpwbav10HqiY/eVYTO1sjQpmRmV991Bj7wAoOAjGQ97PpQcXorDE2Uc4hnGWLY17xme+5t6MlSg== -xterm-addon-canvas@0.5.0-beta.1: - version "0.5.0-beta.1" - resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.5.0-beta.1.tgz#b5ae185741423715460a66029c944b4dededfab0" - integrity sha512-A7yjIpyTcOh8ckPJw1YFDvwbTbQ+grM+kTtutOvu5LjLSV9EoCHX17kVoiT2V29ywF7KJMeLYwfBwyFE3uA3QQ== +xterm-addon-canvas@0.5.0-beta.2: + version "0.5.0-beta.2" + resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.5.0-beta.2.tgz#1b83c2a9a306766c47a4f80b8c65cc9ee5f5a5c4" + integrity sha512-oTb/2krdbHYGxH2X6yiBZzAB/1WB+apUu4nXHdhBnht20bl8E+YVWqg95D4o0Gl+QJI+XOfB3mqmWaBx1x531A== xterm-addon-image@0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/xterm-addon-image/-/xterm-addon-image-0.4.1.tgz#ec8f750af48005ad641c1128fa1f551ac198472a" integrity sha512-iJpYyvtbHg4oXSv+D6J73ZfCjnboZpbZ567MLplXDBlYSUknv3kvPTfVMPJATV7Zsx7+bDgyXboCh9vsDf/m/w== -xterm-addon-search@0.13.0-beta.1: - version "0.13.0-beta.1" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.13.0-beta.1.tgz#9fb6ede402d4c369d59d5d6faefe54a05b125bcf" - integrity sha512-rdOIhwkfRASqTriUO8QP9UY0p6BosLMv1NXTZqhgq3/5xAXx4VZg6mlQjTRGnUz/GJIN1jU9e/Vp20SpocP/Hw== +xterm-addon-search@0.13.0-beta.2: + version "0.13.0-beta.2" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.13.0-beta.2.tgz#c984a35312acad4ce768d17bc49adffa90eece61" + integrity sha512-+VoPhIRmfiX2uh2t6xD/RJtBYjVjrkNa3dKQnOYEp4UbYzDjK57rZX652mnZ82TQfk/juxf7v+jV5aRdNLZVbA== xterm-addon-unicode11@0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.5.0.tgz#41c0d96acc1e3bb6c6596eee64e163b6bca74be7" integrity sha512-Jm4/g4QiTxiKiTbYICQgC791ubhIZyoIwxAIgOW8z8HWFNY+lwk+dwaKEaEeGBfM48Vk8fklsUW9u/PlenYEBg== -xterm-addon-webgl@0.16.0-beta.1: - version "0.16.0-beta.1" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.16.0-beta.1.tgz#e2b41c6b5f838724a5cb3cfa4231e2d1b8f3f130" - integrity sha512-iJK+Uk+23Mh84BNa/44JqAdPESdNKN0ONfw6UztmDk2HTvsy47sU+d/lgF2kOcuI3ew2tRzK9YlupOUhVPwe9g== +xterm-addon-webgl@0.16.0-beta.2: + version "0.16.0-beta.2" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.16.0-beta.2.tgz#30489ef235405255ee54077002c90553531870d8" + integrity sha512-DAt4E/QI1w34ToBhcDj0vaZOAHOO+ffwMt2HGDAB7amPXRcMb0LBIjLpyZhB9sD4tbIgsE0vuqZi1R9vKxZwbg== -xterm@5.3.0-beta.1: - version "5.3.0-beta.1" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.3.0-beta.1.tgz#68e76f2818965592c60bb269360f1fc37219f4ae" - integrity sha512-2v/Qmk1A0wO5oouRWUWZ3wxqtfFjxsQbZ1sWxPGJTQvoTSdkORLG44gxrU+Sk2jB5Ojz+3Kg42bnfFghsXVzlw== +xterm@5.3.0-beta.3: + version "5.3.0-beta.3" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.3.0-beta.3.tgz#1a1aaf9a57afe4dcf86e87d8dc85e80a41d68644" + integrity sha512-NGxpV25U2W/KKk6M5V2OXuLgrKY+w05ABi66ZEYuCTi7ux1Qv0z+jm7bkgzk1pGGiTVLG+90OGr2nrhbFr5Y4w== diff --git a/remote/yarn.lock b/remote/yarn.lock index b3f8935f2cb..8836ac2d179 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -836,45 +836,45 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -xterm-addon-canvas@0.5.0-beta.1: - version "0.5.0-beta.1" - resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.5.0-beta.1.tgz#b5ae185741423715460a66029c944b4dededfab0" - integrity sha512-A7yjIpyTcOh8ckPJw1YFDvwbTbQ+grM+kTtutOvu5LjLSV9EoCHX17kVoiT2V29ywF7KJMeLYwfBwyFE3uA3QQ== +xterm-addon-canvas@0.5.0-beta.2: + version "0.5.0-beta.2" + resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.5.0-beta.2.tgz#1b83c2a9a306766c47a4f80b8c65cc9ee5f5a5c4" + integrity sha512-oTb/2krdbHYGxH2X6yiBZzAB/1WB+apUu4nXHdhBnht20bl8E+YVWqg95D4o0Gl+QJI+XOfB3mqmWaBx1x531A== xterm-addon-image@0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/xterm-addon-image/-/xterm-addon-image-0.4.1.tgz#ec8f750af48005ad641c1128fa1f551ac198472a" integrity sha512-iJpYyvtbHg4oXSv+D6J73ZfCjnboZpbZ567MLplXDBlYSUknv3kvPTfVMPJATV7Zsx7+bDgyXboCh9vsDf/m/w== -xterm-addon-search@0.13.0-beta.1: - version "0.13.0-beta.1" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.13.0-beta.1.tgz#9fb6ede402d4c369d59d5d6faefe54a05b125bcf" - integrity sha512-rdOIhwkfRASqTriUO8QP9UY0p6BosLMv1NXTZqhgq3/5xAXx4VZg6mlQjTRGnUz/GJIN1jU9e/Vp20SpocP/Hw== +xterm-addon-search@0.13.0-beta.2: + version "0.13.0-beta.2" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.13.0-beta.2.tgz#c984a35312acad4ce768d17bc49adffa90eece61" + integrity sha512-+VoPhIRmfiX2uh2t6xD/RJtBYjVjrkNa3dKQnOYEp4UbYzDjK57rZX652mnZ82TQfk/juxf7v+jV5aRdNLZVbA== -xterm-addon-serialize@0.11.0-beta.1: - version "0.11.0-beta.1" - resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.11.0-beta.1.tgz#a4bc1ef5d8b8db0180c07f071ce543536d806db1" - integrity sha512-2I9Dq49nXUc6ymznwJp8SUsDq5owUdYviUy11HzLh35baDjzbG31CCu5Gs8KSlfUxpNRr3BxaV5/hx7MRPu7Qg== +xterm-addon-serialize@0.11.0-beta.2: + version "0.11.0-beta.2" + resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.11.0-beta.2.tgz#fff924decfbf1bc08434317894f985fef7bb260b" + integrity sha512-tN4IT2e+EIpsoFpMONUh1OAuoVAcV7AYOLsqMKgH6GNWB1D/LKGo3cwjpw1vwRZzDJJcCcLxYgxlUzhPbDbLxQ== xterm-addon-unicode11@0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.5.0.tgz#41c0d96acc1e3bb6c6596eee64e163b6bca74be7" integrity sha512-Jm4/g4QiTxiKiTbYICQgC791ubhIZyoIwxAIgOW8z8HWFNY+lwk+dwaKEaEeGBfM48Vk8fklsUW9u/PlenYEBg== -xterm-addon-webgl@0.16.0-beta.1: - version "0.16.0-beta.1" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.16.0-beta.1.tgz#e2b41c6b5f838724a5cb3cfa4231e2d1b8f3f130" - integrity sha512-iJK+Uk+23Mh84BNa/44JqAdPESdNKN0ONfw6UztmDk2HTvsy47sU+d/lgF2kOcuI3ew2tRzK9YlupOUhVPwe9g== +xterm-addon-webgl@0.16.0-beta.2: + version "0.16.0-beta.2" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.16.0-beta.2.tgz#30489ef235405255ee54077002c90553531870d8" + integrity sha512-DAt4E/QI1w34ToBhcDj0vaZOAHOO+ffwMt2HGDAB7amPXRcMb0LBIjLpyZhB9sD4tbIgsE0vuqZi1R9vKxZwbg== -xterm-headless@5.3.0-beta.1: - version "5.3.0-beta.1" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.3.0-beta.1.tgz#8c7db703b9f57496c2f052411721c00909b08e8b" - integrity sha512-6rsv6l44hLL9Eg2UrfAbCiZcAucdHuPyIsovl2BEmluo4chwd4LD7VINRlPV/x8ML2HgD9SohFyNs5BQAc07Gg== +xterm-headless@5.3.0-beta.3: + version "5.3.0-beta.3" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.3.0-beta.3.tgz#153cf330082f4b2aae64ff736ef0b62d93c30da8" + integrity sha512-4i/bpFoAn4D4ZA4g8RKrJdhq2EcB1HN2E25yUg3omRbWCOZ2Gp9nAn+62LYzX5rvGqdNbpUTRJLX0lKwEFyLFw== -xterm@5.3.0-beta.1: - version "5.3.0-beta.1" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.3.0-beta.1.tgz#68e76f2818965592c60bb269360f1fc37219f4ae" - integrity sha512-2v/Qmk1A0wO5oouRWUWZ3wxqtfFjxsQbZ1sWxPGJTQvoTSdkORLG44gxrU+Sk2jB5Ojz+3Kg42bnfFghsXVzlw== +xterm@5.3.0-beta.3: + version "5.3.0-beta.3" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.3.0-beta.3.tgz#1a1aaf9a57afe4dcf86e87d8dc85e80a41d68644" + integrity sha512-NGxpV25U2W/KKk6M5V2OXuLgrKY+w05ABi66ZEYuCTi7ux1Qv0z+jm7bkgzk1pGGiTVLG+90OGr2nrhbFr5Y4w== yallist@^4.0.0: version "4.0.0" diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 21216688f4d..284c7238948 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -230,7 +230,6 @@ export interface ITerminalService extends ITerminalInstanceHost { resolveLocation(location?: ITerminalLocationOptions): TerminalLocation | undefined; setNativeDelegate(nativeCalls: ITerminalServiceNativeDelegate): void; - toggleEscapeSequenceLogging(): Promise; getEditingTerminal(): ITerminalInstance | undefined; setEditingTerminal(instance: ITerminalInstance | undefined): void; @@ -240,8 +239,6 @@ export class TerminalLinkQuickPickEvent extends MouseEvent { } export interface ITerminalServiceNativeDelegate { getWindowCount(): Promise; - openDevTools(): Promise; - toggleDevTools(): Promise; } /** @@ -857,11 +854,6 @@ export interface ITerminalInstance { */ toggleSizeToContentWidth(): Promise; - /** - * Toggles escape sequence logging in the devtools console. - */ - toggleEscapeSequenceLogging(): Promise; - /** * Sets whether escape seqeunce logging is enabled in the devtools console. */ diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 6b27e824491..567382feaf6 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -928,13 +928,6 @@ export function registerTerminalActions() { } }); - registerTerminalAction({ - id: TerminalCommandId.ToggleEscapeSequenceLogging, - title: { value: localize('workbench.action.terminal.toggleEscapeSequenceLogging', "Toggle Escape Sequence Logging"), original: 'Toggle Escape Sequence Logging' }, - precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated), - run: (c) => c.service.toggleEscapeSequenceLogging() - }); - registerTerminalAction({ id: TerminalCommandId.SendSequence, title: terminalStrings.sendSequence, diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 7a48be17e03..6a6e7f7cfe6 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -2110,12 +2110,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this.statusList.add(info.getStatus({ workspaceFolder })); } - async toggleEscapeSequenceLogging(): Promise { - const xterm = await this._xtermReadyPromise; - xterm.raw.options.logLevel = xterm.raw.options.logLevel === 'debug' ? 'info' : 'debug'; - return xterm.raw.options.logLevel === 'debug'; - } - async getInitialCwd(): Promise { if (!this._initialCwd) { this._initialCwd = this._processManager.initialCwd; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 08dd70e1fad..ab1a2474dbf 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -477,17 +477,6 @@ export class TerminalService implements ITerminalService { return reconnectCounter; } - async toggleEscapeSequenceLogging(): Promise { - if (this.instances.length === 0) { - return; - } - this._escapeSequenceLoggingEnabled = await this.instances[0].toggleEscapeSequenceLogging(); - for (let i = 1; i < this.instances.length; i++) { - this.instances[i].setEscapeSequenceLogging(this._escapeSequenceLoggingEnabled); - } - await this._toggleDevTools(this._escapeSequenceLoggingEnabled); - } - private _attachProcessLayoutListeners(): void { this.onDidChangeActiveGroup(() => this._saveState()); this.onDidChangeActiveInstance(() => this._saveState()); @@ -621,14 +610,6 @@ export class TerminalService implements ITerminalService { this._nativeDelegate = nativeDelegate; } - private async _toggleDevTools(open?: boolean): Promise { - if (open) { - this._nativeDelegate?.openDevTools(); - } else { - this._nativeDelegate?.toggleDevTools(); - } - } - private _shouldReviveProcesses(reason: ShutdownReason): boolean { if (!this._configHelper.config.enablePersistentSessions) { return false; diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts index a188ac5ea5a..cfb38995a78 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import type { IBuffer, ITheme, Terminal as RawXtermTerminal } from 'xterm'; +import type { IBuffer, ITheme, Terminal as RawXtermTerminal, LogLevel as XtermLogLevel } from 'xterm'; import type { CanvasAddon as CanvasAddonType } from 'xterm-addon-canvas'; import type { ISearchOptions, SearchAddon as SearchAddonType } from 'xterm-addon-search'; import type { Unicode11Addon as Unicode11AddonType } from 'xterm-addon-unicode11'; @@ -20,7 +20,7 @@ import { IShellIntegration, TerminalSettingId } from 'vs/platform/terminal/commo import { ITerminalFont } from 'vs/workbench/contrib/terminal/common/terminal'; import { isSafari } from 'vs/base/browser/browser'; import { IMarkTracker, IInternalXtermTerminal, IXtermTerminal, ISuggestController, IXtermColorProvider, XtermTerminalConstants, IXtermAttachToElementOptions, IDetachedXtermTerminal } from 'vs/workbench/contrib/terminal/browser/terminal'; -import { ILogService } from 'vs/platform/log/common/log'; +import { ILogger, ILoggerService, LogLevel } from 'vs/platform/log/common/log'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { TerminalStorageKeys } from 'vs/workbench/contrib/terminal/common/terminalStorageKeys'; import { INotificationService, IPromptChoice, Severity } from 'vs/platform/notification/common/notification'; @@ -114,16 +114,6 @@ function getFullBufferLineAsString(lineIndex: number, buffer: IBuffer): { lineDa export class XtermTerminal extends DisposableStore implements IXtermTerminal, IDetachedXtermTerminal, IInternalXtermTerminal { /** The raw xterm.js instance */ readonly raw: RawXtermTerminal; - - *getBufferReverseIterator(): IterableIterator { - for (let i = this.raw.buffer.active.length; i >= 0; i--) { - const { lineData, lineIndex } = getFullBufferLineAsString(i, this.raw.buffer.active); - if (lineData) { - i = lineIndex; - yield lineData; - } - } - } private _core: IXtermCore; private static _suggestedRendererType: 'canvas' | 'dom' | undefined = undefined; private _attached?: { container: HTMLElement; options: IXtermAttachToElementOptions }; @@ -131,23 +121,25 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, ID // Always on addons private _markNavigationAddon: MarkNavigationAddon; private _shellIntegrationAddon: ShellIntegrationAddon; - private _decorationAddon: DecorationAddon; - private _suggestAddon?: SuggestAddon; // Optional addons + private _suggestAddon?: SuggestAddon; private _canvasAddon?: CanvasAddonType; private _searchAddon?: SearchAddonType; private _unicode11Addon?: Unicode11AddonType; private _webglAddon?: WebglAddonType; private _serializeAddon?: SerializeAddonType; private _imageAddon?: ImageAddonType; + + private readonly _logger: ILogger; private readonly _attachedDisposables = this.add(new DisposableStore()); private readonly _anyTerminalFocusContextKey: IContextKey; private readonly _anyFocusedTerminalHasSelection: IContextKey; private _lastFindResult: { resultIndex: number; resultCount: number } | undefined; get findResult(): { resultIndex: number; resultCount: number } | undefined { return this._lastFindResult; } + get isStdinDisabled(): boolean { return !!this.raw.options.disableStdin; } private readonly _onDidRequestRunCommand = new Emitter<{ command: ITerminalCommand; copyAsHtml?: boolean; noNewLine?: boolean }>(); @@ -199,7 +191,7 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, ID disableShellIntegrationReporting: boolean, @IConfigurationService private readonly _configurationService: IConfigurationService, @IInstantiationService private readonly _instantiationService: IInstantiationService, - @ILogService private readonly _logService: ILogService, + @ILoggerService private readonly _loggerService: ILoggerService, @INotificationService private readonly _notificationService: INotificationService, @IStorageService private readonly _storageService: IStorageService, @IThemeService private readonly _themeService: IThemeService, @@ -212,6 +204,7 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, ID const config = this._configHelper.config; const editorOptions = this._configurationService.getValue('editor'); + this._logger = this._loggerService.createLogger('terminal', { name: localize('terminalLoggerName', 'Terminal') }); this.raw = this.add(new xtermCtor({ allowProposedApi: true, cols, @@ -226,6 +219,8 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, ID fontSize: font.fontSize, letterSpacing: font.letterSpacing, lineHeight: font.lineHeight, + logLevel: vscodeToXtermLogLevel(this._logger.getLevel()), + logger: this._logger, minimumContrastRatio: config.minimumContrastRatio, tabStopWidth: config.tabStopWidth, cursorBlink: config.cursorBlinking, @@ -256,6 +251,7 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, ID })); this.add(this._themeService.onDidColorThemeChange(theme => this._updateTheme(theme))); + this.add(this._logger.onDidChangeLogLevel(e => this.raw.options.logLevel = vscodeToXtermLogLevel(e))); // Refire events this.add(this.raw.onSelectionChange(() => { @@ -291,6 +287,16 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, ID } } + *getBufferReverseIterator(): IterableIterator { + for (let i = this.raw.buffer.active.length; i >= 0; i--) { + const { lineData, lineIndex } = getFullBufferLineAsString(i, this.raw.buffer.active); + if (lineData) { + i = lineIndex; + yield lineData; + } + } + } + async getContentsAsHtml(): Promise { if (!this._serializeAddon) { const Addon = await this._getSerializeAddonConstructor(); @@ -630,9 +636,9 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, ID this._disposeOfCanvasRenderer(); try { this.raw.loadAddon(this._webglAddon); - this._logService.trace('Webgl was loaded'); + this._logger.trace('Webgl was loaded'); this._webglAddon.onContextLoss(() => { - this._logService.info(`Webgl lost context, disposing of webgl renderer`); + this._logger.info(`Webgl lost context, disposing of webgl renderer`); this._disposeOfWebglRenderer(); }); // Uncomment to add the texture atlas to the DOM @@ -642,7 +648,7 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, ID // } // }, 5000); } catch (e) { - this._logService.warn(`Webgl could not be loaded. Falling back to the canvas renderer type.`, e); + this._logger.warn(`Webgl could not be loaded. Falling back to the canvas renderer type.`, e); const neverMeasureRenderTime = this._storageService.getBoolean(TerminalStorageKeys.NeverMeasureRenderTime, StorageScope.APPLICATION, false); // if it's already set to dom, no need to measure render time if (!neverMeasureRenderTime && this._configHelper.config.gpuAcceleration !== 'off') { @@ -663,9 +669,9 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, ID this._disposeOfWebglRenderer(); try { this.raw.loadAddon(this._canvasAddon); - this._logService.trace('Canvas renderer was loaded'); + this._logger.trace('Canvas renderer was loaded'); } catch (e) { - this._logService.warn(`Canvas renderer could not be loaded, falling back to dom renderer`, e); + this._logger.warn(`Canvas renderer could not be loaded, falling back to dom renderer`, e); const neverMeasureRenderTime = this._storageService.getBoolean(TerminalStorageKeys.NeverMeasureRenderTime, StorageScope.APPLICATION, false); // if it's already set to dom, no need to measure render time if (!neverMeasureRenderTime && this._configHelper.config.gpuAcceleration !== 'off') { @@ -900,3 +906,14 @@ export function getXtermScaledDimensions(font: ITerminalFont, width: number, hei return { rows, cols }; } + +function vscodeToXtermLogLevel(logLevel: LogLevel): XtermLogLevel { + switch (logLevel) { + case LogLevel.Trace: + case LogLevel.Debug: return 'debug'; + case LogLevel.Info: return 'info'; + case LogLevel.Warning: return 'warn'; + case LogLevel.Error: return 'error'; + default: return 'off'; + } +} diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index 8503f5c471f..c0355a1f873 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -576,7 +576,6 @@ export const enum TerminalCommandId { SelectToNextCommand = 'workbench.action.terminal.selectToNextCommand', SelectToPreviousLine = 'workbench.action.terminal.selectToPreviousLine', SelectToNextLine = 'workbench.action.terminal.selectToNextLine', - ToggleEscapeSequenceLogging = 'toggleEscapeSequenceLogging', SendSequence = 'workbench.action.terminal.sendSequence', ToggleFindRegex = 'workbench.action.terminal.toggleFindRegex', ToggleFindWholeWord = 'workbench.action.terminal.toggleFindWholeWord', diff --git a/src/vs/workbench/contrib/terminal/electron-sandbox/terminalNativeContribution.ts b/src/vs/workbench/contrib/terminal/electron-sandbox/terminalNativeContribution.ts index 19dbb559546..2b541d9fbbd 100644 --- a/src/vs/workbench/contrib/terminal/electron-sandbox/terminalNativeContribution.ts +++ b/src/vs/workbench/contrib/terminal/electron-sandbox/terminalNativeContribution.ts @@ -29,9 +29,7 @@ export class TerminalNativeContribution extends Disposable implements IWorkbench this._register(nativeHostService.onDidResumeOS(() => this._onOsResume())); this._terminalService.setNativeDelegate({ - getWindowCount: () => nativeHostService.getWindowCount(), - openDevTools: () => nativeHostService.openDevTools(), - toggleDevTools: () => nativeHostService.toggleDevTools() + getWindowCount: () => nativeHostService.getWindowCount() }); const connection = remoteAgentService.getConnection(); diff --git a/yarn.lock b/yarn.lock index c3364a6dbd2..8749297dd5c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10453,45 +10453,45 @@ xtend@~2.1.1: dependencies: object-keys "~0.4.0" -xterm-addon-canvas@0.5.0-beta.1: - version "0.5.0-beta.1" - resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.5.0-beta.1.tgz#b5ae185741423715460a66029c944b4dededfab0" - integrity sha512-A7yjIpyTcOh8ckPJw1YFDvwbTbQ+grM+kTtutOvu5LjLSV9EoCHX17kVoiT2V29ywF7KJMeLYwfBwyFE3uA3QQ== +xterm-addon-canvas@0.5.0-beta.2: + version "0.5.0-beta.2" + resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.5.0-beta.2.tgz#1b83c2a9a306766c47a4f80b8c65cc9ee5f5a5c4" + integrity sha512-oTb/2krdbHYGxH2X6yiBZzAB/1WB+apUu4nXHdhBnht20bl8E+YVWqg95D4o0Gl+QJI+XOfB3mqmWaBx1x531A== xterm-addon-image@0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/xterm-addon-image/-/xterm-addon-image-0.4.1.tgz#ec8f750af48005ad641c1128fa1f551ac198472a" integrity sha512-iJpYyvtbHg4oXSv+D6J73ZfCjnboZpbZ567MLplXDBlYSUknv3kvPTfVMPJATV7Zsx7+bDgyXboCh9vsDf/m/w== -xterm-addon-search@0.13.0-beta.1: - version "0.13.0-beta.1" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.13.0-beta.1.tgz#9fb6ede402d4c369d59d5d6faefe54a05b125bcf" - integrity sha512-rdOIhwkfRASqTriUO8QP9UY0p6BosLMv1NXTZqhgq3/5xAXx4VZg6mlQjTRGnUz/GJIN1jU9e/Vp20SpocP/Hw== +xterm-addon-search@0.13.0-beta.2: + version "0.13.0-beta.2" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.13.0-beta.2.tgz#c984a35312acad4ce768d17bc49adffa90eece61" + integrity sha512-+VoPhIRmfiX2uh2t6xD/RJtBYjVjrkNa3dKQnOYEp4UbYzDjK57rZX652mnZ82TQfk/juxf7v+jV5aRdNLZVbA== -xterm-addon-serialize@0.11.0-beta.1: - version "0.11.0-beta.1" - resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.11.0-beta.1.tgz#a4bc1ef5d8b8db0180c07f071ce543536d806db1" - integrity sha512-2I9Dq49nXUc6ymznwJp8SUsDq5owUdYviUy11HzLh35baDjzbG31CCu5Gs8KSlfUxpNRr3BxaV5/hx7MRPu7Qg== +xterm-addon-serialize@0.11.0-beta.2: + version "0.11.0-beta.2" + resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.11.0-beta.2.tgz#fff924decfbf1bc08434317894f985fef7bb260b" + integrity sha512-tN4IT2e+EIpsoFpMONUh1OAuoVAcV7AYOLsqMKgH6GNWB1D/LKGo3cwjpw1vwRZzDJJcCcLxYgxlUzhPbDbLxQ== xterm-addon-unicode11@0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.5.0.tgz#41c0d96acc1e3bb6c6596eee64e163b6bca74be7" integrity sha512-Jm4/g4QiTxiKiTbYICQgC791ubhIZyoIwxAIgOW8z8HWFNY+lwk+dwaKEaEeGBfM48Vk8fklsUW9u/PlenYEBg== -xterm-addon-webgl@0.16.0-beta.1: - version "0.16.0-beta.1" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.16.0-beta.1.tgz#e2b41c6b5f838724a5cb3cfa4231e2d1b8f3f130" - integrity sha512-iJK+Uk+23Mh84BNa/44JqAdPESdNKN0ONfw6UztmDk2HTvsy47sU+d/lgF2kOcuI3ew2tRzK9YlupOUhVPwe9g== +xterm-addon-webgl@0.16.0-beta.2: + version "0.16.0-beta.2" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.16.0-beta.2.tgz#30489ef235405255ee54077002c90553531870d8" + integrity sha512-DAt4E/QI1w34ToBhcDj0vaZOAHOO+ffwMt2HGDAB7amPXRcMb0LBIjLpyZhB9sD4tbIgsE0vuqZi1R9vKxZwbg== -xterm-headless@5.3.0-beta.1: - version "5.3.0-beta.1" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.3.0-beta.1.tgz#8c7db703b9f57496c2f052411721c00909b08e8b" - integrity sha512-6rsv6l44hLL9Eg2UrfAbCiZcAucdHuPyIsovl2BEmluo4chwd4LD7VINRlPV/x8ML2HgD9SohFyNs5BQAc07Gg== +xterm-headless@5.3.0-beta.3: + version "5.3.0-beta.3" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.3.0-beta.3.tgz#153cf330082f4b2aae64ff736ef0b62d93c30da8" + integrity sha512-4i/bpFoAn4D4ZA4g8RKrJdhq2EcB1HN2E25yUg3omRbWCOZ2Gp9nAn+62LYzX5rvGqdNbpUTRJLX0lKwEFyLFw== -xterm@5.3.0-beta.1: - version "5.3.0-beta.1" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.3.0-beta.1.tgz#68e76f2818965592c60bb269360f1fc37219f4ae" - integrity sha512-2v/Qmk1A0wO5oouRWUWZ3wxqtfFjxsQbZ1sWxPGJTQvoTSdkORLG44gxrU+Sk2jB5Ojz+3Kg42bnfFghsXVzlw== +xterm@5.3.0-beta.3: + version "5.3.0-beta.3" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.3.0-beta.3.tgz#1a1aaf9a57afe4dcf86e87d8dc85e80a41d68644" + integrity sha512-NGxpV25U2W/KKk6M5V2OXuLgrKY+w05ABi66ZEYuCTi7ux1Qv0z+jm7bkgzk1pGGiTVLG+90OGr2nrhbFr5Y4w== y18n@^3.2.1: version "3.2.2" From 2dad7f52ad6de2738211b1de774edf4540efabd5 Mon Sep 17 00:00:00 2001 From: Raymond Zhao <7199958+rzhao271@users.noreply.github.com> Date: Fri, 16 Jun 2023 10:10:07 -0700 Subject: [PATCH 46/69] Bump emmet-helper (#184616) --- extensions/emmet/yarn.lock | 41 +++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/extensions/emmet/yarn.lock b/extensions/emmet/yarn.lock index 886d4d8d83d..fdf68a56252 100644 --- a/extensions/emmet/yarn.lock +++ b/extensions/emmet/yarn.lock @@ -2,19 +2,19 @@ # yarn lockfile v1 -"@emmetio/abbreviation@^2.3.2": - version "2.3.2" - resolved "https://registry.yarnpkg.com/@emmetio/abbreviation/-/abbreviation-2.3.2.tgz#375bf6bc6ae6405f62dd0ddab2559b46502d01f4" - integrity sha512-8vqkn4rtjm5Zv34RPgsq3/ij88ri+IcfC2MxPELytrQvfpaLyppscE0YSwDVuIUR6KL5GCBUfr5Mo7SHSbswpA== +"@emmetio/abbreviation@^2.3.3": + version "2.3.3" + resolved "https://registry.yarnpkg.com/@emmetio/abbreviation/-/abbreviation-2.3.3.tgz#ed2b88fe37b972292d6026c7c540aaf887cecb6e" + integrity sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA== dependencies: - "@emmetio/scanner" "^1.0.3" + "@emmetio/scanner" "^1.0.4" -"@emmetio/css-abbreviation@^2.1.7": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@emmetio/css-abbreviation/-/css-abbreviation-2.1.7.tgz#9791269586d780cf4b40078ea79886d1888a188a" - integrity sha512-nrOt3/QROjYYK1cMjoO5fCfHIf0hFpcZeQQt7Ew6ixZ0ElEEs77ijnY57HC6ti91W/mn+c1T7ET8sClBMRHHBg== +"@emmetio/css-abbreviation@^2.1.8": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@emmetio/css-abbreviation/-/css-abbreviation-2.1.8.tgz#b785313486eba6cb7eb623ad39378c4e1063dc00" + integrity sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw== dependencies: - "@emmetio/scanner" "^1.0.3" + "@emmetio/scanner" "^1.0.4" "@emmetio/css-parser@ramya-rao-a/css-parser#vscode": version "0.4.0" @@ -38,11 +38,6 @@ dependencies: "@emmetio/scanner" "^1.0.4" -"@emmetio/scanner@^1.0.3": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@emmetio/scanner/-/scanner-1.0.3.tgz#755e581517e2302d31a387e4064bf73035ebfc46" - integrity sha512-/EFyTijquAwKMGSBd50RnjxsfDXmZAFp71PGu7sM6LEnEJXMV+FKL7Rvr6YLu4czQmPVRsfyhcbQz+WZnM4AZw== - "@emmetio/scanner@^1.0.4": version "1.0.4" resolved "https://registry.yarnpkg.com/@emmetio/scanner/-/scanner-1.0.4.tgz#e9cdc67194fd91f8b7eb141014be4f2d086c15f1" @@ -64,9 +59,9 @@ integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== "@vscode/emmet-helper@^2.8.8": - version "2.8.8" - resolved "https://registry.yarnpkg.com/@vscode/emmet-helper/-/emmet-helper-2.8.8.tgz#df64989d2812e031cd6393ce896a2fe33ae976bd" - integrity sha512-QuD4CmNeXSFxuP8VZwI6qL+8vmmd7JcSdwsEIdsrzb4YumWs/+4rXRX9MM+NsFfUO69g6ezngCD7XRd6jY9TQw== + version "2.8.9" + resolved "https://registry.yarnpkg.com/@vscode/emmet-helper/-/emmet-helper-2.8.9.tgz#536a2cba2f78b0dd25a874b85ab95f9b5424eb39" + integrity sha512-ygpVStaePHt9aI9zk4NNJWI/NsRaeDSW1vQsZVmtpVRVCOdwYlsc3BfB/eppUu1OucT0x3OHDAzKcxnitjcSXQ== dependencies: emmet "^2.4.3" jsonc-parser "^2.3.0" @@ -75,12 +70,12 @@ vscode-uri "^2.1.2" emmet@^2.4.3: - version "2.4.3" - resolved "https://registry.yarnpkg.com/emmet/-/emmet-2.4.3.tgz#c99f19e572a270da27f456dd7f65dfda83dc0ec1" - integrity sha512-Bq6zozVDVrLbBmKdosI9Q2DvrFh/ehwnNjgDRsvGVjPOEAhMKie9HwQnPuUi3NOZ2itVGyRwsLAdufnG9DVFwg== + version "2.4.4" + resolved "https://registry.yarnpkg.com/emmet/-/emmet-2.4.4.tgz#801aad64659dc76f3003130db767d77a78ac298e" + integrity sha512-v8Mwpjym55CS3EjJgiCLWUB3J2HSR93jhzXW325720u8KvYxdI2voYLstW3pHBxFz54H6jFjayR9G4LfTG0q+g== dependencies: - "@emmetio/abbreviation" "^2.3.2" - "@emmetio/css-abbreviation" "^2.1.7" + "@emmetio/abbreviation" "^2.3.3" + "@emmetio/css-abbreviation" "^2.1.8" image-size@~1.0.0: version "1.0.0" From cc025ebac82c47f4b175a11936c454d0dfef8381 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Fri, 16 Jun 2023 12:11:48 -0500 Subject: [PATCH 47/69] follow up cue --- src/vs/platform/audioCues/browser/audioCueService.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/audioCues/browser/audioCueService.ts b/src/vs/platform/audioCues/browser/audioCueService.ts index 1d4df23804c..2e510e66a22 100644 --- a/src/vs/platform/audioCues/browser/audioCueService.ts +++ b/src/vs/platform/audioCues/browser/audioCueService.ts @@ -53,6 +53,12 @@ export class AudioCueService extends Disposable implements IAudioCueService { await Promise.all(Array.from(sounds).map(sound => this.playSound(sound, true))); } + /** + * Gaming and other apps often play a sound variant when the same event happens again + * for an improved experience. This function plays a random sound from the given group to accomplish that. + * @param groupId + * @param allowManyInParallel + */ public playRandomAudioCue(groupId: AudioCueGroupId, allowManyInParallel?: boolean): void { const cues = AudioCue.allAudioCues.filter(cue => cue.groupId === groupId); const index = Math.floor(Math.random() * cues.length); @@ -350,7 +356,7 @@ export class AudioCue { settingsKey: 'audioCues.chatRequestSent' }); - public static readonly chatResponseReceived = { + private static readonly chatResponseReceived = { name: localize('audioCues.chatResponseReceived', 'Chat Response Received'), settingsKey: 'audioCues.chatResponseReceived', groupId: AudioCueGroupId.chatResponseReceived From cc76abec738a56fff3f211ed1e31be79ab055429 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 16 Jun 2023 10:29:23 -0700 Subject: [PATCH 48/69] Fix edge case where logLevel got set back to info --- src/vs/workbench/contrib/terminal/browser/terminalService.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index ab1a2474dbf..b0d47847513 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -61,8 +61,6 @@ export class TerminalService implements ITerminalService { private _terminalEditorActive: IContextKey; private readonly _terminalShellTypeContextKey: IContextKey; - private _escapeSequenceLoggingEnabled: boolean = false; - private _isShuttingDown: boolean = false; private _backgroundedTerminalInstances: ITerminalInstance[] = []; private _backgroundedTerminalDisposables: Map = new Map(); @@ -183,7 +181,6 @@ export class TerminalService implements ITerminalService { this._forwardInstanceHostEvents(this._terminalEditorService); this._terminalGroupService.onDidChangeActiveGroup(this._onDidChangeActiveGroup.fire, this._onDidChangeActiveGroup); this._terminalInstanceService.onDidCreateInstance(instance => { - instance.setEscapeSequenceLogging(this._escapeSequenceLoggingEnabled); this._initInstanceListeners(instance); this._onDidCreateInstance.fire(instance); }); From f929eaa79f637ae42aea057cba6632b47f912e11 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Fri, 16 Jun 2023 12:33:05 -0500 Subject: [PATCH 49/69] Update src/vs/platform/audioCues/browser/audioCueService.ts --- src/vs/platform/audioCues/browser/audioCueService.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/vs/platform/audioCues/browser/audioCueService.ts b/src/vs/platform/audioCues/browser/audioCueService.ts index 2e510e66a22..debebabccd8 100644 --- a/src/vs/platform/audioCues/browser/audioCueService.ts +++ b/src/vs/platform/audioCues/browser/audioCueService.ts @@ -56,8 +56,6 @@ export class AudioCueService extends Disposable implements IAudioCueService { /** * Gaming and other apps often play a sound variant when the same event happens again * for an improved experience. This function plays a random sound from the given group to accomplish that. - * @param groupId - * @param allowManyInParallel */ public playRandomAudioCue(groupId: AudioCueGroupId, allowManyInParallel?: boolean): void { const cues = AudioCue.allAudioCues.filter(cue => cue.groupId === groupId); From 8a74ad8ff50911025e1acadfdf6ff0535ffd1125 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Thu, 15 Jun 2023 14:11:03 -0700 Subject: [PATCH 50/69] cli: show service status in tunnel log Fixes #183714 --- cli/src/commands/args.rs | 2 +- cli/src/commands/tunnels.rs | 40 +++++++++++++------ cli/src/lib.rs | 2 +- cli/src/tunnels/service.rs | 3 ++ cli/src/tunnels/service_linux.rs | 18 ++++++++- cli/src/tunnels/service_macos.rs | 5 +++ cli/src/tunnels/service_windows.rs | 5 +++ cli/src/util/tar.rs | 4 +- cli/src/util/zipper.rs | 3 +- .../remoteTunnel/node/remoteTunnelService.ts | 27 ++++++++----- 10 files changed, 80 insertions(+), 29 deletions(-) diff --git a/cli/src/commands/args.rs b/cli/src/commands/args.rs index 92decf5ff0e..5d23bd634fb 100644 --- a/cli/src/commands/args.rs +++ b/cli/src/commands/args.rs @@ -6,7 +6,7 @@ use std::{fmt, path::PathBuf}; use crate::{constants, log, options, tunnels::code_server::CodeServerArgs}; -use clap::{ValueEnum, Args, Parser, Subcommand}; +use clap::{Args, Parser, Subcommand, ValueEnum}; use const_format::concatcp; const CLI_NAME: &str = concatcp!(constants::PRODUCT_NAME_LONG, " CLI"); diff --git a/cli/src/commands/tunnels.rs b/cli/src/commands/tunnels.rs index b8d7b0b60bd..3f29ee7020e 100644 --- a/cli/src/commands/tunnels.rs +++ b/cli/src/commands/tunnels.rs @@ -4,7 +4,8 @@ *--------------------------------------------------------------------------------------------*/ use async_trait::async_trait; -use base64::{Engine as _, engine::general_purpose as b64}; +use base64::{engine::general_purpose as b64, Engine as _}; +use serde::Serialize; use sha2::{Digest, Sha256}; use std::{str::FromStr, time::Duration}; use sysinfo::Pid; @@ -247,8 +248,14 @@ pub async fn kill(ctx: CommandContext) -> Result { .map_err(|e| e.into()) } +#[derive(Serialize)] +pub struct StatusOutput { + pub tunnel: Option, + pub service_installed: bool, +} + pub async fn status(ctx: CommandContext) -> Result { - let status = do_single_rpc_call::<_, protocol::singleton::Status>( + let tunnel_status = do_single_rpc_call::<_, protocol::singleton::Status>( &ctx.paths.tunnel_lockfile(), ctx.log.clone(), protocol::singleton::METHOD_STATUS, @@ -256,17 +263,24 @@ pub async fn status(ctx: CommandContext) -> Result { ) .await; - match status { - Err(CodeError::NoRunningTunnel) => { - ctx.log.result(CodeError::NoRunningTunnel.to_string()); - Ok(1) - } - Err(e) => Err(e.into()), - Ok(s) => { - ctx.log.result(serde_json::to_string(&s).unwrap()); - Ok(0) - } - } + let service_installed = create_service_manager(ctx.log.clone(), &ctx.paths) + .is_installed() + .await + .unwrap_or(false); + + ctx.log.result( + serde_json::to_string(&StatusOutput { + service_installed, + tunnel: match tunnel_status { + Ok(s) => Some(s.tunnel), + Err(CodeError::NoRunningTunnel) => None, + Err(e) => return Err(e.into()), + }, + }) + .unwrap(), + ); + + Ok(0) } /// Removes unused servers. diff --git a/cli/src/lib.rs b/cli/src/lib.rs index 93777852df2..b2e23cb4d69 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -18,8 +18,8 @@ pub mod tunnels; pub mod update_service; pub mod util; -mod download_cache; mod async_pipe; +mod download_cache; mod json_rpc; mod msgpack_rpc; mod rpc; diff --git a/cli/src/tunnels/service.rs b/cli/src/tunnels/service.rs index 31bf6890996..dba68f3b614 100644 --- a/cli/src/tunnels/service.rs +++ b/cli/src/tunnels/service.rs @@ -41,6 +41,9 @@ pub trait ServiceManager { /// Show logs from the running service to standard out. async fn show_logs(&self) -> Result<(), AnyError>; + /// Gets whether the tunnel service is installed. + async fn is_installed(&self) -> Result; + /// Unregisters the current executable as a service. async fn unregister(&self) -> Result<(), AnyError>; } diff --git a/cli/src/tunnels/service_linux.rs b/cli/src/tunnels/service_linux.rs index 725b72a8d6d..3d1258a469a 100644 --- a/cli/src/tunnels/service_linux.rs +++ b/cli/src/tunnels/service_linux.rs @@ -40,7 +40,7 @@ impl SystemdService { async fn connect() -> Result { let connection = Connection::session() .await - .map_err(|e| wrap(e, "error creating dbus session"))?; + .map_err(|e| wrap(e, "Error creating dbus session. This command uses systemd for managing services, you should check that systemd is installed and running as a user. If it's already installed, you may need to:\n\n- Install the `dbus-user-session` package and reboot\n- Start the user dbus session with `systemctl --user enable dbus --now`. \n\nThe error encountered was"))?; Ok(connection) } @@ -113,6 +113,20 @@ impl ServiceManager for SystemdService { Ok(()) } + async fn is_installed(&self) -> Result { + let connection = SystemdService::connect().await?; + let proxy = SystemdService::proxy(&connection).await?; + let state = proxy + .get_unit_file_state(SystemdService::service_name_string()) + .await; + + if let Ok(s) = state { + Ok(s == "enabled") + } else { + Ok(false) + } + } + async fn run( self, launcher_paths: crate::state::LauncherPaths, @@ -219,6 +233,8 @@ trait SystemdManagerDbus { force: bool, ) -> zbus::Result<(bool, Vec<(String, String, String)>)>; + fn get_unit_file_state(&self, file: String) -> zbus::Result; + fn link_unit_files( &self, files: Vec, diff --git a/cli/src/tunnels/service_macos.rs b/cli/src/tunnels/service_macos.rs index dcc676ffce5..2d0a23f8cb2 100644 --- a/cli/src/tunnels/service_macos.rs +++ b/cli/src/tunnels/service_macos.rs @@ -75,6 +75,11 @@ impl ServiceManager for LaunchdService { handle.run_service(self.log, launcher_paths).await } + async fn is_installed(&self) -> Result { + let cmd = capture_command_and_check_status("launchctl", &["list"]).await?; + Ok(String::from_utf8_lossy(&cmd.stdout).contains(&get_service_label())) + } + async fn unregister(&self) -> Result<(), crate::util::errors::AnyError> { let service_file = get_service_file_path()?; diff --git a/cli/src/tunnels/service_windows.rs b/cli/src/tunnels/service_windows.rs index 3404b4ed52c..427eddd620d 100644 --- a/cli/src/tunnels/service_windows.rs +++ b/cli/src/tunnels/service_windows.rs @@ -114,6 +114,11 @@ impl CliServiceManager for WindowsService { Ok(()) } + async fn is_installed(&self) -> Result { + let key = WindowsService::open_key()?; + Ok(key.get_raw_value(TUNNEL_ACTIVITY_NAME).is_ok()) + } + async fn unregister(&self) -> Result<(), AnyError> { let key = WindowsService::open_key()?; key.delete_value(TUNNEL_ACTIVITY_NAME) diff --git a/cli/src/util/tar.rs b/cli/src/util/tar.rs index 77dd67abbb0..248f63f9720 100644 --- a/cli/src/util/tar.rs +++ b/cli/src/util/tar.rs @@ -6,7 +6,7 @@ use crate::util::errors::{wrap, WrappedError}; use flate2::read::GzDecoder; use std::fs; -use std::io::{Seek, SeekFrom}; +use std::io::Seek; use std::path::{Path, PathBuf}; use tar::Archive; @@ -65,7 +65,7 @@ where // reset since skip logic read the tar already: tar_gz - .seek(SeekFrom::Start(0)) + .rewind() .map_err(|e| wrap(e, "error resetting seek position"))?; let tar = GzDecoder::new(tar_gz); diff --git a/cli/src/util/zipper.rs b/cli/src/util/zipper.rs index 84eec040b0e..45dd3b7e85d 100644 --- a/cli/src/util/zipper.rs +++ b/cli/src/util/zipper.rs @@ -88,8 +88,7 @@ where use std::io::Read; use std::os::unix::ffi::OsStringExt; - if matches!(file.unix_mode(), Some(mode) if mode & (S_IFLNK as u32) == (S_IFLNK as u32)) - { + if matches!(file.unix_mode(), Some(mode) if mode & S_IFLNK == S_IFLNK) { let mut link_to = Vec::new(); file.read_to_end(&mut link_to).map_err(|e| { wrap( diff --git a/src/vs/platform/remoteTunnel/node/remoteTunnelService.ts b/src/vs/platform/remoteTunnel/node/remoteTunnelService.ts index 9b73eece6ba..e3cee9778a2 100644 --- a/src/vs/platform/remoteTunnel/node/remoteTunnelService.ts +++ b/src/vs/platform/remoteTunnel/node/remoteTunnelService.ts @@ -165,7 +165,7 @@ export class RemoteTunnelService extends Disposable implements IRemoteTunnelServ } async startTunnel(session: IRemoteTunnelSession): Promise { - if (isSameSession(session, this._session)) { + if (isSameSession(session, this._session) && this._tunnelStatus.type !== 'disconnected') { return this._tunnelStatus; } this.setSession(session); @@ -195,7 +195,7 @@ export class RemoteTunnelService extends Disposable implements IRemoteTunnelServ } }; try { - await this.runCodeTunneCommand('stop', ['kill'], onOutput); + await this.runCodeTunnelCommand('stop', ['kill'], onOutput); } catch (e) { this._logger.error(e); } @@ -213,26 +213,35 @@ export class RemoteTunnelService extends Disposable implements IRemoteTunnelServ } let isAttached = false; + let output = ''; const onOutput = (a: string, isErr: boolean) => { if (isErr) { this._logger.error(a); } else { - this._logger.info(a); + output += a; } if (!this.environmentService.isBuilt && a.startsWith(' Compiling')) { this.setTunnelStatus(TunnelStates.connecting(localize('remoteTunnelService.building', 'Building CLI from sources'))); } }; - const statusProcess = this.runCodeTunneCommand('status', ['status'], onOutput); + const statusProcess = this.runCodeTunnelCommand('status', ['status'], onOutput); this._tunnelProcess = statusProcess; try { - const status = await statusProcess; + await statusProcess; if (this._tunnelProcess !== statusProcess) { return; } - isAttached = status === 0; + + // split and find the line, since in dev builds additional noise is + // added by cargo to the output. + const status: { + service_installed: boolean; + tunnel: object | null; + } = JSON.parse(output.trim().split('\n').find(l => l.startsWith('{'))!); + + isAttached = !!status.tunnel; this._logger.info(isAttached ? 'Other tunnel running, attaching...' : 'No other tunnel running'); if (!isAttached && !this._session) { this._tunnelProcess = undefined; @@ -255,7 +264,7 @@ export class RemoteTunnelService extends Disposable implements IRemoteTunnelServ a = a.replaceAll(token, '*'.repeat(4)); onOutput(a, isErr); }; - const loginProcess = this.runCodeTunneCommand('login', ['user', 'login', '--provider', session.providerId, '--access-token', token, '--log', LogLevelToString(this._logger.getLevel())], onLoginOutput); + const loginProcess = this.runCodeTunnelCommand('login', ['user', 'login', '--provider', session.providerId, '--access-token', token, '--log', LogLevelToString(this._logger.getLevel())], onLoginOutput); this._tunnelProcess = loginProcess; try { await loginProcess; @@ -286,7 +295,7 @@ export class RemoteTunnelService extends Disposable implements IRemoteTunnelServ if (this._preventSleep()) { args.push('--no-sleep'); } - const serveCommand = this.runCodeTunneCommand('tunnel', args, (message: string, isErr: boolean) => { + const serveCommand = this.runCodeTunnelCommand('tunnel', args, (message: string, isErr: boolean) => { if (isErr) { this._logger.error(message); } else { @@ -315,7 +324,7 @@ export class RemoteTunnelService extends Disposable implements IRemoteTunnelServ }); } - private runCodeTunneCommand(logLabel: string, commandArgs: string[], onOutput: (message: string, isError: boolean) => void = () => { }): CancelablePromise { + private runCodeTunnelCommand(logLabel: string, commandArgs: string[], onOutput: (message: string, isError: boolean) => void = () => { }): CancelablePromise { return createCancelablePromise(token => { return new Promise((resolve, reject) => { if (token.isCancellationRequested) { From 8adc6e0aacfac34a5e15bad5d8e7f3f0d39a7b01 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 16 Jun 2023 10:42:49 -0700 Subject: [PATCH 51/69] Fix tests and remove unused method --- src/vs/workbench/contrib/terminal/browser/terminal.ts | 5 ----- .../workbench/contrib/terminal/browser/terminalInstance.ts | 5 ----- .../terminal/test/browser/xterm/xtermTerminal.test.ts | 6 +++--- .../accessibility/test/browser/bufferContentTracker.test.ts | 4 +++- 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 284c7238948..242786cc2fd 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -854,11 +854,6 @@ export interface ITerminalInstance { */ toggleSizeToContentWidth(): Promise; - /** - * Sets whether escape seqeunce logging is enabled in the devtools console. - */ - setEscapeSequenceLogging(enable: boolean): void; - /** * Gets the initial current working directory, fetching it from the backend if required. */ diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 6a6e7f7cfe6..ad4db231ba1 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -1702,11 +1702,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { }); } - async setEscapeSequenceLogging(enable: boolean): Promise { - const xterm = await this._xtermReadyPromise; - xterm.raw.options.logLevel = enable ? 'debug' : 'info'; - } - @debounce(1000) relaunch(): void { this.reuseTerminal(this._shellLaunchConfig, true); diff --git a/src/vs/workbench/contrib/terminal/test/browser/xterm/xtermTerminal.test.ts b/src/vs/workbench/contrib/terminal/test/browser/xterm/xtermTerminal.test.ts index f3e30380a60..f6ee3248f66 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/xterm/xtermTerminal.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/xterm/xtermTerminal.test.ts @@ -19,9 +19,9 @@ import { Emitter } from 'vs/base/common/event'; import { TERMINAL_BACKGROUND_COLOR, TERMINAL_FOREGROUND_COLOR, TERMINAL_CURSOR_FOREGROUND_COLOR, TERMINAL_CURSOR_BACKGROUND_COLOR, TERMINAL_SELECTION_BACKGROUND_COLOR, TERMINAL_SELECTION_FOREGROUND_COLOR, TERMINAL_INACTIVE_SELECTION_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; import { PANEL_BACKGROUND, SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme'; import { WebglAddon } from 'xterm-addon-webgl'; -import { ILogService, NullLogService } from 'vs/platform/log/common/log'; +import { ILoggerService } from 'vs/platform/log/common/log'; import { IStorageService } from 'vs/platform/storage/common/storage'; -import { TestStorageService } from 'vs/workbench/test/common/workbenchTestServices'; +import { TestLoggerService, TestStorageService } from 'vs/workbench/test/common/workbenchTestServices'; import { isSafari } from 'vs/base/browser/browser'; import { TerminalCapabilityStore } from 'vs/platform/terminal/common/capabilities/terminalCapabilityStore'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; @@ -112,7 +112,7 @@ suite('XtermTerminal', () => { instantiationService = new TestInstantiationService(); instantiationService.stub(IConfigurationService, configurationService); - instantiationService.stub(ILogService, new NullLogService()); + instantiationService.stub(ILoggerService, new TestLoggerService()); instantiationService.stub(IStorageService, new TestStorageService()); instantiationService.stub(IThemeService, themeService); instantiationService.stub(IViewDescriptorService, viewDescriptorService); diff --git a/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts b/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts index e1945415abf..d55f7aa0123 100644 --- a/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts +++ b/src/vs/workbench/contrib/terminalContrib/accessibility/test/browser/bufferContentTracker.test.ts @@ -12,7 +12,7 @@ import { ContextMenuService } from 'vs/platform/contextview/browser/contextMenuS import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService'; -import { ILogService, NullLogService } from 'vs/platform/log/common/log'; +import { ILogService, ILoggerService, NullLogService } from 'vs/platform/log/common/log'; import { TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities'; import { TerminalCapabilityStore } from 'vs/platform/terminal/common/capabilities/terminalCapabilityStore'; import { IThemeService } from 'vs/platform/theme/common/themeService'; @@ -24,6 +24,7 @@ import { ITerminalConfiguration } from 'vs/workbench/contrib/terminal/common/ter import { BufferContentTracker } from 'vs/workbench/contrib/terminalContrib/accessibility/browser/bufferContentTracker'; import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { TestLifecycleService } from 'vs/workbench/test/browser/workbenchTestServices'; +import { TestLoggerService } from 'vs/workbench/test/common/workbenchTestServices'; import { Terminal } from 'xterm'; const defaultTerminalConfig: Partial = { @@ -55,6 +56,7 @@ suite('Buffer Content Tracker', () => { instantiationService.stub(IConfigurationService, configurationService); instantiationService.stub(IThemeService, themeService); instantiationService.stub(ILogService, new NullLogService()); + instantiationService.stub(ILoggerService, new TestLoggerService()); instantiationService.stub(IContextMenuService, instantiationService.createInstance(ContextMenuService)); instantiationService.stub(ILifecycleService, new TestLifecycleService()); instantiationService.stub(IContextKeyService, new MockContextKeyService()); From 4d42fcf80927152e9a92506e7d5df520f61ed05c Mon Sep 17 00:00:00 2001 From: meganrogge Date: Fri, 16 Jun 2023 12:56:43 -0500 Subject: [PATCH 52/69] use status instead of alert --- src/vs/base/browser/ui/aria/aria.ts | 15 +++++---------- .../workbench/contrib/chat/browser/chatWidget.ts | 4 ++-- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/vs/base/browser/ui/aria/aria.ts b/src/vs/base/browser/ui/aria/aria.ts index 69e31279111..a4da8d78445 100644 --- a/src/vs/base/browser/ui/aria/aria.ts +++ b/src/vs/base/browser/ui/aria/aria.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import * as dom from 'vs/base/browser/dom'; -import { isMacintosh } from 'vs/base/common/platform'; import 'vs/css!./aria'; // Use a max length since we are inserting the whole msg in the DOM and that can cause browsers to freeze for long messages #94233 @@ -69,16 +68,12 @@ export function status(msg: string): void { return; } - if (isMacintosh) { - alert(msg); // VoiceOver does not seem to support status role + if (statusContainer.textContent !== msg) { + dom.clearNode(statusContainer2); + insertMessage(statusContainer, msg); } else { - if (statusContainer.textContent !== msg) { - dom.clearNode(statusContainer2); - insertMessage(statusContainer, msg); - } else { - dom.clearNode(statusContainer); - insertMessage(statusContainer2, msg); - } + dom.clearNode(statusContainer); + insertMessage(statusContainer2, msg); } } diff --git a/src/vs/workbench/contrib/chat/browser/chatWidget.ts b/src/vs/workbench/contrib/chat/browser/chatWidget.ts index 7f756c4bb63..9c6cff1d7f6 100644 --- a/src/vs/workbench/contrib/chat/browser/chatWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/chatWidget.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as dom from 'vs/base/browser/dom'; -import { alert } from 'vs/base/browser/ui/aria/aria'; +import { status } from 'vs/base/browser/ui/aria/aria'; import { ITreeContextMenuEvent, ITreeElement } from 'vs/base/browser/ui/tree/tree'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Emitter } from 'vs/base/common/event'; @@ -529,7 +529,7 @@ export class ChatAccessibilityService extends Disposable implements IChatAccessi return; } const errorDetails = response.errorDetails ? ` ${response.errorDetails.message}` : ''; - alert(response.response.value + errorDetails); + status(response.response.value + errorDetails); } } From f4547a67b91bf720fefcdf801638aef7a94771d2 Mon Sep 17 00:00:00 2001 From: Michael Lively Date: Fri, 16 Jun 2023 11:34:07 -0700 Subject: [PATCH 53/69] Nb Workbench Toolbar -- separator fixes, test improvements (#185370) * fix: hidden items between separators -> 2x sep * improve testing: add extra separator case, add secondary actions --- .../viewParts/notebookEditorToolbar.ts | 3 ++ .../browser/notebookWorkbenchToolbar.test.ts | 52 ++++++++++++++----- 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorToolbar.ts b/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorToolbar.ts index b1404793190..b0a6bc62001 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorToolbar.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorToolbar.ts @@ -1132,6 +1132,9 @@ export function workbenchCalculateActions(initialPrimaryActions: IActionModel[], if (itemSize !== 0) { nonZeroAction = true; } + if (actionModel.action instanceof Separator) { + nonZeroAction = false; + } } else { containerFull = true; if (itemSize === 0) { // size 0 implies a hidden item, keep in primary to allow for Workbench to handle visibility diff --git a/src/vs/workbench/contrib/notebook/test/browser/notebookWorkbenchToolbar.test.ts b/src/vs/workbench/contrib/notebook/test/browser/notebookWorkbenchToolbar.test.ts index 4faad5f11c5..4df6550371b 100644 --- a/src/vs/workbench/contrib/notebook/test/browser/notebookWorkbenchToolbar.test.ts +++ b/src/vs/workbench/contrib/notebook/test/browser/notebookWorkbenchToolbar.test.ts @@ -25,6 +25,16 @@ interface IActionModel { * ex: action with size 50 requires 58px of space */ suite('workbenchCalculateActions', () => { + + const defaultSecondaryActionModels: IActionModel[] = [ + { action: new Action('secondaryAction0', 'Secondary Action 0'), size: 50, visible: true, renderLabel: true }, + { action: new Action('secondaryAction1', 'Secondary Action 1'), size: 50, visible: true, renderLabel: true }, + { action: new Action('secondaryAction2', 'Secondary Action 2'), size: 50, visible: true, renderLabel: true }, + ]; + const defaultSecondaryActions: IAction[] = defaultSecondaryActionModels.map(action => action.action); + const separator: IActionModel = { action: new Separator(), size: 1, visible: true, renderLabel: true }; + + test('should return empty primary and secondary actions when given empty initial actions', () => { const result = workbenchCalculateActions([], [], 100); assert.deepEqual(result.primaryActions, []); @@ -37,20 +47,20 @@ suite('workbenchCalculateActions', () => { { action: new Action('action1', 'Action 1'), size: 50, visible: true, renderLabel: true }, { action: new Action('action2', 'Action 2'), size: 50, visible: true, renderLabel: true }, ]; - const result = workbenchCalculateActions(actions, [], 200); + const result = workbenchCalculateActions(actions, defaultSecondaryActions, 200); assert.deepEqual(result.primaryActions, actions.map(action => action.action)); - assert.deepEqual(result.secondaryActions, []); + assert.deepEqual(result.secondaryActions, defaultSecondaryActions); }); - test.skip('should move actions to secondary when they do not fit within the container width', () => { + test('should move actions to secondary when they do not fit within the container width', () => { const actions: IActionModel[] = [ { action: new Action('action0', 'Action 0'), size: 50, visible: true, renderLabel: true }, { action: new Action('action1', 'Action 1'), size: 50, visible: true, renderLabel: true }, { action: new Action('action2', 'Action 2'), size: 50, visible: true, renderLabel: true }, ]; - const result = workbenchCalculateActions(actions, [], 100); + const result = workbenchCalculateActions(actions, defaultSecondaryActions, 100); assert.deepEqual(result.primaryActions, [actions[0]].map(action => action.action)); - assert.deepEqual(result.secondaryActions, [actions[1], actions[2]].map(action => action.action)); + assert.deepEqual(result.secondaryActions, [actions[1], actions[2], separator, ...defaultSecondaryActionModels].map(action => action.action)); }); test('should ignore second separator when two separators are in a row', () => { @@ -60,9 +70,9 @@ suite('workbenchCalculateActions', () => { { action: new Separator(), size: 1, visible: true, renderLabel: true }, { action: new Action('action1', 'Action 1'), size: 50, visible: true, renderLabel: true }, ]; - const result = workbenchCalculateActions(actions, [], 125); + const result = workbenchCalculateActions(actions, defaultSecondaryActions, 125); assert.deepEqual(result.primaryActions, [actions[0], actions[1], actions[3]].map(action => action.action)); - assert.deepEqual(result.secondaryActions, []); + assert.deepEqual(result.secondaryActions, defaultSecondaryActions); }); test('should ignore separators when they are at the end of the resulting primary actions', () => { @@ -72,21 +82,21 @@ suite('workbenchCalculateActions', () => { { action: new Action('action1', 'Action 1'), size: 50, visible: true, renderLabel: true }, { action: new Separator(), size: 1, visible: true, renderLabel: true }, ]; - const result = workbenchCalculateActions(actions, [], 200); + const result = workbenchCalculateActions(actions, defaultSecondaryActions, 200); assert.deepEqual(result.primaryActions, [actions[0], actions[1], actions[2]].map(action => action.action)); - assert.deepEqual(result.secondaryActions, []); + assert.deepEqual(result.secondaryActions, defaultSecondaryActions); }); - test.skip('should keep actions with size 0 in primary actions', () => { + test('should keep actions with size 0 in primary actions', () => { const actions: IActionModel[] = [ { action: new Action('action0', 'Action 0'), size: 50, visible: true, renderLabel: true }, { action: new Action('action1', 'Action 1'), size: 50, visible: true, renderLabel: true }, { action: new Action('action2', 'Action 2'), size: 50, visible: true, renderLabel: true }, { action: new Action('action3', 'Action 3'), size: 0, visible: true, renderLabel: true }, ]; - const result = workbenchCalculateActions(actions, [], 116); + const result = workbenchCalculateActions(actions, defaultSecondaryActions, 116); assert.deepEqual(result.primaryActions, [actions[0], actions[1], actions[3]].map(action => action.action)); - assert.deepEqual(result.secondaryActions, [actions[2]].map(action => action.action)); + assert.deepEqual(result.secondaryActions, [actions[2], separator, ...defaultSecondaryActionModels].map(action => action.action)); }); test('should not render separator if preceeded by size 0 action(s).', () => { @@ -95,8 +105,22 @@ suite('workbenchCalculateActions', () => { { action: new Separator(), size: 1, visible: true, renderLabel: true }, { action: new Action('action1', 'Action 1'), size: 50, visible: true, renderLabel: true }, ]; - const result = workbenchCalculateActions(actions, [], 116); + const result = workbenchCalculateActions(actions, defaultSecondaryActions, 116); assert.deepEqual(result.primaryActions, [actions[0], actions[2]].map(action => action.action)); - assert.deepEqual(result.secondaryActions, []); + assert.deepEqual(result.secondaryActions, defaultSecondaryActions); + }); + + test('should not render second separator if space between is hidden (size 0) actions.', () => { + const actions: IActionModel[] = [ + { action: new Action('action0', 'Action 0'), size: 50, visible: true, renderLabel: true }, + { action: new Separator(), size: 1, visible: true, renderLabel: true }, + { action: new Action('action1', 'Action 1'), size: 0, visible: true, renderLabel: true }, + { action: new Action('action2', 'Action 2'), size: 0, visible: true, renderLabel: true }, + { action: new Separator(), size: 1, visible: true, renderLabel: true }, + { action: new Action('action3', 'Action 3'), size: 50, visible: true, renderLabel: true }, + ]; + const result = workbenchCalculateActions(actions, defaultSecondaryActions, 300); + assert.deepEqual(result.primaryActions, [actions[0], actions[1], actions[2], actions[3], actions[5]].map(action => action.action)); + assert.deepEqual(result.secondaryActions, defaultSecondaryActions); }); }); From a0a662c8fdc8110edbd41bc45dce7bc157e3d259 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Sat, 17 Jun 2023 03:40:20 +0900 Subject: [PATCH 54/69] testing: add configuration to show all test messages. (#185197) * Add configuration to show all test messages. Introduce `testing.showAllMessages` configuration, which defaults to true. When false, only the first message is shown, and the rest are ignored. When true, the most recent message for each line is shown from all past test runs. * Change from Map -> Set. --- .../testing/browser/testingDecorations.ts | 89 ++++++++++--------- .../contrib/testing/common/configuration.ts | 9 +- 2 files changed, 55 insertions(+), 43 deletions(-) diff --git a/src/vs/workbench/contrib/testing/browser/testingDecorations.ts b/src/vs/workbench/contrib/testing/browser/testingDecorations.ts index e12d5881f36..aa47d25f78b 100644 --- a/src/vs/workbench/contrib/testing/browser/testingDecorations.ts +++ b/src/vs/workbench/contrib/testing/browser/testingDecorations.ts @@ -44,7 +44,7 @@ import { DefaultGutterClickAction, TestingConfigKeys, getTestingConfiguration } import { Testing, labelForTestInState } from 'vs/workbench/contrib/testing/common/constants'; import { TestId } from 'vs/workbench/contrib/testing/common/testId'; import { ITestProfileService } from 'vs/workbench/contrib/testing/common/testProfileService'; -import { LiveTestResult } from 'vs/workbench/contrib/testing/common/testResult'; +import { ITestResult, LiveTestResult } from 'vs/workbench/contrib/testing/common/testResult'; import { ITestResultService } from 'vs/workbench/contrib/testing/common/testResultService'; import { ITestService, getContextForTestItem, testsInFile } from 'vs/workbench/contrib/testing/common/testService'; import { IRichLocation, ITestMessage, ITestRunProfile, IncrementalTestCollectionItem, InternalTestItem, TestDiffOpType, TestMessageType, TestResultItem, TestResultState, TestRunProfileBitset } from 'vs/workbench/contrib/testing/common/testTypes'; @@ -318,47 +318,11 @@ export class TestingDecorationService extends Disposable implements ITestingDeco } } - const lastResult = this.results.results[0]; - if (this.testService.showInlineOutput.value && lastResult instanceof LiveTestResult) { - for (const task of lastResult.tasks) { - for (const m of task.otherMessages) { - if (!this.invalidatedMessages.has(m) && m.location?.uri.toString() === uriStr) { - const decoration = lastDecorations.getMessage(m) || this.instantiationService.createInstance(TestMessageDecoration, m, undefined, model); - newDecorations.addMessage(decoration); - } - } - } - - const messageLines = new Map(); - for (const test of lastResult.tests) { - for (let taskId = 0; taskId < test.tasks.length; taskId++) { - const state = test.tasks[taskId]; - for (let i = 0; i < state.messages.length; i++) { - const m = state.messages[i]; - if (this.invalidatedMessages.has(m) || m.location?.uri.toString() !== uriStr) { - continue; - } - - // Only add one message per line number. Overlapping messages - // don't appear well, and the peek will show all of them (#134129) - const line = m.location.range.startLineNumber; - if (messageLines.has(line)) { - newDecorations.removeMessage(messageLines.get(line)!); - } - - const decoration = lastDecorations.getMessage(m) || this.instantiationService.createInstance(TestMessageDecoration, m, buildTestUri({ - type: TestUriType.ResultActualOutput, - messageIndex: i, - taskIndex: taskId, - resultId: lastResult.id, - testExtId: test.item.extId, - }), model); - - newDecorations.addMessage(decoration); - messageLines.set(line, decoration.testMessage); - } - } - } + const messageLines = new Set(); + if (getTestingConfiguration(this.configurationService, TestingConfigKeys.ShowAllMessages)) { + this.results.results.forEach(lastResult => this.applyDecorationsFromResult(lastResult, messageLines, uriStr, lastDecorations, model, newDecorations)); + } else { + this.applyDecorationsFromResult(this.results.results[0], messageLines, uriStr, lastDecorations, model, newDecorations); } const saveFromRemoval = new Set(); @@ -387,6 +351,47 @@ export class TestingDecorationService extends Disposable implements ITestingDeco return newDecorations || lastDecorations; } + + private applyDecorationsFromResult(lastResult: ITestResult, messageLines: Set, uriStr: string, lastDecorations: CachedDecorations, model: ITextModel, newDecorations: CachedDecorations) { + if (this.testService.showInlineOutput.value && lastResult instanceof LiveTestResult) { + for (const task of lastResult.tasks) { + for (const m of task.otherMessages) { + if (!this.invalidatedMessages.has(m) && m.location?.uri.toString() === uriStr) { + const decoration = lastDecorations.getMessage(m) || this.instantiationService.createInstance(TestMessageDecoration, m, undefined, model); + newDecorations.addMessage(decoration); + } + } + } + + for (const test of lastResult.tests) { + for (let taskId = 0; taskId < test.tasks.length; taskId++) { + const state = test.tasks[taskId]; + for (let i = 0; i < state.messages.length; i++) { + const m = state.messages[i]; + if (this.invalidatedMessages.has(m) || m.location?.uri.toString() !== uriStr) { + continue; + } + + // Only add one message per line number. Overlapping messages + // don't appear well, and the peek will show all of them (#134129) + const line = m.location.range.startLineNumber; + if (!messageLines.has(line)) { + const decoration = lastDecorations.getMessage(m) || this.instantiationService.createInstance(TestMessageDecoration, m, buildTestUri({ + type: TestUriType.ResultActualOutput, + messageIndex: i, + taskIndex: taskId, + resultId: lastResult.id, + testExtId: test.item.extId, + }), model); + + newDecorations.addMessage(decoration); + messageLines.add(line); + } + } + } + } + } + } } export class TestingDecorations extends Disposable implements IEditorContribution { diff --git a/src/vs/workbench/contrib/testing/common/configuration.ts b/src/vs/workbench/contrib/testing/common/configuration.ts index fef2b0bd173..8ab51e92ec8 100644 --- a/src/vs/workbench/contrib/testing/common/configuration.ts +++ b/src/vs/workbench/contrib/testing/common/configuration.ts @@ -17,7 +17,8 @@ export const enum TestingConfigKeys { GutterEnabled = 'testing.gutterEnabled', SaveBeforeTest = 'testing.saveBeforeTest', AlwaysRevealTestOnStateChange = 'testing.alwaysRevealTestOnStateChange', - CountBadge = 'testing.countBadge' + CountBadge = 'testing.countBadge', + ShowAllMessages = 'testing.showAllMessages', } export const enum AutoOpenTesting { @@ -71,6 +72,11 @@ export const testingConfiguration: IConfigurationNode = { localize('testing.automaticallyOpenPeekView.never', "Never automatically open."), ], }, + [TestingConfigKeys.ShowAllMessages]: { + description: localize('testing.showAllMessages', "Controls whether to show messages from all test runs."), + type: 'boolean', + default: true, + }, [TestingConfigKeys.AutoOpenPeekViewDuringContinuousRun]: { description: localize('testing.automaticallyOpenPeekViewDuringContinuousRun', "Controls whether to automatically open the Peek view during continuous run mode."), type: 'boolean', @@ -154,6 +160,7 @@ export interface ITestingConfiguration { [TestingConfigKeys.SaveBeforeTest]: boolean; [TestingConfigKeys.OpenTesting]: AutoOpenTesting; [TestingConfigKeys.AlwaysRevealTestOnStateChange]: boolean; + [TestingConfigKeys.ShowAllMessages]: boolean; } export const getTestingConfiguration = (config: IConfigurationService, key: K) => config.getValue(key); From 3804adfd96c96e9b8c1e02da5f8300d41d109afd Mon Sep 17 00:00:00 2001 From: aamunger Date: Fri, 16 Jun 2023 11:40:29 -0700 Subject: [PATCH 55/69] set notebook widget to visible when focusing the IW Editor --- .../contrib/interactive/browser/interactiveEditor.ts | 1 + .../contrib/notebook/browser/notebookEditorWidget.ts | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/vs/workbench/contrib/interactive/browser/interactiveEditor.ts b/src/vs/workbench/contrib/interactive/browser/interactiveEditor.ts index faf374d8746..64715c9f5cd 100644 --- a/src/vs/workbench/contrib/interactive/browser/interactiveEditor.ts +++ b/src/vs/workbench/contrib/interactive/browser/interactiveEditor.ts @@ -670,6 +670,7 @@ export class InteractiveEditor extends EditorPane { } override focus() { + this.#notebookWidget.value?.show(); this.#codeEditorWidget.focus(); } diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 237532de8d0..56ac2e2977d 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -1913,6 +1913,10 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD } } + show() { + this._isVisible = true; + } + private focusEditor(activeElement: CellViewModel): void { for (const [element, editor] of this._renderedEditors.entries()) { if (element === activeElement) { From 797fd9c6e74ef72680aee777bb71e7ad3078dac1 Mon Sep 17 00:00:00 2001 From: aamunger Date: Fri, 16 Jun 2023 11:44:36 -0700 Subject: [PATCH 56/69] change function name --- .../workbench/contrib/interactive/browser/interactiveEditor.ts | 2 +- .../workbench/contrib/notebook/browser/notebookEditorWidget.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/interactive/browser/interactiveEditor.ts b/src/vs/workbench/contrib/interactive/browser/interactiveEditor.ts index 64715c9f5cd..c151e660fe4 100644 --- a/src/vs/workbench/contrib/interactive/browser/interactiveEditor.ts +++ b/src/vs/workbench/contrib/interactive/browser/interactiveEditor.ts @@ -670,7 +670,7 @@ export class InteractiveEditor extends EditorPane { } override focus() { - this.#notebookWidget.value?.show(); + this.#notebookWidget.value?.onShow(); this.#codeEditorWidget.focus(); } diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 56ac2e2977d..e45dc8e343c 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -1913,7 +1913,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD } } - show() { + onShow() { this._isVisible = true; } From 6dd5f94c82434e8e8e2dbddedfaf2f8b812f5ad3 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Fri, 16 Jun 2023 14:02:01 -0500 Subject: [PATCH 57/69] part of #185371 --- .../quickAccess/browser/editorNavigationQuickAccess.ts | 4 ++-- .../contrib/codeEditor/browser/find/simpleFindWidget.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/editor/contrib/quickAccess/browser/editorNavigationQuickAccess.ts b/src/vs/editor/contrib/quickAccess/browser/editorNavigationQuickAccess.ts index 98d97438d14..4336914a3ce 100644 --- a/src/vs/editor/contrib/quickAccess/browser/editorNavigationQuickAccess.ts +++ b/src/vs/editor/contrib/quickAccess/browser/editorNavigationQuickAccess.ts @@ -16,7 +16,7 @@ import { overviewRulerRangeHighlight } from 'vs/editor/common/core/editorColorRe import { IQuickAccessProvider } from 'vs/platform/quickinput/common/quickAccess'; import { IKeyMods, IQuickPick, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; import { themeColorFromId } from 'vs/platform/theme/common/themeService'; -import { alert } from 'vs/base/browser/ui/aria/aria'; +import { status } from 'vs/base/browser/ui/aria/aria'; interface IEditorLineDecoration { readonly rangeHighlightId: string; @@ -149,7 +149,7 @@ export abstract class AbstractEditorNavigationQuickAccessProvider implements IQu } const model = editor.getModel(); if (model && 'getLineContent' in model) { - alert(`${model.getLineContent(options.range.startLineNumber)}`); + status(`${model.getLineContent(options.range.startLineNumber)}`); } } diff --git a/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.ts b/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.ts index bf463408a20..c402fb22a42 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.ts @@ -21,7 +21,7 @@ import * as strings from 'vs/base/common/strings'; import { TerminalCommandId } from 'vs/workbench/contrib/terminal/common/terminal'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { showHistoryKeybindingHint } from 'vs/platform/history/browser/historyWidgetKeybindingHint'; -import { alert as alertFn } from 'vs/base/browser/ui/aria/aria'; +import { status } from 'vs/base/browser/ui/aria/aria'; import { defaultInputBoxStyles, defaultToggleStyles } from 'vs/platform/theme/browser/defaultStyles'; const NLS_FIND_INPUT_LABEL = nls.localize('label.find', "Find"); @@ -374,7 +374,7 @@ export abstract class SimpleFindWidget extends Widget { } else { label = NLS_NO_RESULTS; } - alertFn(this._announceSearchResults(label, this.inputValue)); + status(this._announceSearchResults(label, this.inputValue)); this._matchesCount.appendChild(document.createTextNode(label)); this._foundMatch = !!count && count.resultCount > 0; this.updateButtons(this._foundMatch); From 8bd63725e0fcda90347fbfdd281ecc8db40e31ae Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 16 Jun 2023 12:31:14 -0700 Subject: [PATCH 58/69] Correct pty host logging function name --- src/vs/platform/terminal/node/ptyService.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/terminal/node/ptyService.ts b/src/vs/platform/terminal/node/ptyService.ts index 3819f7741df..54468f5862c 100644 --- a/src/vs/platform/terminal/node/ptyService.ts +++ b/src/vs/platform/terminal/node/ptyService.ts @@ -51,14 +51,14 @@ export function traceRpc(_target: any, key: string, descriptor: any) { descriptor[fnKey!] = async function (...args: any[]) { if (this.traceRpcArgs.logService.getLevel() === LogLevel.Trace) { - this.traceRpcArgs.logService.trace(`[RPC Request] PtyService#${fnKey}(${args.map(e => JSON.stringify(e)).join(', ')})`); + this.traceRpcArgs.logService.trace(`[RPC Request] PtyService#${fn!.name}(${args.map(e => JSON.stringify(e)).join(', ')})`); } if (this.traceRpcArgs.simulatedLatency) { await timeout(this.traceRpcArgs.simulatedLatency); } const result = await fn!.apply(this, args); if (this.traceRpcArgs.logService.getLevel() === LogLevel.Trace) { - this.traceRpcArgs.logService.trace(`[RPC Response] PtyService#${fnKey}`, result); + this.traceRpcArgs.logService.trace(`[RPC Response] PtyService#${fn!.name}`, result); } return result; }; From e4751e3538869c6f4edc5591444164f4d5ec8c88 Mon Sep 17 00:00:00 2001 From: Raymond Zhao <7199958+rzhao271@users.noreply.github.com> Date: Fri, 16 Jun 2023 12:38:37 -0700 Subject: [PATCH 59/69] Fix some terms (#185376) * Fix some terms * Apply PR suggestion --- extensions/fsharp/syntaxes/fsharp.tmLanguage.json | 8 ++++---- extensions/latex/syntaxes/LaTeX.tmLanguage.json | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/extensions/fsharp/syntaxes/fsharp.tmLanguage.json b/extensions/fsharp/syntaxes/fsharp.tmLanguage.json index 0b67638d450..9cb2fc14012 100644 --- a/extensions/fsharp/syntaxes/fsharp.tmLanguage.json +++ b/extensions/fsharp/syntaxes/fsharp.tmLanguage.json @@ -314,7 +314,7 @@ }, { "match": "(?!when|and|or\\b)\\b([\\w0-9'`^._]+)", - "comments": "Here we need the \\w modifier in order to check that the words isn't blacklisted", + "comments": "Here we need the \\w modifier in order to check that the words are allowed", "captures": { "1": { "name": "entity.name.type.fsharp" @@ -677,7 +677,7 @@ }, { "match": "(?!with|get|set\\b)\\b([\\w0-9'`^._]+)", - "comments": "Here we need the \\w modifier in order to check that the words isn't blacklisted", + "comments": "Here we need the \\w modifier in order to check that the words are allowed", "captures": { "1": { "name": "entity.name.type.fsharp" @@ -1658,7 +1658,7 @@ }, { "match": "([\\w0-9'`^._]+)", - "comments": "Here we need the \\w modifier in order to check that the words isn't blacklisted", + "comments": "Here we need the \\w modifier in order to check that the words are allowed", "captures": { "1": { "name": "entity.name.type.fsharp" @@ -1832,4 +1832,4 @@ ] } } -} \ No newline at end of file +} diff --git a/extensions/latex/syntaxes/LaTeX.tmLanguage.json b/extensions/latex/syntaxes/LaTeX.tmLanguage.json index 3955e47cb8d..6c2de88ec05 100644 --- a/extensions/latex/syntaxes/LaTeX.tmLanguage.json +++ b/extensions/latex/syntaxes/LaTeX.tmLanguage.json @@ -102,7 +102,7 @@ "name": "punctuation.definition.arguments.begin.latex" } }, - "comment": "this works OK with all kinds of crazy stuff as long as section is one line", + "comment": "this works OK with all kinds of stuff as long as the section is one line", "contentName": "entity.name.section.latex", "end": "\\}", "endCaptures": { @@ -2371,4 +2371,4 @@ ] } } -} \ No newline at end of file +} From 95e90d22ec5f0465c63abdc023c88b8b8e31f0b3 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Fri, 16 Jun 2023 12:31:04 -0700 Subject: [PATCH 60/69] cli: log startup and shutdown, don't clear service logs on restart Fixes #183696 --- cli/src/commands/tunnels.rs | 12 +++++++++++- cli/src/log.rs | 14 +++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/cli/src/commands/tunnels.rs b/cli/src/commands/tunnels.rs index 3f29ee7020e..d11c15ef1e3 100644 --- a/cli/src/commands/tunnels.rs +++ b/cli/src/commands/tunnels.rs @@ -345,6 +345,13 @@ async fn serve_with_csa( log = log.tee(log_broadcast.clone()); log::install_global_logger(log.clone()); // re-install so that library logs are captured + debug!( + log, + "Starting tunnel with `{} {}`", + APPLICATION_NAME, + std::env::args().collect::>().join(" ") + ); + // Intentionally read before starting the server. If the server updated and // respawn is requested, the old binary will get renamed, and then // current_exe will point to the wrong path. @@ -435,7 +442,10 @@ async fn serve_with_csa( return Ok(exit.code().unwrap_or(1)); } - Next::Exit => return Ok(0), + Next::Exit => { + debug!(log, "Tunnel shut down"); + return Ok(0); + } Next::Restart => continue, } } diff --git a/cli/src/log.rs b/cli/src/log.rs index 1cd908c4b6c..a7561a37f6c 100644 --- a/cli/src/log.rs +++ b/cli/src/log.rs @@ -159,9 +159,21 @@ pub struct FileLogSink { file: Arc>, } +const FILE_LOG_SIZE_LIMIT: u64 = 1024 * 1024 * 10; // 10MB + impl FileLogSink { pub fn new(level: Level, path: &Path) -> std::io::Result { - let file = std::fs::File::create(path)?; + // Truncate the service log occasionally to avoid growing infinitely + if matches!(path.metadata(), Ok(m) if m.len() > FILE_LOG_SIZE_LIMIT) { + // ignore errors, can happen if another process is writing right now + let _ = std::fs::remove_file(path); + } + + let file = std::fs::OpenOptions::new() + .append(true) + .create(true) + .open(path)?; + Ok(Self { level, file: Arc::new(std::sync::Mutex::new(file)), From 7ee813703ac68cc4fca333cd4ffead2d6dc64b22 Mon Sep 17 00:00:00 2001 From: Raymond Zhao <7199958+rzhao271@users.noreply.github.com> Date: Fri, 16 Jun 2023 13:08:33 -0700 Subject: [PATCH 61/69] Add a11y settings in getSimpleEditorOptions (#184623) * Add a11y settings in getSimpleEditorOptions * Forgot a file * Fix AccessibleView * Rebase and fix merge conflict * Apply suggestion --- .../contrib/accessibility/browser/accessibleView.ts | 4 +--- src/vs/workbench/contrib/chat/browser/chatInputPart.ts | 2 +- .../workbench/contrib/chat/browser/chatListRenderer.ts | 2 +- .../contrib/codeEditor/browser/simpleEditorOptions.ts | 7 +++++-- .../browser/suggestEnabledInput/suggestEnabledInput.ts | 4 +--- .../workbench/contrib/debug/browser/breakpointWidget.ts | 2 +- src/vs/workbench/contrib/debug/browser/repl.ts | 5 +---- .../contrib/interactive/browser/interactiveEditor.ts | 2 +- src/vs/workbench/contrib/scm/browser/scmViewPane.ts | 9 ++------- .../accessibility/browser/terminalAccessibleWidget.ts | 4 +--- 10 files changed, 15 insertions(+), 26 deletions(-) diff --git a/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts b/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts index 8288b232880..1688aaa2d1d 100644 --- a/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts +++ b/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts @@ -60,7 +60,7 @@ class AccessibleView extends Disposable { contributions: EditorExtensionsRegistry.getSomeEditorContributions([LinkDetector.ID, SelectionClipboardContributionID, 'editor.contrib.selectionAnchorController']) }; const editorOptions: IEditorConstructionOptions = { - ...getSimpleEditorOptions(), + ...getSimpleEditorOptions(this._configurationService), lineDecorationsWidth: 6, dragAndDrop: true, cursorWidth: 1, @@ -70,8 +70,6 @@ class AccessibleView extends Disposable { quickSuggestions: false, renderWhitespace: 'none', dropIntoEditor: { enabled: true }, - accessibilitySupport: this._configurationService.getValue<'auto' | 'off' | 'on'>('editor.accessibilitySupport'), - cursorBlinking: this._configurationService.getValue('terminal.integrated.cursorBlinking'), readOnly: true }; this._editorWidget = this._register(this._instantiationService.createInstance(CodeEditorWidget, this._editorContainer, editorOptions, codeEditorWidgetOptions)); diff --git a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts index b7d1d8d7611..bcba9122486 100644 --- a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts @@ -190,7 +190,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge historyNavigationForwardsEnablement.set(enabled); }; - const options = getSimpleEditorOptions(); + const options = getSimpleEditorOptions(this.configurationService); options.readOnly = false; options.ariaLabel = this._getAriaLabel(); options.fontFamily = DEFAULT_FONT_FAMILY; diff --git a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts index e0d4b740cf5..2693e3adfb5 100644 --- a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts +++ b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts @@ -612,7 +612,7 @@ class CodeBlockPart extends Disposable implements IChatResultCodeBlockPart { })); const editorElement = dom.append(this.element, $('.interactive-result-editor')); this.editor = this._register(scopedInstantiationService.createInstance(CodeEditorWidget, editorElement, { - ...getSimpleEditorOptions(), + ...getSimpleEditorOptions(this.configurationService), readOnly: true, lineNumbers: 'off', selectOnLineNumbers: true, diff --git a/src/vs/workbench/contrib/codeEditor/browser/simpleEditorOptions.ts b/src/vs/workbench/contrib/codeEditor/browser/simpleEditorOptions.ts index 29d6921a6b0..6acfd4495b7 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/simpleEditorOptions.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/simpleEditorOptions.ts @@ -12,8 +12,9 @@ import { MenuPreventer } from 'vs/workbench/contrib/codeEditor/browser/menuPreve import { SelectionClipboardContributionID } from 'vs/workbench/contrib/codeEditor/browser/selectionClipboard'; import { TabCompletionController } from 'vs/workbench/contrib/snippets/browser/tabCompletion'; import { EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -export function getSimpleEditorOptions(): IEditorOptions { +export function getSimpleEditorOptions(configurationService: IConfigurationService): IEditorOptions { return { wordWrap: 'on', overviewRulerLanes: 0, @@ -39,7 +40,9 @@ export function getSimpleEditorOptions(): IEditorOptions { }, guides: { indentation: false - } + }, + accessibilitySupport: configurationService.getValue<'auto' | 'off' | 'on'>('editor.accessibilitySupport'), + cursorBlinking: configurationService.getValue<'blink' | 'smooth' | 'phase' | 'expand' | 'solid'>('editor.cursorBlinking') }; } diff --git a/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts b/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts index 9026bdbebc0..ddede253470 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts @@ -155,11 +155,9 @@ export class SuggestEnabledInput extends Widget { this.placeholderText = append(this.stylingContainer, $('.suggest-input-placeholder', undefined, options.placeholderText || '')); const editorOptions: IEditorConstructionOptions = mixin( - getSimpleEditorOptions(), + getSimpleEditorOptions(configurationService), getSuggestEnabledInputOptions(ariaLabel)); editorOptions.overflowWidgetsDomNode = options.overflowWidgetsDomNode; - editorOptions.accessibilitySupport = configurationService.getValue<'auto' | 'off' | 'on'>('editor.accessibilitySupport'); - editorOptions.cursorBlinking = configurationService.getValue<'blink' | 'smooth' | 'phase' | 'expand' | 'solid'>('editor.cursorBlinking'); const scopedContextKeyService = this.getScopedContextKeyService(contextKeyService); diff --git a/src/vs/workbench/contrib/debug/browser/breakpointWidget.ts b/src/vs/workbench/contrib/debug/browser/breakpointWidget.ts index ce99af8f16d..48fd41a505f 100644 --- a/src/vs/workbench/contrib/debug/browser/breakpointWidget.ts +++ b/src/vs/workbench/contrib/debug/browser/breakpointWidget.ts @@ -291,7 +291,7 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi private createEditorOptions(): IEditorOptions { const editorConfig = this._configurationService.getValue('editor'); - const options = getSimpleEditorOptions(); + const options = getSimpleEditorOptions(this._configurationService); options.fontSize = editorConfig.fontSize; options.fontFamily = editorConfig.fontFamily; options.lineHeight = editorConfig.lineHeight; diff --git a/src/vs/workbench/contrib/debug/browser/repl.ts b/src/vs/workbench/contrib/debug/browser/repl.ts index 19dc6cda053..f601bc21c89 100644 --- a/src/vs/workbench/contrib/debug/browser/repl.ts +++ b/src/vs/workbench/contrib/debug/browser/repl.ts @@ -649,15 +649,12 @@ export class Repl extends FilterViewPane implements IHistoryNavigationWidget { CONTEXT_IN_DEBUG_REPL.bindTo(this.scopedContextKeyService).set(true); this.scopedInstantiationService = this.instantiationService.createChild(new ServiceCollection([IContextKeyService, this.scopedContextKeyService])); - const options = getSimpleEditorOptions(); + const options = getSimpleEditorOptions(this.configurationService); options.readOnly = true; options.suggest = { showStatusBar: true }; const config = this.configurationService.getValue('debug'); options.acceptSuggestionOnEnter = config.console.acceptSuggestionOnEnter === 'on' ? 'on' : 'off'; options.ariaLabel = localize('debugConsole', "Debug Console"); - // We must respect some accessibility related settings - options.accessibilitySupport = this.configurationService.getValue<'auto' | 'off' | 'on'>('editor.accessibilitySupport'); - options.cursorBlinking = this.configurationService.getValue<'blink' | 'smooth' | 'phase' | 'expand' | 'solid'>('editor.cursorBlinking'); this.replInput = this.scopedInstantiationService.createInstance(CodeEditorWidget, this.replInputContainer, options, getSimpleCodeEditorWidgetOptions()); diff --git a/src/vs/workbench/contrib/interactive/browser/interactiveEditor.ts b/src/vs/workbench/contrib/interactive/browser/interactiveEditor.ts index c151e660fe4..29e8329ac80 100644 --- a/src/vs/workbench/contrib/interactive/browser/interactiveEditor.ts +++ b/src/vs/workbench/contrib/interactive/browser/interactiveEditor.ts @@ -276,7 +276,7 @@ export class InteractiveEditor extends EditorPane { overrideIdentifier = this.#codeEditorWidget.getModel()?.getLanguageId(); } const editorOptions = deepClone(this.#configurationService.getValue('editor', { overrideIdentifier })); - const editorOptionsOverride = getSimpleEditorOptions(); + const editorOptionsOverride = getSimpleEditorOptions(this.#configurationService); const computed = Object.freeze({ ...editorOptions, ...editorOptionsOverride, diff --git a/src/vs/workbench/contrib/scm/browser/scmViewPane.ts b/src/vs/workbench/contrib/scm/browser/scmViewPane.ts index bc33ef351cb..f6278a4d872 100644 --- a/src/vs/workbench/contrib/scm/browser/scmViewPane.ts +++ b/src/vs/workbench/contrib/scm/browser/scmViewPane.ts @@ -2005,9 +2005,6 @@ class SCMInputWidget { const fontFamily = this.getInputEditorFontFamily(); const fontSize = this.getInputEditorFontSize(); const lineHeight = this.computeLineHeight(fontSize); - // We must respect some accessibility related settings - const accessibilitySupport = this.configurationService.getValue<'auto' | 'off' | 'on'>('editor.accessibilitySupport'); - const cursorBlinking = this.configurationService.getValue<'blink' | 'smooth' | 'phase' | 'expand' | 'solid'>('editor.cursorBlinking'); this.setPlaceholderFontStyles(fontFamily, fontSize, lineHeight); @@ -2015,7 +2012,7 @@ class SCMInputWidget { this.repositoryIdContextKey = contextKeyService2.createKey('scmRepository', undefined); const editorOptions: IEditorConstructionOptions = { - ...getSimpleEditorOptions(), + ...getSimpleEditorOptions(configurationService), lineDecorationsWidth: 6, dragAndDrop: true, cursorWidth: 1, @@ -2029,9 +2026,7 @@ class SCMInputWidget { scrollbar: { alwaysConsumeMouseWheel: false }, overflowWidgetsDomNode, renderWhitespace: 'none', - dropIntoEditor: { enabled: true }, - accessibilitySupport, - cursorBlinking + dropIntoEditor: { enabled: true } }; const codeEditorWidgetOptions: ICodeEditorWidgetOptions = { diff --git a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibleWidget.ts b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibleWidget.ts index 013caf6e2fb..d1316db9bee 100644 --- a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibleWidget.ts +++ b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminalAccessibleWidget.ts @@ -66,7 +66,7 @@ export abstract class TerminalAccessibleWidget extends DisposableStore { }; const font = _xterm.getFont(); const editorOptions: IEditorConstructionOptions = { - ...getSimpleEditorOptions(), + ...getSimpleEditorOptions(this._configurationService), lineDecorationsWidth: 6, dragAndDrop: true, cursorWidth: 1, @@ -80,8 +80,6 @@ export abstract class TerminalAccessibleWidget extends DisposableStore { quickSuggestions: false, renderWhitespace: 'none', dropIntoEditor: { enabled: true }, - accessibilitySupport: this._configurationService.getValue<'auto' | 'off' | 'on'>('editor.accessibilitySupport'), - cursorBlinking: this._configurationService.getValue('terminal.integrated.cursorBlinking'), readOnly: true }; this._editorWidget = this.add(this._instantiationService.createInstance(CodeEditorWidget, this._editorContainer, editorOptions, codeEditorWidgetOptions)); From 8a006c7114b348568090c518c5f7d4fd14fffd8a Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Fri, 16 Jun 2023 14:01:07 -0700 Subject: [PATCH 62/69] cli: improve dbus error messaging on linux Fixes https://github.com/microsoft/vscode-remote-release/issues/7778 --- cli/src/tunnels/service_linux.rs | 8 ++++++-- cli/src/util/errors.rs | 23 ++++++++++++++++++++++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/cli/src/tunnels/service_linux.rs b/cli/src/tunnels/service_linux.rs index 3d1258a469a..b60d114dc46 100644 --- a/cli/src/tunnels/service_linux.rs +++ b/cli/src/tunnels/service_linux.rs @@ -17,7 +17,7 @@ use crate::{ constants::{APPLICATION_NAME, PRODUCT_NAME_LONG}, log, state::LauncherPaths, - util::errors::{wrap, AnyError}, + util::errors::{wrap, AnyError, DbusConnectFailedError}, }; use super::ServiceManager; @@ -40,7 +40,7 @@ impl SystemdService { async fn connect() -> Result { let connection = Connection::session() .await - .map_err(|e| wrap(e, "Error creating dbus session. This command uses systemd for managing services, you should check that systemd is installed and running as a user. If it's already installed, you may need to:\n\n- Install the `dbus-user-session` package and reboot\n- Start the user dbus session with `systemctl --user enable dbus --now`. \n\nThe error encountered was"))?; + .map_err(|e| DbusConnectFailedError(e.to_string()))?; Ok(connection) } @@ -110,6 +110,10 @@ impl ServiceManager for SystemdService { info!(self.log, "Tunnel service successfully started"); + if std::env::var("SSH_CLIENT").is_ok() || std::env::var("SSH_TTY").is_ok() { + info!(self.log, "Tip: run `sudo loginctl enable-linger $USER` to ensure the service stays running after you disconnect."); + } + Ok(()) } diff --git a/cli/src/util/errors.rs b/cli/src/util/errors.rs index f1c4cbf5c22..6f4630d0c54 100644 --- a/cli/src/util/errors.rs +++ b/cli/src/util/errors.rs @@ -442,6 +442,26 @@ macro_rules! makeAnyError { }; } +#[derive(Debug)] +pub struct DbusConnectFailedError(pub String); + +impl Display for DbusConnectFailedError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let mut str = String::new(); + str.push_str("Error creating dbus session. This command uses systemd for managing services, you should check that systemd is installed and under your user."); + + if std::env::var("WSL_DISTRO_NAME").is_ok() { + str.push_str("\n\nTo enable systemd on WSL, check out: https://devblogs.microsoft.com/commandline/systemd-support-is-now-available-in-wsl/.\n\n"); + } + + str.push_str("If running `systemctl status` works, systemd is ok, but your session dbus may not be. You might need to:\n\n- Install the `dbus-user-session` package, and reboot if it was not installed\n- Start the user dbus session with `systemctl --user enable dbus --now`.\n\nThe error encountered was: "); + str.push_str(&self.0); + str.push('\n'); + + write!(f, "{}", str) + } +} + /// Internal errors in the VS Code CLI. /// Note: other error should be migrated to this type gradually #[derive(Error, Debug)] @@ -522,7 +542,8 @@ makeAnyError!( MissingHomeDirectory, OAuthError, InvalidRpcDataError, - CodeError + CodeError, + DbusConnectFailedError ); impl From for AnyError { From 5de3dd34e83f2b252a8b5ed393c6c5526d5db782 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 16 Jun 2023 16:29:29 -0700 Subject: [PATCH 63/69] Allow vscode.open in chat markdown (#185386) --- src/vs/workbench/contrib/chat/browser/chatListRenderer.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts index 2693e3adfb5..d770a649f36 100644 --- a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts +++ b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts @@ -396,7 +396,11 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer markdown.value.startsWith(`/${s.command} `)); const toRender = usedSlashCommand ? markdown.value.slice(usedSlashCommand.command.length + 2) : markdown.value; - markdown = new MarkdownString(toRender); + markdown = new MarkdownString(toRender, { + isTrusted: { + enabledCommands: ['vscode.open'] + }, + }); const codeblocks: IChatCodeBlockInfo[] = []; const result = this.renderer.render(markdown, { From a4d4857ed6c1d479829ba9ede2dd54150c478eac Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Fri, 16 Jun 2023 17:01:36 -0700 Subject: [PATCH 64/69] Notify user once when Encryption isn't available (#185390) And point to troubleshooting doc. ref https://github.com/microsoft/vscode/issues/185212 --- src/vs/platform/secrets/common/secrets.ts | 31 +++++++++++++++++-- .../secrets/browser/secretStorageService.ts | 6 +++- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/vs/platform/secrets/common/secrets.ts b/src/vs/platform/secrets/common/secrets.ts index 815fb358e9e..e2b54212a82 100644 --- a/src/vs/platform/secrets/common/secrets.ts +++ b/src/vs/platform/secrets/common/secrets.ts @@ -5,10 +5,15 @@ import { SequencerByKey } from 'vs/base/common/async'; import { IEncryptionService } from 'vs/platform/encryption/common/encryptionService'; -import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService, createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IStorageService, InMemoryStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { Event, PauseableEmitter } from 'vs/base/common/event'; import { ILogService } from 'vs/platform/log/common/log'; +import { isNative } from 'vs/base/common/platform'; +import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; +import { localize } from 'vs/nls'; +import { IOpenerService } from 'vs/platform/opener/common/opener'; +import { once } from 'vs/base/common/functional'; export const ISecretStorageService = createDecorator('secretStorageService'); @@ -40,7 +45,9 @@ export class SecretStorageService implements ISecretStorageService { constructor( @IStorageService private _storageService: IStorageService, @IEncryptionService private _encryptionService: IEncryptionService, - @ILogService private readonly _logService: ILogService, + @IInstantiationService private readonly _instantiationService: IInstantiationService, + @INotificationService private readonly _notificationService: INotificationService, + @ILogService private readonly _logService: ILogService ) { this._storageService.onDidChangeValue(e => this.onDidChangeValue(e.key)); } @@ -89,6 +96,10 @@ export class SecretStorageService implements ISecretStorageService { return this._sequencer.queue(key, async () => { await this.initialized; + if (isNative && this.type !== 'persisted') { + this.notifyNativeUserOnce(); + } + const encrypted = await this._encryptionService.encrypt(value); const fullKey = this.getKey(key); try { @@ -129,4 +140,20 @@ export class SecretStorageService implements ISecretStorageService { private getKey(key: string): string { return `${this._storagePrefix}${key}`; } + + private notifyNativeUserOnce = once(() => this.notifyNativeUser()); + private notifyNativeUser(): void { + this._notificationService.prompt( + Severity.Warning, + localize('notEncrypted', 'Secrets are not being stored on disk because encryption is not available in this environment.'), + [{ + label: localize('openTroubleshooting', "Open Troubleshooting"), + run: () => this._instantiationService.invokeFunction(accessor => { + const openerService = accessor.get(IOpenerService); + // Open troubleshooting docs page + return openerService.open('https://go.microsoft.com/fwlink/?linkid=2239490'); + }) + }] + ); + } } diff --git a/src/vs/workbench/services/secrets/browser/secretStorageService.ts b/src/vs/workbench/services/secrets/browser/secretStorageService.ts index bdc68b1f4a1..e28cec9b7d6 100644 --- a/src/vs/workbench/services/secrets/browser/secretStorageService.ts +++ b/src/vs/workbench/services/secrets/browser/secretStorageService.ts @@ -5,7 +5,9 @@ import { IEncryptionService } from 'vs/platform/encryption/common/encryptionService'; import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; +import { INotificationService } from 'vs/platform/notification/common/notification'; import { ISecretStorageProvider, ISecretStorageService, SecretStorageService } from 'vs/platform/secrets/common/secrets'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { IBrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService'; @@ -18,9 +20,11 @@ export class BrowserSecretStorageService extends SecretStorageService { @IStorageService storageService: IStorageService, @IEncryptionService encryptionService: IEncryptionService, @IBrowserWorkbenchEnvironmentService environmentService: IBrowserWorkbenchEnvironmentService, + @IInstantiationService instantiationService: IInstantiationService, + @INotificationService notificationService: INotificationService, @ILogService logService: ILogService ) { - super(storageService, encryptionService, logService); + super(storageService, encryptionService, instantiationService, notificationService, logService); if (environmentService.options?.secretStorageProvider) { this._secretStorageProvider = environmentService.options.secretStorageProvider; From 2f867fa7a17d3020ae0ce46c6026054c3c0c7742 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Fri, 16 Jun 2023 17:38:58 -0700 Subject: [PATCH 65/69] cli: fix macos build (#185401) --- cli/src/util/zipper.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cli/src/util/zipper.rs b/cli/src/util/zipper.rs index 45dd3b7e85d..0e9939d4db5 100644 --- a/cli/src/util/zipper.rs +++ b/cli/src/util/zipper.rs @@ -88,7 +88,13 @@ where use std::io::Read; use std::os::unix::ffi::OsStringExt; - if matches!(file.unix_mode(), Some(mode) if mode & S_IFLNK == S_IFLNK) { + #[cfg(target_os = "macos")] + const S_IFLINK_32: u32 = S_IFLNK as u32; + + #[cfg(target_os = "linux")] + const S_IFLINK_32: u32 = S_IFLNK; + + if matches!(file.unix_mode(), Some(mode) if mode & S_IFLINK_32 == S_IFLINK_32) { let mut link_to = Vec::new(); file.read_to_end(&mut link_to).map_err(|e| { wrap( From e6de1b08224620383cb94e48a7ad32530ed7ee34 Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Fri, 16 Jun 2023 18:01:30 -0700 Subject: [PATCH 66/69] Miscellaneous NL Command Palette improvements (#185382) * Always show "Ask Copilot" * Open Quick Question UX instead of Chat view * If we have _any_ similar commands, show the "similar commands" separators even if there are no regular picks * Have Semantic Similarity setting be on by default * Remove QQ setting since it's not really useful --- .../quickinput/browser/commandsQuickAccess.ts | 5 +- .../browser/workbench.contribution.ts | 2 +- .../browser/actions/chatQuickInputActions.ts | 10 +- .../contrib/chat/browser/chat.contribution.ts | 6 -- .../browser/commandsQuickAccess.ts | 93 ++++++------------- .../browser/quickAccess.contribution.ts | 3 +- 6 files changed, 39 insertions(+), 80 deletions(-) diff --git a/src/vs/platform/quickinput/browser/commandsQuickAccess.ts b/src/vs/platform/quickinput/browser/commandsQuickAccess.ts index 05e07a1543d..97a5cb2ce5b 100644 --- a/src/vs/platform/quickinput/browser/commandsQuickAccess.ts +++ b/src/vs/platform/quickinput/browser/commandsQuickAccess.ts @@ -26,6 +26,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; export interface ICommandQuickPick extends IPickerQuickAccessItem { readonly commandId: string; readonly commandAlias?: string; + readonly args?: any[]; } export interface ICommandsQuickAccessOptions extends IPickerQuickAccessProviderOptions { @@ -211,7 +212,9 @@ export abstract class AbstractCommandsQuickAccessProvider extends PickerQuickAcc // Run try { - await this.commandService.executeCommand(commandPick.commandId); + commandPick.args?.length + ? await this.commandService.executeCommand(commandPick.commandId, ...commandPick.args) + : await this.commandService.executeCommand(commandPick.commandId); } catch (error) { if (!isCancellationError(error)) { this.dialogService.error(localize('canNotRun', "Command '{0}' resulted in an error", commandPick.label), toErrorMessage(error)); diff --git a/src/vs/workbench/browser/workbench.contribution.ts b/src/vs/workbench/browser/workbench.contribution.ts index f8d1715e921..35de24122ec 100644 --- a/src/vs/workbench/browser/workbench.contribution.ts +++ b/src/vs/workbench/browser/workbench.contribution.ts @@ -358,7 +358,7 @@ const registry = Registry.as(ConfigurationExtensions.Con 'type': 'boolean', tags: ['experimental'], 'description': localize('useSemanticSimilarity', "Controls whether the command palette should include similar commands. You must have an extension installed that provides Semantic Similarity."), - 'default': false + 'default': true }, 'workbench.quickOpen.closeOnFocusLost': { 'type': 'boolean', diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatQuickInputActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatQuickInputActions.ts index 0c583da7ee9..7691cf8fd9c 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatQuickInputActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatQuickInputActions.ts @@ -24,9 +24,10 @@ import { IChatReplyFollowup, IChatService } from 'vs/workbench/contrib/chat/comm import { ChatViewModel } from 'vs/workbench/contrib/chat/common/chatViewModel'; import { CHAT_CATEGORY } from 'vs/workbench/contrib/chat/browser/actions/chatActions'; import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat'; -import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { CONTEXT_PROVIDER_EXISTS } from 'vs/workbench/contrib/chat/common/chatContextKeys'; +export const ASK_QUICK_QUESTION_ACTION_ID = 'chat.action.askQuickQuestion'; + export function registerChatQuickQuestionActions() { registerAction2(AskQuickQuestionAction); } @@ -41,15 +42,14 @@ class AskQuickQuestionAction extends Action2 { constructor() { super({ - id: 'chat.action.askQuickQuestion', + id: ASK_QUICK_QUESTION_ACTION_ID, title: { value: localize('askQuickQuestion', "Ask Quick Question"), original: 'Ask Quick Question' }, precondition: CONTEXT_PROVIDER_EXISTS, - f1: true, + f1: false, category: CHAT_CATEGORY, keybinding: { weight: KeybindingWeight.WorkbenchContrib, - primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyI, - when: ContextKeyExpr.equals('config.chat.experimental.quickQuestion.enable', true), + primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyI } }); } diff --git a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts index af94c2c5c24..f0c600dcbd4 100644 --- a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts +++ b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts @@ -70,12 +70,6 @@ configurationRegistry.registerConfiguration({ type: 'number', description: nls.localize('interactiveSession.editor.lineHeight', "Controls the line height in pixels in chat codeblocks. Use 0 to compute the line height from the font size."), default: 0 - }, - 'chat.experimental.quickQuestion.enable': { - type: 'boolean', - description: nls.localize('interactiveSession.experimental.quickQuestion.enable', "Controls whether the quick question feature is enabled."), - default: false, - tags: ['experimental'] } } }); diff --git a/src/vs/workbench/contrib/quickaccess/browser/commandsQuickAccess.ts b/src/vs/workbench/contrib/quickaccess/browser/commandsQuickAccess.ts index 39fbc52fbdc..dd837a29ec7 100644 --- a/src/vs/workbench/contrib/quickaccess/browser/commandsQuickAccess.ts +++ b/src/vs/workbench/contrib/quickaccess/browser/commandsQuickAccess.ts @@ -35,8 +35,7 @@ import { isFirefox } from 'vs/base/browser/browser'; import { IProductService } from 'vs/platform/product/common/productService'; import { ISemanticSimilarityService } from 'vs/workbench/services/semanticSimilarity/common/semanticSimilarityService'; import { IChatService } from 'vs/workbench/contrib/chat/common/chatService'; -import { ILogService } from 'vs/platform/log/common/log'; -import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat'; +import { ASK_QUICK_QUESTION_ACTION_ID } from 'vs/workbench/contrib/chat/browser/actions/chatQuickInputActions'; export class CommandsQuickAccessProvider extends AbstractEditorCommandsQuickAccessProvider { @@ -80,19 +79,10 @@ export class CommandsQuickAccessProvider extends AbstractEditorCommandsQuickAcce ) { super({ showAlias: !Language.isDefaultVariant(), - noResultsPick: (filter) => { - const info = this.chatService.getProviderInfos()[0]; - return info - ? { - label: localize('askXInChat', "Ask {0}: {1}", info.displayName, filter), - commandId: AskInInteractiveAction.ID, - accept: () => commandService.executeCommand(AskInInteractiveAction.ID, filter) - } - : { - label: localize('noCommandResults', "No matching commands"), - commandId: '' - }; - }, + noResultsPick: () => ({ + label: localize('noCommandResults', "No matching commands"), + commandId: '' + }), }, instantiationService, keybindingService, commandService, telemetryService, dialogService); this._register(configurationService.onDidChangeConfiguration((e) => this.updateOptions(e))); @@ -175,12 +165,7 @@ export class CommandsQuickAccessProvider extends AbstractEditorCommandsQuickAcce const sortedIndices = scores.map((_, i) => i).sort((a, b) => scores[b] - scores[a]); const setOfPicksSoFar = new Set(picksSoFar.map(p => p.commandId)); - const additionalPicks: Array = picksSoFar.length > 0 - ? [{ - type: 'separator', - label: localize('semanticSimilarity', "similar commands") - }] - : []; + const additionalPicks = new Array(); let numOfSmartPicks = 0; for (const i of sortedIndices) { @@ -196,6 +181,28 @@ export class CommandsQuickAccessProvider extends AbstractEditorCommandsQuickAcce } } + if (numOfSmartPicks) { + additionalPicks.unshift({ + type: 'separator', + label: localize('semanticSimilarity', "similar commands") + }); + } + + if (picksSoFar.length || additionalPicks.length) { + additionalPicks.push({ + type: 'separator' + }); + } + + const info = this.chatService.getProviderInfos()[0]; + if (info) { + additionalPicks.push({ + label: localize('askXInChat', "Ask {0}: {1}", info.displayName, filter), + commandId: ASK_QUICK_QUESTION_ACTION_ID, + args: [filter] + }); + } + return additionalPicks; } @@ -299,48 +306,4 @@ export class ClearCommandHistoryAction extends Action2 { } } -// TODO: Should this live here? It seems fairly generic and could live in the interactive code. -export class AskInInteractiveAction extends Action2 { - - static readonly ID = 'workbench.action.askCommandInChat'; - - constructor() { - super({ - id: AskInInteractiveAction.ID, - title: { value: localize('askInChat', "Ask In Chat"), original: 'Ask In Chat' }, - f1: false - }); - } - - async run(accessor: ServicesAccessor, filter?: string): Promise { - const chatService = accessor.get(IChatService); - const chatWidgetService = accessor.get(IChatWidgetService); - const logService = accessor.get(ILogService); - - if (!filter) { - throw new Error('No filter provided.'); - } - - let providerId: string; - const providerInfos = chatService.getProviderInfos(); - switch (providerInfos.length) { - case 0: - throw new Error('No chat provider found.'); - case 1: - providerId = providerInfos[0].id; - break; - default: - logService.warn('Multiple chat providers found. Using the first one.'); - providerId = providerInfos[0].id; - break; - } - - const widget = await chatWidgetService.revealViewForProvider(providerId); - if (widget?.viewModel) { - // TODO: Maybe this could provide metadata saying it came from the command palette? - chatService.sendRequestToProvider(widget.viewModel.sessionId, { message: filter }); - } - } -} - //#endregion diff --git a/src/vs/workbench/contrib/quickaccess/browser/quickAccess.contribution.ts b/src/vs/workbench/contrib/quickaccess/browser/quickAccess.contribution.ts index 19795f4c5f0..85a5e04afd2 100644 --- a/src/vs/workbench/contrib/quickaccess/browser/quickAccess.contribution.ts +++ b/src/vs/workbench/contrib/quickaccess/browser/quickAccess.contribution.ts @@ -8,7 +8,7 @@ import { IQuickAccessRegistry, Extensions } from 'vs/platform/quickinput/common/ import { Registry } from 'vs/platform/registry/common/platform'; import { HelpQuickAccessProvider } from 'vs/platform/quickinput/browser/helpQuickAccess'; import { ViewQuickAccessProvider, OpenViewPickerAction, QuickAccessViewPickerAction } from 'vs/workbench/contrib/quickaccess/browser/viewQuickAccess'; -import { CommandsQuickAccessProvider, ShowAllCommandsAction, ClearCommandHistoryAction, AskInInteractiveAction } from 'vs/workbench/contrib/quickaccess/browser/commandsQuickAccess'; +import { CommandsQuickAccessProvider, ShowAllCommandsAction, ClearCommandHistoryAction } from 'vs/workbench/contrib/quickaccess/browser/commandsQuickAccess'; import { MenuRegistry, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; import { KeyMod } from 'vs/base/common/keyCodes'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; @@ -112,7 +112,6 @@ registerAction2(ClearCommandHistoryAction); registerAction2(ShowAllCommandsAction); registerAction2(OpenViewPickerAction); registerAction2(QuickAccessViewPickerAction); -registerAction2(AskInInteractiveAction); const inViewsPickerContextKey = 'inViewsPicker'; const inViewsPickerContext = ContextKeyExpr.and(inQuickPickContext, ContextKeyExpr.has(inViewsPickerContextKey)); From 8fb5ea014274354927f390a5c2cef2178ae8ff3d Mon Sep 17 00:00:00 2001 From: Robo Date: Sat, 17 Jun 2023 10:03:35 +0900 Subject: [PATCH 67/69] feat: use custom tag instead of custom version for MS electron releases (#181309) * feat: use custom tag instead of custom version for MS electron releases * chore: bump @vscode/gulp-electron * chore: move build id to .yarnrc * chore: rename enableUNCAccessChecks => restrictUNCAccess * chore: update electron@22.3.11 * chore: add build info to about dialog * chore: simplify helper function * chore: remove unused node.js checksums * chore: bump nodejs internal version * chore: bump distro * fix: revert changes to sign.ts * chore: bump distro --- .yarnrc | 3 ++- build/checksums/nodejs.txt | 27 ------------------- build/lib/electron.js | 8 +++--- build/lib/electron.ts | 7 +++-- build/lib/util.js | 7 ++--- build/lib/util.ts | 7 ++--- build/linux/debian/install-sysroot.js | 4 +-- build/linux/debian/install-sysroot.ts | 2 +- cgmanifest.json | 2 +- package.json | 6 ++--- remote/.yarnrc | 2 +- src/vs/base/node/unc.js | 4 +-- .../parts/dialogs/dialogHandler.ts | 3 ++- yarn.lock | 16 +++++------ 14 files changed, 40 insertions(+), 58 deletions(-) diff --git a/.yarnrc b/.yarnrc index 2e1d8081976..37b969922e9 100644 --- a/.yarnrc +++ b/.yarnrc @@ -1,4 +1,5 @@ disturl "https://electronjs.org/headers" -target "22.3.10" +target "22.3.11" +ms_build_id "21658788" runtime "electron" build_from_source "true" diff --git a/build/checksums/nodejs.txt b/build/checksums/nodejs.txt index edc1af90cd9..5229a5bc80a 100644 --- a/build/checksums/nodejs.txt +++ b/build/checksums/nodejs.txt @@ -1,34 +1,7 @@ -dfb37570ef34ac04f34c26d0ec558df60a9665df5961c01c1657c0ca495f2f01 node-v16.17.1-aix-ppc64.tar.gz f9f02f7872e2e8ee54320fce13deb9d56904f32bb0615b6e21aa3371d8899150 node-v16.17.1-darwin-arm64.tar.gz -09a45f60bfb9dfbea4f69044dc733ef983945acd92ca89ccccac267f3d71bd44 node-v16.17.1-darwin-arm64.tar.xz 3db26761ad8493b894d42260d7e65094b7af9bc473588739e61bc1c32d6ff955 node-v16.17.1-darwin-x64.tar.gz -8e7089956fa01cf7d0045945c0863d282dc6818fb0476237c1396497e29a4254 node-v16.17.1-darwin-x64.tar.xz -35ccb95caf02cda3bd680da4350a8ae5d666a7a9eae3afe5c2a1b3ef29aef108 node-v16.17.1-headers.tar.gz -554c8d1b4b16e0f4c073b9df7c49c893716a3a533f25ac646f23619f5ccee7df node-v16.17.1-headers.tar.xz adc7032888d4e672a4aac886baede8c04fccdd1a2e7ab4bcf325e3f336f44a3d node-v16.17.1-linux-arm64.tar.gz -3dfb8fd8f6b97df69cdc56524abc906c50ef1d0bf091188616802e6c7c731389 node-v16.17.1-linux-arm64.tar.xz aeab05e35f1d2824ecfb88ca321f1408b44d292b2775f2890972c828e00216d0 node-v16.17.1-linux-armv7l.tar.gz -a035ceefb5e16f5fce98c8ddfdf721b96eec20542c72fb8781bcbb6ef20c5550 node-v16.17.1-linux-armv7l.tar.xz -1f48de7bed99e973c4c50f1b7fc99fc9af5144d093fd6d2b50a1e43b5818bf05 node-v16.17.1-linux-ppc64le.tar.gz -70305934661f89fca64053b85317a75f233d5e3fdb2caa6546a19262a519cf20 node-v16.17.1-linux-ppc64le.tar.xz -029dad48018bda07b481213816549b632059fc673c30fdc7a353e04619128344 node-v16.17.1-linux-s390x.tar.gz -1a47f604944c6aff37cb7483503155671cdb34bda9bfb8962007bc440fa04d77 node-v16.17.1-linux-s390x.tar.xz da5658693243b3ecf6a4cba6751a71df1eb9e9703ca93b42a9404aed85f58ad0 node-v16.17.1-linux-x64.tar.gz -06ba2eb34aa385967f5f58c87a44753f83212f6cccea892b33f80a2e7fda8384 node-v16.17.1-linux-x64.tar.xz -12d10476ea7483298364c810c037b9316d1a73dc8c81cfeff7d794aecadde498 node-v16.17.1.pkg -e423985f6019b2026f9a191adb56a96ae83ecd56cdf839cf94aa980168b7a90f node-v16.17.1.tar.gz -6721feb4152d56d2c6b358ce397abd5a7f1daf09ee2e25c5021b9b4d3f86a330 node-v16.17.1.tar.xz -9777e8c4b2864c5b54a0e4e9400f14887db68560a09b94b4113b560a64d1e680 node-v16.17.1-win-x64.7z -ed290151efb417262b9808a70738d4ab79e9d53653a6a9f4b8dd97912e279dce node-v16.17.1-win-x64.zip -0f8101648d5c9e49e89fee541da9e574f899716c32b7c51a732b1766b9fc4526 node-v16.17.1-win-x86.7z -189b5e8b23226403e7b07a46614de19b444d369e694901e3668e2f549799cbcd node-v16.17.1-win-x86.zip -1bdff65fb7642425c0d6826084d63c4be43520316f0ea0b46e6a51999a0ed7fc node-v16.17.1-x64.msi -b737eb23a2c67c253b9364b5284123faf5220d567615bebd4ec4b81070e4d177 node-v16.17.1-x86.msi f518a70dcab7c3fac5b2e1ef100b4f628edfb160f4fafa9a94ef222da8a6e9ab win-x64/node.exe -2f459a64647db493da63c790ce368ad54f59f086d9f22f59c5018680420197b3 win-x64/node.lib -23215ce7d1e9de9777c3407239e7cf18d29d60f757b772219421ab361ac67c74 win-x64/node_pdb.7z -8e32ec12028fd3e3147435be79a858ed9c870aaafa1fcb291362307ef3c47547 win-x64/node_pdb.zip 2393aff88be19dbe0205cbde4ff0c1d89911b15de5c99c80f6e5e29604eecd12 win-x86/node.exe -5018c3d42f3fbacbd06cb943b3f2696c8e67ca9bdf6864d0e263d6d6911dffd2 win-x86/node.lib -05a4db56444a60ee70b0d2642d7f2d82a33339894d2d73bd07b1a41d6c869e04 win-x86/node_pdb.7z -8f86eacb7f13a1bf6738cb0819d7854a2abca40fc2e9e1f91421e44ba52cad7e win-x86/node_pdb.zip diff --git a/build/lib/electron.js b/build/lib/electron.js index 5cf792c491c..1af02cc9c30 100644 --- a/build/lib/electron.js +++ b/build/lib/electron.js @@ -75,8 +75,10 @@ function darwinBundleDocumentTypes(types, icon) { }; }); } +const { electronVersion, msBuildId } = util.getElectronVersion(); exports.config = { - version: product.electronRepository ? '22.5.7' : util.getElectronVersion(), + version: electronVersion, + tag: product.electronRepository ? `v${electronVersion}-${msBuildId}` : undefined, productAppName: product.nameLong, companyName: 'Microsoft Corporation', copyright: 'Copyright (C) 2023 Microsoft. All rights reserved', @@ -193,7 +195,7 @@ function getElectron(arch) { }; } async function main(arch = process.arch) { - const version = product.electronRepository ? '22.5.7' : util.getElectronVersion(); + const version = electronVersion; const electronPath = path.join(root, '.build', 'electron'); const versionFile = path.join(electronPath, 'version'); const isUpToDate = fs.existsSync(versionFile) && fs.readFileSync(versionFile, 'utf8') === `${version}`; @@ -208,4 +210,4 @@ if (require.main === module) { process.exit(1); }); } -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWxlY3Ryb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJlbGVjdHJvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7OztnR0FHZ0c7OztBQUVoRyx5QkFBeUI7QUFDekIsNkJBQTZCO0FBQzdCLGdDQUFnQztBQUNoQyxzQ0FBc0M7QUFDdEMsZ0NBQWdDO0FBQ2hDLCtCQUErQjtBQUMvQiw2Q0FBMEM7QUFZMUMsU0FBUyxnQkFBZ0IsQ0FBQyxHQUFZO0lBQ3JDLE9BQU8sR0FBRyxLQUFLLFVBQVUsSUFBSSxHQUFHLEtBQUssUUFBUSxJQUFJLEdBQUcsS0FBSyxNQUFNLElBQUksR0FBRyxLQUFLLGFBQWEsQ0FBQztBQUMxRixDQUFDO0FBRUQsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUM7QUFDbkQsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLGNBQWMsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUM7QUFDckYsTUFBTSxNQUFNLEdBQUcsSUFBQSx1QkFBVSxFQUFDLElBQUksQ0FBQyxDQUFDO0FBRWhDLE1BQU0scUJBQXFCLEdBQUcsT0FBTyxDQUFDLGFBQWEsSUFBSSxDQUFDLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsT0FBTyxDQUFDLGFBQWEsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUM7QUFFbkk7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWtCRztBQUNILFNBQVMsd0JBQXdCLENBQUMsVUFBb0IsRUFBRSxJQUFZLEVBQUUsWUFBNEMsRUFBRSxJQUFlO0lBQ2xJLDJGQUEyRjtJQUMzRixJQUFJLGdCQUFnQixDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsWUFB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 \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWxlY3Ryb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJlbGVjdHJvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7OztnR0FHZ0c7OztBQUVoRyx5QkFBeUI7QUFDekIsNkJBQTZCO0FBQzdCLGdDQUFnQztBQUNoQyxzQ0FBc0M7QUFDdEMsZ0NBQWdDO0FBQ2hDLCtCQUErQjtBQUMvQiw2Q0FBMEM7QUFZMUMsU0FBUyxnQkFBZ0IsQ0FBQyxHQUFZO0lBQ3JDLE9BQU8sR0FBRyxLQUFLLFVBQVUsSUFBSSxHQUFHLEtBQUssUUFBUSxJQUFJLEdBQUcsS0FBSyxNQUFNLElBQUksR0FBRyxLQUFLLGFBQWEsQ0FBQztBQUMxRixDQUFDO0FBRUQsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUM7QUFDbkQsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLGNBQWMsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUM7QUFDckYsTUFBTSxNQUFNLEdBQUcsSUFBQSx1QkFBVSxFQUFDLElBQUksQ0FBQyxDQUFDO0FBRWhDLE1BQU0scUJBQXFCLEdBQUcsT0FBTyxDQUFDLGFBQWEsSUFBSSxDQUFDLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsT0FBTyxDQUFDLGFBQWEsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUM7QUFFbkk7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWtCRztBQUNILFNBQVMsd0JBQXdCLENBQUMsVUFBb0IsRUFBRSxJQUFZLEVBQUUsWUFBNEMsRUFBRSxJQUFlO0lBQ2xJLDJGQUEyRjtJQUMzRixJQUFJLGdCQUFnQixDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsWUFB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 \ No newline at end of file diff --git a/build/lib/electron.ts b/build/lib/electron.ts index 1d11429e586..ea1c3c16086 100644 --- a/build/lib/electron.ts +++ b/build/lib/electron.ts @@ -90,8 +90,11 @@ function darwinBundleDocumentTypes(types: { [name: string]: string | string[] }, }); } +const { electronVersion, msBuildId } = util.getElectronVersion(); + export const config = { - version: product.electronRepository ? '22.5.7' : util.getElectronVersion(), + version: electronVersion, + tag: product.electronRepository ? `v${electronVersion}-${msBuildId}` : undefined, productAppName: product.nameLong, companyName: 'Microsoft Corporation', copyright: 'Copyright (C) 2023 Microsoft. All rights reserved', @@ -212,7 +215,7 @@ function getElectron(arch: string): () => NodeJS.ReadWriteStream { } async function main(arch = process.arch): Promise { - const version = product.electronRepository ? '22.5.7' : util.getElectronVersion(); + const version = electronVersion; const electronPath = path.join(root, '.build', 'electron'); const versionFile = path.join(electronPath, 'version'); const isUpToDate = fs.existsSync(versionFile) && fs.readFileSync(versionFile, 'utf8') === `${version}`; diff --git a/build/lib/util.js b/build/lib/util.js index 8bd8c1931e8..c6c45010223 100644 --- a/build/lib/util.js +++ b/build/lib/util.js @@ -314,8 +314,9 @@ function streamToPromise(stream) { exports.streamToPromise = streamToPromise; function getElectronVersion() { const yarnrc = fs.readFileSync(path.join(root, '.yarnrc'), 'utf8'); - const target = /^target "(.*)"$/m.exec(yarnrc)[1]; - return target; + const electronVersion = /^target "(.*)"$/m.exec(yarnrc)[1]; + const msBuildId = /^ms_build_id "(.*)"$/m.exec(yarnrc)[1]; + return { electronVersion, msBuildId }; } exports.getElectronVersion = getElectronVersion; function acquireWebNodePaths() { @@ -405,4 +406,4 @@ function buildWebNodePaths(outDir) { return result; } exports.buildWebNodePaths = buildWebNodePaths; -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInV0aWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Z0dBR2dHOzs7QUFFaEcsbUNBQW1DO0FBQ25DLHNDQUF1QztBQUN2Qyx1Q0FBdUM7QUFDdkMsc0NBQXNDO0FBQ3RDLDZCQUE2QjtBQUM3Qix5QkFBeUI7QUFDekIsa0NBQWtDO0FBQ2xDLG1DQUFtQztBQUduQyw2QkFBb0M7QUFDcEMsZ0RBQWdEO0FBRWhELE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDO0FBTW5ELE1BQU0sbUJBQW1CLEdBQXVCLEVBQUUsdUJBQXVCLEVBQUUsR0FBRyxFQUFFLENBQUMsS0FBSyxFQUFFLENBQUM7QUFNekYsU0FBZ0IsV0FBVyxDQUFDLGNBQStCLEVBQUUsT0FBK0IsRUFBRSxvQkFBOEI7SUFDM0gsTUFBTSxLQUFLLEdBQUcsRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQzNCLE1BQU0sTUFBTSxHQUFHLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQztJQUM1QixJQUFJLEtBQUssR0FBRyxNQUFNLENBQUM7SUFDbkIsSUFBSSxNQUFNLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUVqQyxNQUFNLEtBQUssR0FBbUMsQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUFFLHVCQUF1QixFQUFFLEdBQUcsRUFBRSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO0lBRXBKLE1BQU0sR0FBRyxHQUFHLENBQUMsS0FBNkIsRUFBRSxhQUFzQixFQUFFLEVBQUU7UUFDckUsS0FBSyxHQUFHLFNBQVMsQ0FBQztRQUVsQixNQUFNLE1BQU0sR0FBRyxDQUFDLG9CQUFvQixDQUFDLENB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 \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInV0aWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Z0dBR2dHOzs7QUFFaEcsbUNBQW1DO0FBQ25DLHNDQUF1QztBQUN2Qyx1Q0FBdUM7QUFDdkMsc0NBQXNDO0FBQ3RDLDZCQUE2QjtBQUM3Qix5QkFBeUI7QUFDekIsa0NBQWtDO0FBQ2xDLG1DQUFtQztBQUduQyw2QkFBb0M7QUFDcEMsZ0RBQWdEO0FBRWhELE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDO0FBTW5ELE1BQU0sbUJBQW1CLEdBQXVCLEVBQUUsdUJBQXVCLEVBQUUsR0FBRyxFQUFFLENBQUMsS0FBSyxFQUFFLENBQUM7QUFNekYsU0FBZ0IsV0FBVyxDQUFDLGNBQStCLEVBQUUsT0FBK0IsRUFBRSxvQkFBOEI7SUFDM0gsTUFBTSxLQUFLLEdBQUcsRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQzNCLE1BQU0sTUFBTSxHQUFHLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQztJQUM1QixJQUFJLEtBQUssR0FBRyxNQUFNLENBQUM7SUFDbkIsSUFBSSxNQUFNLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUVqQyxNQUFNLEtBQUssR0FBbUMsQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUFFLHVCQUF1QixFQUFFLEdBQUcsRUFBRSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO0lBRXBKLE1BQU0sR0FBRyxHQUFHLENBQUMsS0FBNkIsRUFBRSxhQUFzQixFQUFFLEVBQUU7UUFDckUsS0FBSyxHQUFHLFNBQVMsQ0FBQztRQUVsQixNQUFNLE1BQU0sR0FBRyxDQUFDLG9CQUFvQixDQUFDLENB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 \ No newline at end of file diff --git a/build/lib/util.ts b/build/lib/util.ts index 1a0edc582f2..b0f9c054997 100644 --- a/build/lib/util.ts +++ b/build/lib/util.ts @@ -384,10 +384,11 @@ export function streamToPromise(stream: NodeJS.ReadWriteStream): Promise { }); } -export function getElectronVersion(): string { +export function getElectronVersion(): Record { const yarnrc = fs.readFileSync(path.join(root, '.yarnrc'), 'utf8'); - const target = /^target "(.*)"$/m.exec(yarnrc)![1]; - return target; + const electronVersion = /^target "(.*)"$/m.exec(yarnrc)![1]; + const msBuildId = /^ms_build_id "(.*)"$/m.exec(yarnrc)![1]; + return { electronVersion, msBuildId }; } export function acquireWebNodePaths() { diff --git a/build/linux/debian/install-sysroot.js b/build/linux/debian/install-sysroot.js index f249ad032cb..0197f5f2571 100644 --- a/build/linux/debian/install-sysroot.js +++ b/build/linux/debian/install-sysroot.js @@ -30,7 +30,7 @@ function getSha(filename) { return hash.digest('hex'); } async function getSysroot(arch) { - const sysrootJSONUrl = `https://raw.githubusercontent.com/electron/electron/v${util.getElectronVersion()}/script/sysroots.json`; + const sysrootJSONUrl = `https://raw.githubusercontent.com/electron/electron/v${util.getElectronVersion().electronVersion}/script/sysroots.json`; const sysrootDictLocation = `${(0, os_1.tmpdir)()}/sysroots.json`; const result = (0, child_process_1.spawnSync)('curl', [sysrootJSONUrl, '-o', sysrootDictLocation]); if (result.status !== 0) { @@ -87,4 +87,4 @@ async function getSysroot(arch) { return sysroot; } exports.getSysroot = getSysroot; -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5zdGFsbC1zeXNyb290LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiaW5zdGFsbC1zeXNyb290LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7O2dHQUdnRzs7O0FBRWhHLGlEQUEwQztBQUMxQyxtQ0FBb0M7QUFDcEMsMkJBQTRCO0FBQzVCLHlCQUF5QjtBQUN6QiwrQkFBK0I7QUFDL0IsNkJBQTZCO0FBRTdCLHVDQUF1QztBQUV2QyxvSEFBb0g7QUFDcEgsTUFBTSxVQUFVLEdBQUcsNENBQTRDLENBQUM7QUFDaEUsTUFBTSxRQUFRLEdBQUcsb0JBQW9CLENBQUM7QUFFdEMsU0FBUyxNQUFNLENBQUMsUUFBcUI7SUFDcEMsTUFBTSxJQUFJLEdBQUcsSUFBQSxtQkFBVSxFQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ2hDLDJCQUEyQjtJQUMzQixNQUFNLEVBQUUsR0FBRyxFQUFFLENBQUMsUUFBUSxDQUFDLFFBQVEsRUFBRSxHQUFHLENBQUMsQ0FBQztJQUN0QyxNQUFNLE1BQU0sR0FBRyxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksR0FBRyxJQUFJLENBQUMsQ0FBQztJQUN6QyxJQUFJLFFBQVEsR0FBRyxDQUFDLENBQUM7SUFDakIsSUFBSSxTQUFTLEdBQUcsQ0FBQyxDQUFDO0lBQ2xCLE9BQU8sQ0FBQyxTQUFTLEdBQUcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxFQUFFLEVBQUUsTUFBTSxFQUFFLENBQUMsRUFBRSxNQUFNLENBQUMsTUFBTSxFQUFFLFFBQVEsQ0FBQyxDQUFDLEtBQUssTUFBTSxDQUFDLE1BQU0sRUFBRTtRQUMzRixJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3BCLFFBQVEsSUFBSSxTQUFTLENBQUM7S0FDdEI7SUFDRCxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLFNBQVMsQ0FBQyxDQUFDLENBQUM7SUFDeEMsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO0FBQzNCLENBQUM7QUFRTSxLQUFLLFVBQVUsVUFBVSxDQUFDLElBQXNCO0lBQ3RELE1BQU0sY0FBYyxHQUFHLHdEQUF3RCxJQUFJLENBQUMsa0JBQWtCLEVBQUUsdUJBQXVCLENBQUM7SUFDaEksTUFBTSxtQkFBbUIsR0FBRyxHQUFHLElBQUEsV0FBTSxHQUFFLGdCQUFnQixDQUFDO0lBQ3hELE1BQU0sTUFBTSxHQUFHLElBQUEseUJBQVMsRUFBQyxNQUFNLEVBQUUsQ0FBQyxjQUFjLEVBQUUsSUFBSSxFQUFFLG1CQUFtQixDQUFDLENBQUMsQ0FBQztJQUM5RSxJQUFJLE1BQU0sQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFO1FBQ3hCLE1BQU0sSUFBSSxLQUFLLENBQUMsMENBQTBDLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0tBQzVFO0lBQ0QsTUFBTSxXQUFXLEdBQUcsT0FBTyxDQUFDLG1CQUFtQixDQUFDLENBQUM7SUFDakQsTUFBTSxXQUFXLEdBQUcsSUFBSSxLQUFLLE9BQU8sQ0FBQyxDQUFDLENBQUMsY0FBYyxDQUFDLENBQUMsQ0FBQyxZQUFZLElBQUksRUFBRSxDQUFDO0lBQzNFLE1BQU0sV0FBVyxHQUFxQixXQUFXLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDL0QsTUFBTSxlQUFlLEdBQUcsV0FBVyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQy9DLE1BQU0sVUFBVSxHQUFHLFdBQVcsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUMxQyxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUEsV0FBTSxHQUFFLEVBQUUsV0FBVyxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUM7SUFDL0QsTUFBTSxHQUFHLEdBQUcsQ0FBQyxVQUFVLEVBQUUsUUFBUSxFQUFFLFVBQVUsRUFBRSxlQUFlLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDMUUsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFDM0MsSUFBSSxFQUFFLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLENBQUMsUUFBUSxFQUFFLEtBQUssR0FBRyxFQUFFO1FBQ3RFLE9BQU8sT0FBTyxDQUFDO0tBQ2Y7SUFFRCxPQUFPLENBQUMsR0FBRyxDQUFDLHFCQUFxQixJQUFJLGdCQUFnQixPQUFPLEVBQUUsQ0FBQyxDQUFDO0lBQ2hFLEVBQUUsQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUNyRCxFQUFFLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ3RCLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLGVBQWUsQ0FBQyxDQUFDO0lBQ3BELE9BQU8sQ0FBQyxHQUFHLENBQUMsZUFBZSxHQUFHLEVBQUUsQ0FBQyxDQUFDO0lBQ2xDLElBQUksZUFBZSxHQUFHLEtBQUssQ0FBQztJQUM1QixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsZUFBZSxFQUFFLENBQUMsRUFBRSxFQUFFO1FBQy9DLEVBQUUsQ0FBQyxhQUFhLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQzlCLE1BQU0sSUFBSSxPQUFPLENBQU8sQ0FBQyxDQUFDLEVBQUUsRUFBRTtZQUM3QixLQUFLLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDLEdBQUcsRUFBRSxFQUFFO2dCQUN0QixHQUFHLENBQUMsRUFBRSxDQUFDLE1BQU0sRUFBRSxDQUFDLEtBQUssRUFBRSxFQUFFO29CQUN4QixFQUFFLENBQUMsY0FBYyxDQUFDLE9BQU8sRUFBRSxLQUFLLENBQUMsQ0FBQztnQkFDbkMsQ0FBQyxDQUFDLENBQUM7Z0JBQ0gsR0FBRyxDQUFDLEVBQUUsQ0FBQyxLQUFLLEVBQUUsR0FBRyxFQUFFO29CQUNsQixlQUFlLEdBQUcsSUFBSSxDQUFDO29CQUN2QixDQUFDLEVBQUUsQ0FBQztnQkFDTCxDQUFDLENBQUMsQ0FBQztZQUNKLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxHQUFHLEVBQUUsRUFBRTtnQkFDdEIsT0FBTyxDQUFDLEtBQUssQ0FBQyxvREFBb0QsR0FBRyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7Z0JBQ2xGLENBQUMsRUFBRSxDQUFDO1lBQ0wsQ0FBQyxDQUFDLENBQUM7UUFDSixDQUFDLENBQUMsQ0FBQztLQUNIO0lBQ0QsSUFBSSxDQUFDLGVBQWUsRUFBRTtRQUNyQixFQUFFLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ25CLE1BQU0sSUFBSSxLQUFLLENBQUMscUJBQXFCLEdBQUcsR0FBRyxDQUFDLENBQUM7S0FDN0M7SUFDRCxNQUFNLEdBQUcsR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDNUIsSUFBSSxHQUFHLEtBQUssVUFBVSxFQUFFO1FBQ3ZCLE1BQU0sSUFBSSxLQUFLLENBQUMsc0NBQXNDLFVBQVUsWUFBWSxHQUFHLEVBQUUsQ0FBQyxDQUFDO0tBQ25GO0lBRUQsTUFBTSxJQUFJLEdBQUcsSUFBQSx5QkFBUyxFQUFDLEtBQUssRUFBRSxDQUFDLElBQUksRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUM7SUFDOUQsSUFBSSxJQUFJLENBQUMsTUFBTSxFQUFFO1FBQ2hCLE1BQU0sSUFBSSxLQUFLLENBQUMsc0NBQXNDLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0tBQ3RFO0lBQ0QsRUFBRSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUNuQixFQUFFLENBQUMsYUFBYSxDQUFDLEtBQUssRUFBRSxHQUFHLENBQUMsQ0FBQztJQUM3QixPQUFPLE9BQU8sQ0FBQztBQUNoQixDQUFDO0FBMURELGdDQTBEQyJ9 \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5zdGFsbC1zeXNyb290LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiaW5zdGFsbC1zeXNyb290LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7O2dHQUdnRzs7O0FBRWhHLGlEQUEwQztBQUMxQyxtQ0FBb0M7QUFDcEMsMkJBQTRCO0FBQzVCLHlCQUF5QjtBQUN6QiwrQkFBK0I7QUFDL0IsNkJBQTZCO0FBRTdCLHVDQUF1QztBQUV2QyxvSEFBb0g7QUFDcEgsTUFBTSxVQUFVLEdBQUcsNENBQTRDLENBQUM7QUFDaEUsTUFBTSxRQUFRLEdBQUcsb0JBQW9CLENBQUM7QUFFdEMsU0FBUyxNQUFNLENBQUMsUUFBcUI7SUFDcEMsTUFBTSxJQUFJLEdBQUcsSUFBQSxtQkFBVSxFQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ2hDLDJCQUEyQjtJQUMzQixNQUFNLEVBQUUsR0FBRyxFQUFFLENBQUMsUUFBUSxDQUFDLFFBQVEsRUFBRSxHQUFHLENBQUMsQ0FBQztJQUN0QyxNQUFNLE1BQU0sR0FBRyxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksR0FBRyxJQUFJLENBQUMsQ0FBQztJQUN6QyxJQUFJLFFBQVEsR0FBRyxDQUFDLENBQUM7SUFDakIsSUFBSSxTQUFTLEdBQUcsQ0FBQyxDQUFDO0lBQ2xCLE9BQU8sQ0FBQyxTQUFTLEdBQUcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxFQUFFLEVBQUUsTUFBTSxFQUFFLENBQUMsRUFBRSxNQUFNLENBQUMsTUFBTSxFQUFFLFFBQVEsQ0FBQyxDQUFDLEtBQUssTUFBTSxDQUFDLE1BQU0sRUFBRTtRQUMzRixJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3BCLFFBQVEsSUFBSSxTQUFTLENBQUM7S0FDdEI7SUFDRCxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLFNBQVMsQ0FBQyxDQUFDLENBQUM7SUFDeEMsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFD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 \ No newline at end of file diff --git a/build/linux/debian/install-sysroot.ts b/build/linux/debian/install-sysroot.ts index ac9de5b8578..49eb4a67127 100644 --- a/build/linux/debian/install-sysroot.ts +++ b/build/linux/debian/install-sysroot.ts @@ -38,7 +38,7 @@ type SysrootDictEntry = { }; export async function getSysroot(arch: DebianArchString): Promise { - const sysrootJSONUrl = `https://raw.githubusercontent.com/electron/electron/v${util.getElectronVersion()}/script/sysroots.json`; + const sysrootJSONUrl = `https://raw.githubusercontent.com/electron/electron/v${util.getElectronVersion().electronVersion}/script/sysroots.json`; const sysrootDictLocation = `${tmpdir()}/sysroots.json`; const result = spawnSync('curl', [sysrootJSONUrl, '-o', sysrootDictLocation]); if (result.status !== 0) { diff --git a/cgmanifest.json b/cgmanifest.json index 761741d5ec1..41afe464f7e 100644 --- a/cgmanifest.json +++ b/cgmanifest.json @@ -533,7 +533,7 @@ }, "isOnlyProductionDependency": true, "license": "MIT", - "version": "22.3.10" + "version": "22.3.11" }, { "component": { diff --git a/package.json b/package.json index ade6173707b..f1f8428adab 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.80.0", - "distro": "94a4bd29af2fe03e39c7867fdca1b2e27fed3a39", + "distro": "cbc1aeab0c196a6c6314cf4df21228d9016c70d1", "author": { "name": "Microsoft Corporation" }, @@ -132,7 +132,7 @@ "@typescript-eslint/eslint-plugin": "^5.57.0", "@typescript-eslint/experimental-utils": "^5.57.0", "@typescript-eslint/parser": "^5.57.0", - "@vscode/gulp-electron": "^1.34.0", + "@vscode/gulp-electron": "^1.35.0", "@vscode/l10n-dev": "0.0.21", "@vscode/telemetry-extractor": "^1.9.9", "@vscode/test-web": "^0.0.41", @@ -147,7 +147,7 @@ "cssnano": "^4.1.11", "debounce": "^1.0.0", "deemon": "^1.8.0", - "electron": "22.3.10", + "electron": "22.3.11", "eslint": "8.36.0", "eslint-plugin-header": "3.1.1", "eslint-plugin-jsdoc": "^39.3.2", diff --git a/remote/.yarnrc b/remote/.yarnrc index d714499d29d..9c86ae6bba4 100644 --- a/remote/.yarnrc +++ b/remote/.yarnrc @@ -1,5 +1,5 @@ disturl "http://nodejs.org/dist" target "16.17.1" -ms_build_id "20230714" +ms_build_id "218982" runtime "node" build_from_source "true" diff --git a/src/vs/base/node/unc.js b/src/vs/base/node/unc.js index 4e774d1114a..b0af4d38b68 100644 --- a/src/vs/base/node/unc.js +++ b/src/vs/base/node/unc.js @@ -114,7 +114,7 @@ return; } - process.enableUNCAccessChecks = false; + process.restrictUNCAccess = false; } function isUNCAccessRestrictionsDisabled() { @@ -122,7 +122,7 @@ return true; } - return process.enableUNCAccessChecks === false; + return process.restrictUNCAccess === false; } return { diff --git a/src/vs/workbench/electron-sandbox/parts/dialogs/dialogHandler.ts b/src/vs/workbench/electron-sandbox/parts/dialogs/dialogHandler.ts index 575bde3b87b..5df2e350a0e 100644 --- a/src/vs/workbench/electron-sandbox/parts/dialogs/dialogHandler.ts +++ b/src/vs/workbench/electron-sandbox/parts/dialogs/dialogHandler.ts @@ -78,11 +78,12 @@ export class NativeDialogHandler extends AbstractDialogHandler { const detailString = (useAgo: boolean): string => { return localize({ key: 'aboutDetail', comment: ['Electron, Chromium, Node.js and V8 are product names that need no translation'] }, - "Version: {0}\nCommit: {1}\nDate: {2}\nElectron: {3}\nChromium: {4}\nNode.js: {5}\nV8: {6}\nOS: {7}", + "Version: {0}\nCommit: {1}\nDate: {2}\nElectron: {3}\nElectronBuildId: {4}\nChromium: {5}\nNode.js: {6}\nV8: {7}\nOS: {8}", version, this.productService.commit || 'Unknown', this.productService.date ? `${this.productService.date}${useAgo ? ' (' + fromNow(new Date(this.productService.date), true) + ')' : ''}` : 'Unknown', process.versions['electron'], + process.versions['microsoft-build'], process.versions['chrome'], process.versions['node'], process.versions['v8'], diff --git a/yarn.lock b/yarn.lock index 8749297dd5c..cece00d0a16 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1240,10 +1240,10 @@ resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== -"@vscode/gulp-electron@^1.34.0": - version "1.34.0" - resolved "https://registry.yarnpkg.com/@vscode/gulp-electron/-/gulp-electron-1.34.0.tgz#59e00502e0a9703d1a0b7184dbd98ffe5125d2f4" - integrity sha512-zqLmueXYIqwgv0QhDdiDJOQYBYlCKE6Vu9KovMJ1ONZDrgb2CxUdaqxJRnROY18n6XO9RmNWodnplvSWkM+RVQ== +"@vscode/gulp-electron@^1.35.0": + version "1.35.0" + resolved "https://registry.yarnpkg.com/@vscode/gulp-electron/-/gulp-electron-1.35.0.tgz#b66aa307b1edefb0b37988faf29b82ab9974c466" + integrity sha512-FjRdAlfJBflFs28RYBaJ3gK/LHFZ4T34nP/FnKZrwNjWq5ojDC9WiwOMDHaG7wP7AKBcxh267Gz2epghMeO1ng== dependencies: "@electron/get" "^2.0.2" "@octokit/rest" "^18.0.14" @@ -3526,10 +3526,10 @@ electron-to-chromium@^1.4.202: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.207.tgz#9c3310ebace2952903d05dcaba8abe3a4ed44c01" integrity sha512-piH7MJDJp4rJCduWbVvmUd59AUne1AFBJ8JaRQvk0KzNTSUnZrVXHCZc+eg+CGE4OujkcLJznhGKD6tuAshj5Q== -electron@22.3.10: - version "22.3.10" - resolved "https://registry.yarnpkg.com/electron/-/electron-22.3.10.tgz#bf2b98fbb452f41b057ffcd4e57678e363f9735c" - integrity sha512-gh7PtSh+rfxHfM4dzPiEO+k1NRo07FvaK/jXG3HzuODrpTTEhC9rsE+AJGrTKQU6Nz7GorseMvnvs8PnUQPPTw== +electron@22.3.11: + version "22.3.11" + resolved "https://registry.yarnpkg.com/electron/-/electron-22.3.11.tgz#db68c3f820eab9868ccf65bd4604c2805c4c93b9" + integrity sha512-4PW1rJRUckJUCxTXRJkzJ7qlGTZ8Qfwoke5aFlaGccmn/zViuE9iSCg9zqIx00rzsbF9R5j8j9V4tAqyqjjJRA== dependencies: "@electron/get" "^2.0.0" "@types/node" "^16.11.26" From eb69cf5427c0d1350de11fc3e27160167cab6923 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 16 Jun 2023 19:08:40 -0700 Subject: [PATCH 68/69] Let chat view be wider (#185402) --- src/vs/workbench/contrib/chat/browser/chatWidget.ts | 2 +- src/vs/workbench/contrib/chat/browser/media/chat.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatWidget.ts b/src/vs/workbench/contrib/chat/browser/chatWidget.ts index 9c6cff1d7f6..8ed4825829d 100644 --- a/src/vs/workbench/contrib/chat/browser/chatWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/chatWidget.ts @@ -430,7 +430,7 @@ export class ChatWidget extends Disposable implements IChatWidget { } layout(height: number, width: number): void { - width = Math.min(width, 600); + width = Math.min(width, 850); this.bodyDimension = new dom.Dimension(width, height); const inputPartHeight = this.inputPart.layout(height, width); diff --git a/src/vs/workbench/contrib/chat/browser/media/chat.css b/src/vs/workbench/contrib/chat/browser/media/chat.css index 6796d8436a8..d156d968408 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chat.css +++ b/src/vs/workbench/contrib/chat/browser/media/chat.css @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ .interactive-session { - max-width: 600px; + max-width: 850px; margin: auto; } From 3b53204ad19491151643ff2ecf867ef101f40cc1 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Fri, 16 Jun 2023 19:58:02 -0700 Subject: [PATCH 69/69] testing: remove old test output terminal (#185405) Remove the old "test output terminal" stuff now that we use real terminals for showing output in the Test Results view. Move the "Show Output" buttons to reveal the Test Results view instead of opening the terminal. Closes https://github.com/microsoft/vscode/issues/151964 --- .../testing/browser/testExplorerActions.ts | 29 +- .../testing/browser/testing.contribution.ts | 22 +- .../testing/browser/testingOutputPeek.ts | 34 +- .../browser/testingOutputTerminalService.ts | 293 ------------------ 4 files changed, 31 insertions(+), 347 deletions(-) delete mode 100644 src/vs/workbench/contrib/testing/browser/testingOutputTerminalService.ts diff --git a/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts b/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts index bd2c7faf1fc..1e490d507e1 100644 --- a/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts +++ b/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts @@ -31,7 +31,7 @@ import { VIEWLET_ID as EXTENSIONS_VIEWLET_ID, IExtensionsViewPaneContainer } fro import { IActionableTestTreeElement, TestExplorerTreeElement, TestItemTreeElement } from 'vs/workbench/contrib/testing/browser/explorerProjections/index'; import * as icons from 'vs/workbench/contrib/testing/browser/icons'; import { TestingExplorerView } from 'vs/workbench/contrib/testing/browser/testingExplorerView'; -import { ITestingOutputTerminalService } from 'vs/workbench/contrib/testing/browser/testingOutputTerminalService'; +import { TestResultsView } from 'vs/workbench/contrib/testing/browser/testingOutputPeek'; import { TestingConfigKeys, getTestingConfiguration } from 'vs/workbench/contrib/testing/common/configuration'; import { TestCommandId, TestExplorerViewMode, TestExplorerViewSorting, Testing, testConfigurationGroupNames } from 'vs/workbench/contrib/testing/common/constants'; import { TestId } from 'vs/workbench/contrib/testing/common/testId'; @@ -840,30 +840,9 @@ export class ShowMostRecentOutputAction extends Action2 { } public async run(accessor: ServicesAccessor) { - const quickInputService = accessor.get(IQuickInputService); - const terminalOutputService = accessor.get(ITestingOutputTerminalService); - const result = accessor.get(ITestResultService).results[0]; - - if (!result.tasks.length) { - return; - } - - let index = 0; - if (result.tasks.length > 1) { - const picked = await quickInputService.pick( - result.tasks.map((t, i) => ({ label: t.name || localize('testing.pickTaskUnnamed', "Run #{0}", i), index: i })), - { placeHolder: localize('testing.pickTask', "Pick a run to show output for") } - ); - - if (!picked) { - return; - } - - index = picked.index; - } - - - terminalOutputService.open(result, index); + const viewService = accessor.get(IViewsService); + const testView = await viewService.openView(Testing.ResultsViewId, true); + testView?.showLatestRun(); } } diff --git a/src/vs/workbench/contrib/testing/browser/testing.contribution.ts b/src/vs/workbench/contrib/testing/browser/testing.contribution.ts index 5569b1fc9f6..73030bcd305 100644 --- a/src/vs/workbench/contrib/testing/browser/testing.contribution.ts +++ b/src/vs/workbench/contrib/testing/browser/testing.contribution.ts @@ -16,35 +16,34 @@ import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IProgressService } from 'vs/platform/progress/common/progress'; import { Registry } from 'vs/platform/registry/common/platform'; -import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; -import { Extensions as ViewContainerExtensions, IViewContainersRegistry, IViewsRegistry, IViewsService, ViewContainerLocation } from 'vs/workbench/common/views'; +import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer'; +import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; +import { IViewContainersRegistry, IViewsRegistry, IViewsService, Extensions as ViewContainerExtensions, ViewContainerLocation } from 'vs/workbench/common/views'; import { REVEAL_IN_EXPLORER_COMMAND_ID } from 'vs/workbench/contrib/files/browser/fileConstants'; import { testingResultsIcon, testingViewIcon } from 'vs/workbench/contrib/testing/browser/icons'; -import { TestingDecorations, TestingDecorationService } from 'vs/workbench/contrib/testing/browser/testingDecorations'; +import { TestingDecorationService, TestingDecorations } from 'vs/workbench/contrib/testing/browser/testingDecorations'; import { TestingExplorerView } from 'vs/workbench/contrib/testing/browser/testingExplorerView'; import { CloseTestPeek, GoToNextMessageAction, GoToPreviousMessageAction, OpenMessageInEditorAction, TestResultsView, TestingOutputPeekController, TestingPeekOpener, ToggleTestingPeekHistory } from 'vs/workbench/contrib/testing/browser/testingOutputPeek'; -import { ITestingOutputTerminalService, TestingOutputTerminalService } from 'vs/workbench/contrib/testing/browser/testingOutputTerminalService'; import { ITestingProgressUiService, TestingProgressTrigger, TestingProgressUiService } from 'vs/workbench/contrib/testing/browser/testingProgressUiService'; import { TestingViewPaneContainer } from 'vs/workbench/contrib/testing/browser/testingViewPaneContainer'; import { testingConfiguration } from 'vs/workbench/contrib/testing/common/configuration'; import { TestCommandId, Testing } from 'vs/workbench/contrib/testing/common/constants'; -import { ITestItem, TestRunProfileBitset } from 'vs/workbench/contrib/testing/common/testTypes'; import { ITestExplorerFilterState, TestExplorerFilterState } from 'vs/workbench/contrib/testing/common/testExplorerFilterState'; import { TestId, TestPosition } from 'vs/workbench/contrib/testing/common/testId'; -import { TestingContentProvider } from 'vs/workbench/contrib/testing/common/testingContentProvider'; -import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingContextKeys'; -import { ITestingDecorationsService } from 'vs/workbench/contrib/testing/common/testingDecorations'; -import { ITestingPeekOpener } from 'vs/workbench/contrib/testing/common/testingPeekOpener'; import { ITestProfileService, TestProfileService } from 'vs/workbench/contrib/testing/common/testProfileService'; import { ITestResultService, TestResultService } from 'vs/workbench/contrib/testing/common/testResultService'; import { ITestResultStorage, TestResultStorage } from 'vs/workbench/contrib/testing/common/testResultStorage'; import { ITestService } from 'vs/workbench/contrib/testing/common/testService'; import { TestService } from 'vs/workbench/contrib/testing/common/testServiceImpl'; +import { ITestItem, TestRunProfileBitset } from 'vs/workbench/contrib/testing/common/testTypes'; +import { TestingContentProvider } from 'vs/workbench/contrib/testing/common/testingContentProvider'; +import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingContextKeys'; +import { ITestingContinuousRunService, TestingContinuousRunService } from 'vs/workbench/contrib/testing/common/testingContinuousRunService'; +import { ITestingDecorationsService } from 'vs/workbench/contrib/testing/common/testingDecorations'; +import { ITestingPeekOpener } from 'vs/workbench/contrib/testing/common/testingPeekOpener'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { allTestActions, discoverAndRunTests } from './testExplorerActions'; import './testingConfigurationUi'; -import { ITestingContinuousRunService, TestingContinuousRunService } from 'vs/workbench/contrib/testing/common/testingContinuousRunService'; -import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer'; registerSingleton(ITestService, TestService, InstantiationType.Delayed); registerSingleton(ITestResultStorage, TestResultStorage, InstantiationType.Delayed); @@ -52,7 +51,6 @@ registerSingleton(ITestProfileService, TestProfileService, InstantiationType.Del registerSingleton(ITestingContinuousRunService, TestingContinuousRunService, InstantiationType.Delayed); registerSingleton(ITestResultService, TestResultService, InstantiationType.Delayed); registerSingleton(ITestExplorerFilterState, TestExplorerFilterState, InstantiationType.Delayed); -registerSingleton(ITestingOutputTerminalService, TestingOutputTerminalService, InstantiationType.Delayed); registerSingleton(ITestingPeekOpener, TestingPeekOpener, InstantiationType.Delayed); registerSingleton(ITestingProgressUiService, TestingProgressUiService, InstantiationType.Delayed); registerSingleton(ITestingDecorationsService, TestingDecorationService, InstantiationType.Delayed); diff --git a/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts b/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts index 5fc25be8ed2..4076b424ae6 100644 --- a/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts +++ b/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts @@ -75,7 +75,6 @@ import { TERMINAL_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/ import { flatTestItemDelimiter } from 'vs/workbench/contrib/testing/browser/explorerProjections/display'; import { getTestItemContextOverlay } from 'vs/workbench/contrib/testing/browser/explorerProjections/testItemContextOverlay'; import * as icons from 'vs/workbench/contrib/testing/browser/icons'; -import { ITestingOutputTerminalService } from 'vs/workbench/contrib/testing/browser/testingOutputTerminalService'; import { testingPeekBorder, testingPeekHeaderBackground } from 'vs/workbench/contrib/testing/browser/theme'; import { AutoOpenPeekViewWhen, TestingConfigKeys, getTestingConfiguration } from 'vs/workbench/contrib/testing/common/configuration'; import { Testing } from 'vs/workbench/contrib/testing/common/constants'; @@ -945,6 +944,18 @@ export class TestResultsView extends ViewPane { return this.content.current; } + public showLatestRun(preserveFocus = false) { + const result = this.resultService.results.find(r => r.tasks.length); + if (!result) { + return; + } + + this.content.reveal({ + preserveFocus, + subject: new TaskSubject(result.id, 0), + }); + } + protected override renderBody(container: HTMLElement): void { super.renderBody(container); this.content.fillBody(container); @@ -1517,7 +1528,7 @@ class OutputPeekTree extends Disposable { ) { super(); - this.treeActions = instantiationService.createInstance(TreeActionsProvider, options.showRevealLocationOnMessages); + this.treeActions = instantiationService.createInstance(TreeActionsProvider, options.showRevealLocationOnMessages, this.requestReveal,); const diffIdentityProvider: IIdentityProvider = { getId(e: TreeElement) { return e.id; @@ -1718,9 +1729,7 @@ class OutputPeekTree extends Disposable { })); this._register(this.tree.onDidOpen(async e => { - if (e.element instanceof TaskElement) { - this.requestReveal.fire(new TaskSubject(e.element.results.id, e.element.index)); - } else if (e.element instanceof TestMessageElement) { + if (e.element instanceof TestMessageElement) { this.requestReveal.fire(new MessageSubject(e.element.result.id, e.element.test, e.element.taskIndex, e.element.messageIndex)); } })); @@ -1852,8 +1861,8 @@ class TestRunElementRenderer implements ICompressibleTreeRenderer, @IContextKeyService private readonly contextKeyService: IContextKeyService, - @ITestingOutputTerminalService private readonly testTerminalService: ITestingOutputTerminalService, @IMenuService private readonly menuService: IMenuService, @ICommandService private readonly commandService: ICommandService, @ITestProfileService private readonly testProfileService: ITestProfileService, @@ -1880,7 +1889,7 @@ class TreeActionsProvider { localize('testing.showResultOutput', "Show Result Output"), ThemeIcon.asClassName(Codicon.terminal), undefined, - () => this.testTerminalService.open(element.results, element.index) + () => this.requestReveal.fire(new TaskSubject(element.results.id, element.index)), )); } @@ -1892,7 +1901,7 @@ class TreeActionsProvider { localize('testing.showResultOutput', "Show Result Output"), ThemeIcon.asClassName(Codicon.terminal), undefined, - () => this.testTerminalService.open(element.value, 0) + () => this.requestReveal.fire(new TaskSubject(element.value.id, 0)), )); } @@ -1970,15 +1979,6 @@ class TreeActionsProvider { }), )); } - if (element.marker !== undefined) { - primary.push(new Action( - 'testing.outputPeek.showMessageInTerminal', - localize('testing.showMessageInTerminal', "Show Output in Terminal"), - ThemeIcon.asClassName(Codicon.terminal), - undefined, - () => this.testTerminalService.open(element.result, element.taskIndex, element.marker), - )); - } } const result = { primary, secondary }; diff --git a/src/vs/workbench/contrib/testing/browser/testingOutputTerminalService.ts b/src/vs/workbench/contrib/testing/browser/testingOutputTerminalService.ts deleted file mode 100644 index 89bcc961b5e..00000000000 --- a/src/vs/workbench/contrib/testing/browser/testingOutputTerminalService.ts +++ /dev/null @@ -1,293 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { DeferredPromise } from 'vs/base/common/async'; -import { Emitter, Event } from 'vs/base/common/event'; -import { Disposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle'; -import { language } from 'vs/base/common/platform'; -import { isDefined } from 'vs/base/common/types'; -import { localize } from 'vs/nls'; -import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { IProcessDataEvent, IProcessPropertyMap, IProcessReadyEvent, IShellLaunchConfig, ITerminalChildProcess, ITerminalDimensionsOverride, ITerminalLaunchError, ProcessPropertyType, TerminalLocation, TerminalShellType } from 'vs/platform/terminal/common/terminal'; -import { IViewsService } from 'vs/workbench/common/views'; -import { ITerminalEditorService, ITerminalGroupService, ITerminalInstance, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; -import { TERMINAL_VIEW_ID } from 'vs/workbench/contrib/terminal/common/terminal'; -import { testingViewIcon } from 'vs/workbench/contrib/testing/browser/icons'; -import { ITestResult } from 'vs/workbench/contrib/testing/common/testResult'; -import { ITestResultService } from 'vs/workbench/contrib/testing/common/testResultService'; -import { getMarkId } from 'vs/workbench/contrib/testing/common/testTypes'; - - -export interface ITestingOutputTerminalService { - _serviceBrand: undefined; - - /** - * Opens a terminal for the given test's output. Optionally, scrolls to and - * selects the given marker in the test results. - */ - open(result: ITestResult, taskIndex: number, marker?: number): Promise; -} - -const friendlyDate = (date: number) => { - const d = new Date(date); - return d.getHours() + ':' + String(d.getMinutes()).padStart(2, '0') + ':' + String(d.getSeconds()).padStart(2, '0'); -}; - -const getTitle = (result: ITestResult | undefined, taskIndex: number | undefined) => { - if (!result || taskIndex === undefined) { - return genericTitle; - } - - const task = result.tasks[taskIndex]; - if (result.tasks.length < 2 || !task?.name) { - return localize('testOutputTerminalTitleWithDate', 'Test Output at {0}', friendlyDate(result.completedAt ?? Date.now())); - } - - return localize('testOutputTerminalTitleWithDateAndTaskName', '{0} at {1}', task.name, friendlyDate(result.completedAt ?? Date.now())); -}; - -const genericTitle = localize('testOutputTerminalTitle', 'Test Output'); - -export const ITestingOutputTerminalService = createDecorator('ITestingOutputTerminalService'); - -export class TestingOutputTerminalService implements ITestingOutputTerminalService { - _serviceBrand: undefined; - - private outputTerminals = new WeakMap(); - - constructor( - @ITerminalService private readonly terminalService: ITerminalService, - @ITerminalGroupService private readonly terminalGroupService: ITerminalGroupService, - @ITerminalEditorService private readonly terminalEditorService: ITerminalEditorService, - @ITestResultService resultService: ITestResultService, - @IViewsService private viewsService: IViewsService, - ) { - - const newTaskListener = new MutableDisposable(); - - // If a result terminal is currently active and we start a new test run, - // stream live results there automatically. - resultService.onResultsChanged(evt => { - if (!('started' in evt)) { - return; - } - - newTaskListener.value = evt.started.onNewTask(taskIndex => { - const active = this.terminalService.activeInstance; - if (!active) { - return; - } - - const pane = this.viewsService.getActiveViewWithId(TERMINAL_VIEW_ID); - if (!pane) { - return; - } - - const output = this.outputTerminals.get(active); - if (output && output.ended) { - this.showResultsInTerminal(active, output, evt.started, taskIndex); - } - }); - }); - } - - /** - * @inheritdoc - */ - public async open(result: ITestResult | undefined, taskIndex: number | undefined, marker?: number): Promise { - const testOutputPtys = this.terminalService.instances - .map(t => { - const output = this.outputTerminals.get(t); - return output ? [t, output] as const : undefined; - }) - .filter(isDefined); - - // If there's an existing terminal for the attempted reveal, show that instead. - const existing = testOutputPtys.find(([, o]) => o.resultId === result?.id && o.taskIndex === taskIndex); - if (existing) { - this.terminalService.setActiveInstance(existing[0]); - if (existing[0].target === TerminalLocation.Editor) { - this.terminalEditorService.revealActiveEditor(); - } else { - this.terminalGroupService.showPanel(); - } - - this.revealMarker(existing[0], marker); - return; - } - - // Try to reuse ended terminals, otherwise make a new one - const ended = testOutputPtys.find(([, o]) => o.ended); - if (ended) { - ended[1].clear(); - this.showResultsInTerminal(ended[0], ended[1], result, taskIndex); - return; - } - - const output = new TestOutputProcess(); - this.showResultsInTerminal(await this.terminalService.createTerminal({ - config: { - isFeatureTerminal: true, - icon: testingViewIcon, - customPtyImplementation: () => output, - name: getTitle(result, taskIndex), - }, - }), output, result, taskIndex, marker); - } - - private async showResultsInTerminal(terminal: ITerminalInstance, output: TestOutputProcess, result: ITestResult | undefined, taskIndex: number | undefined, thenSelectMarker?: number) { - this.outputTerminals.set(terminal, output); - const title = getTitle(result, taskIndex); - output.resetFor(result?.id, taskIndex, title); - terminal.rename(title); - - this.terminalService.setActiveInstance(terminal); - if (terminal.target === TerminalLocation.Editor) { - this.terminalEditorService.revealActiveEditor(); - } else { - this.terminalGroupService.showPanel(); - } - - await output.started; - - if (!result || taskIndex === undefined) { - // seems like it takes a tick for listeners to be registered - output.ended = true; - setTimeout(() => output.pushData(localize('testNoRunYet', '\r\nNo tests have been run, yet.\r\n'))); - return; - } - - - const testOutput = result.tasks[taskIndex].output; - - let hadData = false; - for (const d of testOutput.buffers) { - hadData = true; - output.pushData(d.toString()); - } - - const disposable = new DisposableStore(); - disposable.add(testOutput.onDidWriteData(d => { - hadData = true; - output.pushData(d.toString()); - })); - - testOutput.endPromise.then(() => { - if (disposable.isDisposed) { - return; - } - if (!hadData) { - output.pushData(`\x1b[2m${localize('runNoOutout', 'The test run did not record any output.')}\x1b[0m`); - } - - const completedAt = result.completedAt ? new Date(result.completedAt) : new Date(); - const text = localize('runFinished', 'Test run finished at {0}', completedAt.toLocaleString(language)); - output.pushData(`\r\n\r\n\x1b[1m> ${text} <\x1b[0m\r\n\r\n`); - output.ended = true; - this.revealMarker(terminal, thenSelectMarker); - disposable.dispose(); - }); - - disposable.add(terminal.onDisposed(() => { - disposable.dispose(); - })); - } - - private revealMarker(terminal: ITerminalInstance, marker?: number) { - if (marker !== undefined) { - terminal.scrollToMark(getMarkId(marker, true), getMarkId(marker, false), true); - } - } -} - -class TestOutputProcess extends Disposable implements ITerminalChildProcess { - onProcessOverrideDimensions?: Event | undefined; - onProcessResolvedShellLaunchConfig?: Event | undefined; - onDidChangeHasChildProcesses?: Event | undefined; - onDidChangeProperty = Event.None; - private processDataEmitter = this._register(new Emitter()); - private readonly startedDeferred = new DeferredPromise(); - /** Whether the associated test has ended (indicating the terminal can be reused) */ - public ended = true; - /** Result currently being displayed */ - public resultId: string | undefined; - /** Task currently being displayed */ - public taskIndex: number | undefined; - /** Promise resolved when the terminal is ready to take data */ - public readonly started = this.startedDeferred.p; - - public pushData(data: string | IProcessDataEvent) { - this.processDataEmitter.fire(data); - } - - public clear() { - this.processDataEmitter.fire('\x1bc'); - } - - public resetFor(resultId: string | undefined, taskIndex: number | undefined, title: string) { - this.ended = false; - this.resultId = resultId; - this.taskIndex = taskIndex; - } - - //#region implementation - public readonly id = 0; - public readonly shouldPersist = false; - - public readonly onProcessData = this.processDataEmitter.event; - public readonly onProcessExit = this._register(new Emitter()).event; - private readonly _onProcessReady = this._register(new Emitter()); - public readonly onProcessReady = this._onProcessReady.event; - public readonly onProcessShellTypeChanged = this._register(new Emitter()).event; - - public start(): Promise { - this.startedDeferred.complete(); - this._onProcessReady.fire({ pid: -1, cwd: '', windowsPty: undefined }); - return Promise.resolve(undefined); - } - public shutdown(): void { - // no-op - } - public input(): void { - // not supported - } - public processBinary(): Promise { - return Promise.resolve(); - } - public resize(): void { - // no-op - } - public clearBuffer(): void | Promise { - // no-op - } - public acknowledgeDataEvent(): void { - // no-op, flow control not currently implemented - } - public setUnicodeVersion(): Promise { - // no-op - return Promise.resolve(); - } - - public getInitialCwd(): Promise { - return Promise.resolve(''); - } - - public getCwd(): Promise { - return Promise.resolve(''); - } - - public getLatency(): Promise { - return Promise.resolve(0); - } - - public refreshProperty(property: ProcessPropertyType): Promise { - throw new Error(`refreshProperty is not suppported in TestOutputProcesses. property: ${property}`); - } - - public updateProperty(property: ProcessPropertyType, value: any): Promise { - throw new Error(`updateProperty is not suppported in TestOutputProcesses. property: ${property}, value: ${value}`); - } - //#endregion -}