[terminal] IJ-MR-158015 Refactor: extract FusAwareTtyConnector

Use delegation instead of inheritance.

GitOrigin-RevId: cf3b94e624396593bb5cad0e3d6d5d25d35970e5
This commit is contained in:
Sergei Tachenov
2025-04-15 07:32:53 +00:00
committed by intellij-monorepo-bot
parent 9f6e1bd228
commit daef3c9e81
4 changed files with 49 additions and 39 deletions
@@ -6,6 +6,7 @@ import com.intellij.openapi.project.Project
import com.intellij.platform.util.coroutines.childScope
import com.intellij.terminal.JBTerminalSystemSettingsProviderBase
import com.intellij.terminal.TerminalExecutorServiceManagerImpl
import com.intellij.terminal.backend.fus.enableFus
import com.intellij.terminal.session.TerminalSession
import com.intellij.terminal.session.TerminalSessionTerminatedEvent
import com.intellij.util.AwaitCancellationAndInvoke
@@ -24,7 +25,6 @@ import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.launch
import org.jetbrains.plugins.terminal.FusAwareTtyBasedDataStream
import org.jetbrains.plugins.terminal.LocalBlockTerminalRunner
import org.jetbrains.plugins.terminal.LocalTerminalTtyConnector
import org.jetbrains.plugins.terminal.ShellStartupOptions
import org.jetbrains.plugins.terminal.fus.BackendOutputActivity
import org.jetbrains.plugins.terminal.util.STOP_EMULATOR_TIMEOUT
@@ -55,9 +55,9 @@ internal fun createTerminalSession(
coroutineScope: CoroutineScope,
fusActivity: BackendOutputActivity,
): TerminalSession {
ttyConnector.startStatisticsReporting(fusActivity)
val connector = enableFus(ttyConnector, fusActivity)
val maxHistoryLinesCount = AdvancedSettings.getInt("terminal.buffer.max.lines.count")
val services: JediTermServices = createJediTermServices(ttyConnector, fusActivity, initialSize, maxHistoryLinesCount, settings)
val services: JediTermServices = createJediTermServices(connector, fusActivity, initialSize, maxHistoryLinesCount, settings)
val outputScope = coroutineScope.childScope("Terminal output forwarding")
val shellIntegrationController = TerminalShellIntegrationController(services.controller)
@@ -100,7 +100,7 @@ internal fun createTerminalSession(
}
private fun createJediTermServices(
connector: LocalTerminalTtyConnector,
connector: TtyConnector,
fusActivity: BackendOutputActivity,
termSize: TermSize,
maxHistoryLinesCount: Int,
@@ -4,8 +4,11 @@ import com.intellij.openapi.diagnostic.logger
import com.intellij.platform.rpc.UID
import com.intellij.terminal.session.TerminalContentUpdatedEvent
import com.intellij.terminal.session.TerminalWriteBytesEvent
import com.jediterm.core.util.TermSize
import com.jediterm.terminal.TtyConnector
import fleet.multiplatform.shims.ConcurrentHashMap
import org.jetbrains.plugins.terminal.fus.BackendLatencyService
import org.jetbrains.plugins.terminal.fus.BackendLatencyService.Companion.getInstance
import org.jetbrains.plugins.terminal.fus.BackendOutputActivity
import org.jetbrains.plugins.terminal.fus.BackendTypingActivity
import org.jetbrains.plugins.terminal.fus.ReworkedTerminalUsageCollector
@@ -32,6 +35,9 @@ internal class BackendLatencyServiceImpl : BackendLatencyService {
}
}
internal fun enableFus(ttyConnector: TtyConnector, fusActivity: BackendOutputActivity): TtyConnector =
FusAwareTtyConnector(ttyConnector, fusActivity)
private val backendTypingActivityByByteArray = ConcurrentHashMap<ByteArray, BackendTypingActivityImpl>()
private class BackendTypingActivityImpl(override val id: Int, private val bytes: ByteArray) : BackendTypingActivity {
@@ -285,6 +291,43 @@ private class BackendOutputActivityImpl : BackendOutputActivity {
}
}
private class FusAwareTtyConnector(private val original: TtyConnector, private val outputActivity: BackendOutputActivity) : TtyConnector {
override fun read(buf: CharArray, offset: Int, length: Int): Int = original.read(buf, offset, length).also { charsRead ->
outputActivity.charsRead(charsRead)
}
override fun write(bytes: ByteArray) {
val typingActivity = getInstance().getBackendTypingActivityOrNull(bytes)
try {
original.write(bytes)
typingActivity?.reportDuration()
}
finally {
typingActivity?.finishBytesProcessing()
}
}
override fun write(string: String) {
original.write(string)
}
override fun isConnected(): Boolean = original.isConnected
override fun waitFor(): Int = original.waitFor()
override fun ready(): Boolean = original.ready()
override fun getName(): String? = original.name
override fun close() {
original.close()
}
override fun resize(termSize: TermSize) {
original.resize(termSize)
}
}
// used to track individual instances of data classes
private class IdentityWrapper<T : Any>(private val instance: T) {
override fun equals(other: Any?): Boolean = instance === (other as? IdentityWrapper<T>)?.instance
@@ -2,12 +2,13 @@
package org.jetbrains.plugins.terminal
import com.jediterm.terminal.TtyBasedArrayDataStream
import com.jediterm.terminal.TtyConnector
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.plugins.terminal.fus.BackendOutputActivity
@ApiStatus.Internal
class FusAwareTtyBasedDataStream(
connector: LocalTerminalTtyConnector,
connector: TtyConnector,
private val fusActivity: BackendOutputActivity,
) : TtyBasedArrayDataStream(connector) {
@@ -9,11 +9,7 @@ import com.pty4j.PtyProcess;
import com.pty4j.unix.UnixPtyProcess;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.terminal.fus.BackendLatencyService;
import org.jetbrains.plugins.terminal.fus.BackendOutputActivity;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.concurrent.TimeUnit;
@@ -21,42 +17,12 @@ import java.util.concurrent.TimeUnit;
public class LocalTerminalTtyConnector extends PtyProcessTtyConnector {
private static final Logger LOG = Logger.getInstance(LocalTerminalTtyConnector.class);
private final @NotNull PtyProcess myProcess;
private @Nullable BackendOutputActivity fusActivity;
LocalTerminalTtyConnector(@NotNull PtyProcess process, @NotNull Charset charset) {
super(process, charset);
myProcess = process;
}
public void startStatisticsReporting(@NotNull BackendOutputActivity fusActivity) {
this.fusActivity = fusActivity;
}
@Override
public int read(char[] buf, int offset, int length) throws IOException {
var fusActivity = this.fusActivity;
var charsRead = super.read(buf, offset, length);
if (fusActivity == null) return charsRead;
fusActivity.charsRead(charsRead);
return charsRead;
}
@Override
public void write(byte[] bytes) throws IOException {
var fusActivity = BackendLatencyService.getInstance().getBackendTypingActivityOrNull(bytes);
try {
super.write(bytes);
if (fusActivity != null) {
fusActivity.reportDuration();
}
}
finally {
if (fusActivity != null) {
fusActivity.finishBytesProcessing();
}
}
}
@Override
public void close() {
if (myProcess instanceof UnixPtyProcess) {