mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[terminal] IJPL-212254 Add an ability to listen for terminal process working directory updates
Also, expose nio Path instead of plane native path string to avoid misuse. (cherry picked from commit e40073ba78fe429899a333081214ca88abf8fe2f) IJ-CR-214214 GitOrigin-RevId: b989cc23b9ac8d3dee75b715e8a400a9c5306641
This commit is contained in:
committed by
intellij-monorepo-bot
parent
8a5a5ac3de
commit
79c6b3f1c8
@@ -2,6 +2,7 @@ package com.intellij.terminal.frontend.view
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.actionSystem.DataKey
|
||||
import com.intellij.platform.eel.annotations.NativePath
|
||||
import com.intellij.terminal.TerminalTitle
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Deferred
|
||||
@@ -16,6 +17,7 @@ import org.jetbrains.plugins.terminal.view.TerminalOutputModelsSet
|
||||
import org.jetbrains.plugins.terminal.view.TerminalSendTextBuilder
|
||||
import org.jetbrains.plugins.terminal.view.shellIntegration.TerminalShellIntegration
|
||||
import java.awt.event.KeyEvent
|
||||
import java.nio.file.Path
|
||||
import javax.swing.JComponent
|
||||
|
||||
@ApiStatus.Internal
|
||||
@@ -98,6 +100,17 @@ interface TerminalView {
|
||||
*/
|
||||
val keyEventsFlow: Flow<TerminalKeyEvent>
|
||||
|
||||
/**
|
||||
* Absolute [Path] of the current working directory of the terminal process.
|
||||
*
|
||||
* When [TerminalShellIntegration] is available, it is used to track the working directory.
|
||||
* Otherwise, the OS-specific heuristics and polling approach will be used.
|
||||
*
|
||||
* Can be null if process is not started yet.
|
||||
* Or if shell integration is not available and OS-specific heuristics fail to determine the working directory of the process.
|
||||
*/
|
||||
val workingDirectoryFlow: StateFlow<Path?>
|
||||
|
||||
/**
|
||||
* Can be used to get or await the shell integration initialization.
|
||||
*
|
||||
@@ -144,7 +157,8 @@ interface TerminalView {
|
||||
* Returns null if the shell process is not connected yet to the [TerminalView]
|
||||
* or if the initial value is not yet received from the backend.
|
||||
*/
|
||||
fun getCurrentDirectory(): String?
|
||||
@Deprecated("Use workingDirectoryFlow instead.", ReplaceWith("workingDirectoryFlow.value"))
|
||||
fun getCurrentDirectory(): @NativePath String?
|
||||
|
||||
/**
|
||||
* A shortcut to schedule sending the specified text to the shell process
|
||||
|
||||
+1
-14
@@ -1,12 +1,9 @@
|
||||
package com.intellij.terminal.frontend.view.impl
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.platform.eel.path.EelPath
|
||||
import com.intellij.platform.eel.provider.asNioPath
|
||||
import com.intellij.terminal.frontend.toolwindow.TerminalToolWindowTabsManager
|
||||
import com.intellij.terminal.frontend.toolwindow.findTabByContent
|
||||
import com.intellij.terminal.frontend.toolwindow.impl.shouldUseReworkedTerminal
|
||||
import com.intellij.terminal.frontend.view.TerminalView
|
||||
import com.intellij.toolWindow.ToolWindowSplitContentProvider
|
||||
import com.intellij.ui.content.Content
|
||||
import org.jetbrains.plugins.terminal.TerminalOptionsProvider
|
||||
@@ -14,8 +11,6 @@ import org.jetbrains.plugins.terminal.TerminalTabState
|
||||
import org.jetbrains.plugins.terminal.TerminalToolWindowManager
|
||||
import org.jetbrains.plugins.terminal.fus.TerminalStartupFusInfo
|
||||
import org.jetbrains.plugins.terminal.fus.TerminalTabOpeningWay
|
||||
import org.jetbrains.plugins.terminal.util.getNow
|
||||
import java.nio.file.Path
|
||||
|
||||
internal class TerminalToolWindowSplitContentProvider : ToolWindowSplitContentProvider {
|
||||
override fun createContentCopy(project: Project, content: Content): Content {
|
||||
@@ -32,7 +27,7 @@ internal class TerminalToolWindowSplitContentProvider : ToolWindowSplitContentPr
|
||||
private fun createReworkedTerminalContent(project: Project, content: Content, fusInfo: TerminalStartupFusInfo): Content {
|
||||
val manager = TerminalToolWindowTabsManager.getInstance(project)
|
||||
val originalView = manager.findTabByContent(content)?.view
|
||||
val currentDirectory = originalView?.getCurrentDirectoryPath()
|
||||
val currentDirectory = originalView?.workingDirectoryFlow?.value
|
||||
|
||||
return manager.createTabBuilder()
|
||||
.workingDirectory(currentDirectory?.toString())
|
||||
@@ -42,14 +37,6 @@ internal class TerminalToolWindowSplitContentProvider : ToolWindowSplitContentPr
|
||||
.content
|
||||
}
|
||||
|
||||
private fun TerminalView.getCurrentDirectoryPath(): Path? {
|
||||
val currentDirectory = getCurrentDirectory() ?: return null
|
||||
val session = sessionDeferred.getNow() ?: return null
|
||||
return runCatching {
|
||||
EelPath.parse(currentDirectory, session.eelDescriptor).asNioPath()
|
||||
}.getOrNull()
|
||||
}
|
||||
|
||||
private fun createClassicTerminalContent(
|
||||
project: Project,
|
||||
originalContent: Content,
|
||||
|
||||
+12
-1
@@ -21,6 +21,7 @@ import com.intellij.openapi.util.registry.Registry
|
||||
import com.intellij.openapi.wm.IdeFocusManager
|
||||
import com.intellij.platform.eel.provider.LocalEelDescriptor
|
||||
import com.intellij.platform.util.coroutines.childScope
|
||||
import com.intellij.platform.util.coroutines.flow.mapStateIn
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import com.intellij.terminal.JBTerminalSystemSettingsProviderBase
|
||||
import com.intellij.terminal.TerminalTitle
|
||||
@@ -91,6 +92,7 @@ import org.jetbrains.plugins.terminal.hyperlinks.session.TerminalHyperlinksSessi
|
||||
import org.jetbrains.plugins.terminal.session.TerminalGridSize
|
||||
import org.jetbrains.plugins.terminal.session.TerminalStartupOptions
|
||||
import org.jetbrains.plugins.terminal.session.impl.TerminalSession
|
||||
import org.jetbrains.plugins.terminal.util.convertNativePathToNioPath
|
||||
import org.jetbrains.plugins.terminal.util.getNow
|
||||
import org.jetbrains.plugins.terminal.view.TerminalContentChangeEvent
|
||||
import org.jetbrains.plugins.terminal.view.TerminalCursorOffsetChangeEvent
|
||||
@@ -117,6 +119,7 @@ import java.awt.event.ComponentEvent
|
||||
import java.awt.event.FocusEvent
|
||||
import java.awt.event.FocusListener
|
||||
import java.awt.event.KeyEvent
|
||||
import java.nio.file.Path
|
||||
import javax.swing.JComponent
|
||||
import javax.swing.JPanel
|
||||
import kotlin.coroutines.cancellation.CancellationException
|
||||
@@ -181,6 +184,8 @@ class TerminalViewImpl(
|
||||
override val keyEventsFlow: Flow<TerminalKeyEvent> = mutableKeyEventsFlow.asSharedFlow()
|
||||
private val inputInterceptors = ContainerUtil.createLockFreeCopyOnWriteList<TerminalInputInterceptor>()
|
||||
|
||||
override val workingDirectoryFlow: StateFlow<Path?>
|
||||
|
||||
override val shellIntegrationDeferred: CompletableDeferred<TerminalShellIntegration> =
|
||||
CompletableDeferred(coroutineScope.coroutineContext.job)
|
||||
override val startupOptionsDeferred: CompletableDeferred<TerminalStartupOptions> =
|
||||
@@ -191,6 +196,12 @@ class TerminalViewImpl(
|
||||
|
||||
init {
|
||||
sessionModel = TerminalSessionModelImpl()
|
||||
workingDirectoryFlow = sessionModel.terminalState.mapStateIn(coroutineScope.childScope("workingDirectoryFlow")) {
|
||||
val directoryString = it.currentDirectory ?: return@mapStateIn null
|
||||
val eelDescriptor = sessionDeferred.getNow()?.eelDescriptor ?: return@mapStateIn null
|
||||
convertNativePathToNioPath(directoryString, eelDescriptor)
|
||||
}
|
||||
|
||||
encodingManager = TerminalKeyEncodingManager(sessionModel, coroutineScope.childScope("TerminalKeyEncodingManager"))
|
||||
|
||||
terminalInput = TerminalInput(
|
||||
@@ -750,7 +761,7 @@ class TerminalViewImpl(
|
||||
|
||||
override fun toString(): String {
|
||||
val commandText = startupOptionsDeferred.getNow()?.let { "${it.shellCommand}" }
|
||||
return "TerminalViewImpl(state=${sessionState.value}, command=$commandText, cwd=${getCurrentDirectory()})"
|
||||
return "TerminalViewImpl(state=${sessionState.value}, command=$commandText, cwd=${workingDirectoryFlow.value})"
|
||||
}
|
||||
|
||||
private inner class TerminalPanel(initialContent: Editor) : BorderLayoutPanel(), UiDataProvider, TerminalPanelMarker {
|
||||
|
||||
@@ -13,6 +13,11 @@ import com.intellij.openapi.keymap.Keymap
|
||||
import com.intellij.openapi.keymap.KeymapManager
|
||||
import com.intellij.openapi.keymap.ex.KeymapManagerEx
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.platform.eel.EelDescriptor
|
||||
import com.intellij.platform.eel.annotations.NativePath
|
||||
import com.intellij.platform.eel.path.EelPath
|
||||
import com.intellij.platform.eel.path.EelPathException
|
||||
import com.intellij.platform.eel.provider.asNioPath
|
||||
import com.intellij.util.concurrency.annotations.RequiresBackgroundThread
|
||||
import com.intellij.util.concurrency.annotations.RequiresReadLockAbsence
|
||||
import com.intellij.util.io.awaitExit
|
||||
@@ -250,3 +255,22 @@ internal fun String?.toExistentNioDirectory(labelToLogOnFailure: String? = null)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null if failed to convert [remotePath] to nio Path.
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
fun convertNativePathToNioPath(remotePath: @NativePath String, descriptor: EelDescriptor): Path? {
|
||||
val eelPath: EelPath = try {
|
||||
EelPath.parse(remotePath, descriptor)
|
||||
}
|
||||
catch (_: EelPathException) {
|
||||
return null
|
||||
}
|
||||
return try {
|
||||
eelPath.asNioPath()
|
||||
}
|
||||
catch (_: IllegalArgumentException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user