Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ide] Initialize a shared terminal on JetBrains IDEs when a workspace starts #9443

Merged
merged 1 commit into from
Apr 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,96 @@
// 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.remoteDev.util.onTerminationOrNow
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) {
val job = launch()
lifetime.onTerminationOrNow { job.cancel() }
}
}

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 - Run `gp tasks --help` to learn how to attach and watch tasks defined in .gitpod.yml!\n'; gp tasks attach"
)
}

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 suspend fun delayUntilControllerClientConnects() {
while (UnattendedHostManager.getInstance().controllerClientId == null) {
delay(1000L)
}
}

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