Skip to content

Commit

Permalink
[ide] Initialize a shared terminal on JetBrains IDEs when a workspace…
Browse files Browse the repository at this point in the history
… starts
  • Loading branch information
felladrin committed Apr 21, 2022
1 parent beb02b6 commit cec497b
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 1 deletion.
2 changes: 1 addition & 1 deletion components/ide/jetbrains/backend-plugin/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ platformVersion=221.4994-EAP-CANDIDATE-SNAPSHOT
platformDownloadSources=true
# Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html
# Example: platformPlugins = com.intellij.java, com.jetbrains.php:203.4449.22
platformPlugins=Git4Idea
platformPlugins=Git4Idea, org.jetbrains.plugins.terminal, com.jetbrains.codeWithMe
# Opt-out flag for bundling Kotlin standard library.
# See https://plugins.jetbrains.com/docs/intellij/kotlin.html#kotlin-standard-library for details.
kotlin.stdlib.default.dependency=false
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Copyright (c) 2022 Gitpod GmbH. All rights reserved.
// Licensed under the GNU Affero General Public License (AGPL).
// See License-AGPL.txt in the project root for license information.

package io.gitpod.jetbrains.remote

import com.intellij.openapi.Disposable
import com.intellij.openapi.application.runInEdt
import com.intellij.openapi.project.Project
import com.intellij.openapi.wm.ToolWindowManager
import com.intellij.openapi.wm.ex.ToolWindowManagerListener
import com.intellij.util.application
import com.jetbrains.rd.util.lifetime.Lifetime
import com.jetbrains.rdserver.terminal.BackendTerminalManager
import com.jetbrains.rdserver.unattendedHost.UnattendedHostManager
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.future.await
import kotlinx.coroutines.launch
import org.jetbrains.plugins.terminal.ShellTerminalWidget
import org.jetbrains.plugins.terminal.TerminalToolWindowFactory
import org.jetbrains.plugins.terminal.TerminalView
import java.util.concurrent.CompletableFuture

@Suppress("UnstableApiUsage", "EXPERIMENTAL_IS_NOT_ENABLED", "OPT_IN_IS_NOT_ENABLED")
@OptIn(DelicateCoroutinesApi::class)
class GitpodTerminalService(private val project: Project) : Disposable {
private val lifetime = Lifetime.Eternal.createNested()
private val terminalView = TerminalView.getInstance(project)
private val backendTerminalManager = BackendTerminalManager.getInstance(project)

override fun dispose() {
lifetime.terminate()
}

init {
if (!application.isHeadlessEnvironment) {
launch()
}
}

private fun launch() = GlobalScope.launch {
getTerminalToolWindowRegisteredEvent().await()
delayUntilControllerClientConnects()
val widget = createNewSharedTerminal().await()
printWelcomeMessage(widget)
}

private fun printWelcomeMessage(widget: ShellTerminalWidget) {
widget.executeCommand(
"clear; echo '\uD83D\uDC4B Welcome to Gitpod!\n" +
"\t\t - Start by typing `gp --help` to see what you can do with Gitpod CLI.\n" +
"\t\t - Check also `gp tasks --help` to learn how to attach and watch running tasks defined on .gitpod.yml!\n'"
)
}

private fun getTerminalToolWindowRegisteredEvent(): CompletableFuture<Void> {
val completableFuture = CompletableFuture<Void>()

val messageBusConnection = project.messageBus.connect()

val toolWindowManagerListener = object : ToolWindowManagerListener {
override fun toolWindowsRegistered(ids: MutableList<String>, toolWindowManager: ToolWindowManager) {
if (ids.contains(TerminalToolWindowFactory.TOOL_WINDOW_ID)) {
completableFuture.complete(null)
messageBusConnection.disconnect()
}
}
}

messageBusConnection.subscribe(ToolWindowManagerListener.TOPIC, toolWindowManagerListener)

return completableFuture
}

private tailrec suspend fun delayUntilControllerClientConnects() {
if (UnattendedHostManager.getInstance().controllerClientId == null) {
delay(1000L)
return delayUntilControllerClientConnects()
}
}

private fun createNewSharedTerminal(): CompletableFuture<ShellTerminalWidget> {
val completableFuture = CompletableFuture<ShellTerminalWidget>()

runInEdt {
val shellTerminalWidget = terminalView.createLocalShellWidget(project.basePath, null)
backendTerminalManager.shareTerminal(shellTerminalWidget, "Gitpod")
completableFuture.complete(shellTerminalWidget)
}

return completableFuture
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
<depends>com.intellij.modules.platform</depends>
<dependencies>
<plugin id="Git4Idea"/>
<plugin id="org.jetbrains.plugins.terminal"/>
<plugin id="com.jetbrains.codeWithMe"/>
</dependencies>

<extensions defaultExtensionNs="com.intellij">
Expand All @@ -24,6 +26,7 @@
<notificationGroup id="Gitpod Notifications" displayType="BALLOON" isLogByDefault="false" />
<httpRequestHandler implementation="io.gitpod.jetbrains.remote.GitpodCLIService"/>
<projectService serviceImplementation="io.gitpod.jetbrains.remote.GitpodClientProjectSessionTracker" client="guest" preload="true"/>
<projectService serviceImplementation="io.gitpod.jetbrains.remote.GitpodTerminalService" preload="true"/>
<projectService serviceImplementation="io.gitpod.jetbrains.remote.GitpodProjectManager" preload="true"/>
</extensions>

Expand Down

0 comments on commit cec497b

Please sign in to comment.