Skip to content

Commit bcc4919

Browse files
committed
Disconnect the terminal widget when Gitpod Task exits, and update terminal widget tab when Gitpod Task title changes
1 parent 33c613c commit bcc4919

File tree

2 files changed

+112
-12
lines changed

2 files changed

+112
-12
lines changed

components/ide/jetbrains/backend-plugin/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ plugins {
1313
// Kotlin support - check the latest version at https://plugins.gradle.org/plugin/org.jetbrains.kotlin.jvm
1414
id("org.jetbrains.kotlin.jvm") version "1.7.0"
1515
// gradle-intellij-plugin - read more: https://github.com/JetBrains/gradle-intellij-plugin
16-
id("org.jetbrains.intellij") version "1.8.0"
16+
id("org.jetbrains.intellij") version "1.8.1"
1717
// detekt linter - read more: https://detekt.github.io/detekt/gradle.html
1818
id("io.gitlab.arturbosch.detekt") version "1.17.1"
1919
// ktlint linter - read more: https://github.com/JLLeitschuh/ktlint-gradle

components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/GitpodTerminalService.kt

Lines changed: 111 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,21 @@ package io.gitpod.jetbrains.remote
77
import com.intellij.openapi.client.ClientProjectSession
88
import com.intellij.openapi.diagnostic.thisLogger
99
import com.intellij.util.application
10+
import com.jediterm.terminal.ui.TerminalWidget
11+
import com.jediterm.terminal.ui.TerminalWidgetListener
1012
import com.jetbrains.rdserver.terminal.BackendTerminalManager
11-
import io.gitpod.jetbrains.remote.GitpodManager
1213
import io.gitpod.supervisor.api.Status
1314
import io.gitpod.supervisor.api.StatusServiceGrpc
1415
import io.gitpod.supervisor.api.TerminalOuterClass
1516
import io.gitpod.supervisor.api.TerminalServiceGrpc
17+
import io.grpc.StatusRuntimeException
1618
import io.grpc.stub.ClientCallStreamObserver
1719
import io.grpc.stub.ClientResponseObserver
1820
import org.jetbrains.plugins.terminal.ShellTerminalWidget
1921
import org.jetbrains.plugins.terminal.TerminalView
2022
import java.util.*
2123
import java.util.concurrent.CompletableFuture
24+
import java.util.concurrent.ExecutionException
2225
import java.util.concurrent.TimeUnit
2326

2427
@Suppress("UnstableApiUsage")
@@ -30,6 +33,7 @@ class GitpodTerminalService(session: ClientProjectSession) {
3033
private val terminalView = TerminalView.getInstance(session.project)
3134
private val backendTerminalManager = BackendTerminalManager.getInstance(session.project)
3235
private val terminalServiceFutureStub = TerminalServiceGrpc.newFutureStub(GitpodManager.supervisorChannel)
36+
private val terminalServiceStub = TerminalServiceGrpc.newStub(GitpodManager.supervisorChannel)
3337
private val statusServiceStub = StatusServiceGrpc.newStub(GitpodManager.supervisorChannel)
3438

3539
init { start() }
@@ -49,7 +53,7 @@ class GitpodTerminalService(session: ClientProjectSession) {
4953
}
5054
}
5155

52-
private fun createSharedTerminalAndExecuteCommand(title: String, command: String) {
56+
private fun createSharedTerminalAndExecuteCommand(title: String, command: String): ShellTerminalWidget? {
5357
val registeredTerminals = terminalView.widgets.toMutableList()
5458

5559
backendTerminalManager.createNewSharedTerminal(UUID.randomUUID().toString(), title)
@@ -59,8 +63,14 @@ class GitpodTerminalService(session: ClientProjectSession) {
5963

6064
widget.terminalTitle.change { applicationTitle = title }
6165

62-
(widget as ShellTerminalWidget).executeCommand(command)
66+
val shellTerminalWidget = widget as ShellTerminalWidget
67+
68+
shellTerminalWidget.executeCommand(command)
69+
70+
return shellTerminalWidget
6371
}
72+
73+
return null
6474
}
6575

6676
private fun createTerminalsAttachedToTasks(
@@ -120,8 +130,9 @@ class GitpodTerminalService(session: ClientProjectSession) {
120130
}
121131

122132
thisLogger().error(
123-
"gitpod: Got an error while trying to get tasks list from Supervisor. Trying again in on second.",
124-
throwable
133+
"gitpod: Got an error while trying to get tasks list from Supervisor. " +
134+
"Trying again in one second.",
135+
throwable
125136
)
126137
}
127138

@@ -150,8 +161,9 @@ class GitpodTerminalService(session: ClientProjectSession) {
150161
}
151162

152163
thisLogger().error(
153-
"gitpod: Got an error while trying to get terminals list from Supervisor. Trying again in on second.",
154-
throwable
164+
"gitpod: Got an error while trying to get terminals list from Supervisor. " +
165+
"Trying again in one second.",
166+
throwable
155167
)
156168
}
157169

@@ -164,9 +176,97 @@ class GitpodTerminalService(session: ClientProjectSession) {
164176
}
165177

166178
private fun createAttachedSharedTerminal(supervisorTerminal: TerminalOuterClass.Terminal) {
167-
createSharedTerminalAndExecuteCommand(
168-
supervisorTerminal.title,
169-
"gp tasks attach ${supervisorTerminal.alias}"
170-
)
179+
val shellTerminalWidget = createSharedTerminalAndExecuteCommand(
180+
supervisorTerminal.title,
181+
"gp tasks attach ${supervisorTerminal.alias}"
182+
) ?: return
183+
184+
exitTaskWhenTerminalWidgetGetsClosed(supervisorTerminal, shellTerminalWidget)
185+
186+
listenForTaskTerminationAndTitleChanges(supervisorTerminal, shellTerminalWidget)
187+
}
188+
189+
private fun listenForTaskTerminationAndTitleChanges(
190+
supervisorTerminal: TerminalOuterClass.Terminal,
191+
shellTerminalWidget: ShellTerminalWidget
192+
) = application.executeOnPooledThread {
193+
var hasOpenSessions = true
194+
195+
while (hasOpenSessions) {
196+
val completableFuture = CompletableFuture<Void>()
197+
198+
val listenTerminalRequest = TerminalOuterClass.ListenTerminalRequest.newBuilder()
199+
.setAlias(supervisorTerminal.alias)
200+
.build()
201+
202+
val listenTerminalResponseObserver =
203+
object : ClientResponseObserver<TerminalOuterClass.ListenTerminalRequest, TerminalOuterClass.ListenTerminalResponse> {
204+
override fun beforeStart(request: ClientCallStreamObserver<TerminalOuterClass.ListenTerminalRequest>) {
205+
@Suppress("ObjectLiteralToLambda")
206+
shellTerminalWidget.addListener(object : TerminalWidgetListener {
207+
override fun allSessionsClosed(widget: TerminalWidget) {
208+
hasOpenSessions = false
209+
request.cancel("gitpod: Terminal closed on the client.", null)
210+
}
211+
})
212+
}
213+
214+
override fun onNext(response: TerminalOuterClass.ListenTerminalResponse) {
215+
when {
216+
response.hasTitle() -> application.invokeLater {
217+
shellTerminalWidget.terminalTitle.change {
218+
applicationTitle = response.title
219+
}
220+
}
221+
222+
response.hasExitCode() -> application.invokeLater {
223+
shellTerminalWidget.close()
224+
}
225+
}
226+
}
227+
228+
override fun onCompleted() = Unit
229+
230+
override fun onError(throwable: Throwable) {
231+
completableFuture.completeExceptionally(throwable)
232+
}
233+
}
234+
235+
terminalServiceStub.listen(listenTerminalRequest, listenTerminalResponseObserver)
236+
237+
try {
238+
completableFuture.get()
239+
} catch (throwable: Throwable) {
240+
if (throwable is StatusRuntimeException || throwable is ExecutionException || throwable is InterruptedException) {
241+
shellTerminalWidget.close()
242+
thisLogger()
243+
.info("gitpod: Stopped listening to " +
244+
"'${supervisorTerminal.title}' terminal due via an expected exception.", throwable)
245+
break
246+
}
247+
248+
thisLogger()
249+
.error("gitpod: Got an error while listening to " +
250+
"'${supervisorTerminal.title}' terminal. Trying again in one second.", throwable)
251+
}
252+
253+
TimeUnit.SECONDS.sleep(1)
254+
}
255+
}
256+
257+
private fun exitTaskWhenTerminalWidgetGetsClosed(
258+
supervisorTerminal: TerminalOuterClass.Terminal,
259+
shellTerminalWidget: ShellTerminalWidget
260+
) {
261+
@Suppress("ObjectLiteralToLambda")
262+
shellTerminalWidget.addListener(object : TerminalWidgetListener {
263+
override fun allSessionsClosed(widget: TerminalWidget) {
264+
terminalServiceFutureStub.shutdown(
265+
TerminalOuterClass.ShutdownTerminalRequest.newBuilder()
266+
.setAlias(supervisorTerminal.alias)
267+
.build()
268+
)
269+
}
270+
})
171271
}
172272
}

0 commit comments

Comments
 (0)