mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[terminal] IJPL-211122 Document TerminalShellIntegration and related interfaces
(cherry picked from commit e8722fa85d0ff51d574d60c4fa9e3c9eb3a0f886) IJ-CR-180081 GitOrigin-RevId: bfcb3cfa5212cbadd6e4f4fb370c2d50fc732794
This commit is contained in:
committed by
intellij-monorepo-bot
parent
34a20b3806
commit
d6e1c5df15
@@ -70,10 +70,14 @@ interface TerminalView {
|
||||
|
||||
/**
|
||||
* Can be used to get or await the shell integration initialization.
|
||||
* Note that it may never complete because the shell integration may be not available
|
||||
*
|
||||
* Note that **it may never complete** because the shell integration may be not available
|
||||
* (for example, because of an unsupported shell or environment)
|
||||
* or it can be disabled in the Terminal settings ([org.jetbrains.plugins.terminal.TerminalOptionsProvider.shellIntegration]).
|
||||
*
|
||||
* If the started shell supports the shell integration,
|
||||
* it will be initialized before the first prompt is printed in the output.
|
||||
*
|
||||
* @see TerminalShellIntegration
|
||||
*/
|
||||
val shellIntegrationDeferred: Deferred<TerminalShellIntegration>
|
||||
|
||||
+3
@@ -4,6 +4,9 @@ package org.jetbrains.plugins.terminal.view.shellIntegration
|
||||
import kotlinx.serialization.Serializable
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
/**
|
||||
* The unique identifier of the terminal block.
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
@Serializable
|
||||
sealed interface TerminalBlockId
|
||||
|
||||
+71
-5
@@ -5,26 +5,92 @@ import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.plugins.terminal.view.TerminalOffset
|
||||
import org.jetbrains.plugins.terminal.view.TerminalOutputModel
|
||||
|
||||
/**
|
||||
* The terminal block is the range of text in the [TerminalOutputModel] and some additional information
|
||||
* about the content and meaning of this text.
|
||||
*
|
||||
* Currently, there is a single implementation: [TerminalCommandBlock].
|
||||
* So, use safe cast to [TerminalCommandBlock] if you need to work with the command block.
|
||||
* But other implementations might be added in the future.
|
||||
*
|
||||
* Blocks are supported only for the [regular][org.jetbrains.plugins.terminal.view.TerminalOutputModelsSet.regular] output model,
|
||||
* so all [TerminalOffset]'s are specified relative to it.
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
@ApiStatus.NonExtendable
|
||||
interface TerminalBlockBase {
|
||||
val id: TerminalBlockId
|
||||
|
||||
/**
|
||||
* Always check that this offset is in the bounds of the regular [TerminalOutputModel] before accessing the text.
|
||||
* Because when the output model starts trimming the start of the output (because of reaching the max length),
|
||||
* the block offsets are not updated.
|
||||
*/
|
||||
val startOffset: TerminalOffset
|
||||
|
||||
val endOffset: TerminalOffset
|
||||
}
|
||||
|
||||
/**
|
||||
* The terminal block that represents the range of the terminal output that can contain
|
||||
* prompt, command and the command output.
|
||||
* Also, it provides additional metadata about the command, such as [workingDirectory], [executedCommand] and [exitCode].
|
||||
*
|
||||
* The usual structure of the block is the following:
|
||||
* ```
|
||||
* <startOffset>prompt: <commandStartOffset>some command
|
||||
* <outputStartOffset>some
|
||||
* command
|
||||
* output
|
||||
* <endOffset>
|
||||
* ```
|
||||
*
|
||||
* Note that the shell output can also contain the right prompt and line continuations.
|
||||
* It is worth detecting the positions of these parts as well, but it is not supported at the moment.
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
@ApiStatus.NonExtendable
|
||||
interface TerminalCommandBlock : TerminalBlockBase {
|
||||
/**
|
||||
* The offset where the prompt finishes and command text starts.
|
||||
* Can be null in the initial block of the output before the first prompt is printed.
|
||||
*
|
||||
* Always check that this offset is in the bounds of the regular [TerminalOutputModel] before accessing the text.
|
||||
* Because when the output model starts trimming the start of the output (because of reaching the max length),
|
||||
* the block offsets are not updated.
|
||||
*/
|
||||
val commandStartOffset: TerminalOffset?
|
||||
|
||||
/**
|
||||
* The offset where the command output starts.
|
||||
*
|
||||
* Can be null if the command was not started to execute.
|
||||
* For example, if a user is typing a command now.
|
||||
* Or if the command was meaningless and shell just printed the new prompt.
|
||||
* Or if the user aborted the command typing by pressing Ctrl+C.
|
||||
*
|
||||
* Always check that this offset is in the bounds of the regular [TerminalOutputModel] before accessing the text.
|
||||
* Because when the output model starts trimming the start of the output (because of reaching the max length),
|
||||
* the block offsets are not updated.
|
||||
*/
|
||||
val outputStartOffset: TerminalOffset?
|
||||
|
||||
val workingDirectory: String?
|
||||
/**
|
||||
* Should be non-null if the command was started to execute.
|
||||
* It is the command text reported by the shell integration right before it is started.
|
||||
* The absolute OS-dependent path to the working directory that was set in a shell
|
||||
* when this command block was active.
|
||||
*/
|
||||
val workingDirectory: String?
|
||||
|
||||
/**
|
||||
* The command text reported by the shell integration right before it is started.
|
||||
* Null if the command was not executed.
|
||||
*/
|
||||
val executedCommand: String?
|
||||
|
||||
/**
|
||||
* The exit code reported by the shell integration when the command execution was finished.
|
||||
* Null if the command was not executed.
|
||||
*/
|
||||
val exitCode: Int?
|
||||
}
|
||||
|
||||
@@ -54,7 +120,7 @@ fun TerminalCommandBlock.getTypedCommandText(model: TerminalOutputModel): String
|
||||
* @param model regular terminal output model (not alternative one)
|
||||
* @return command output text with possibly trimmed start and without trailing whitespaces.
|
||||
* Can return null if no command was running in this block or the block is out of model bounds.
|
||||
* If the command produces no output, an empty string will be returned.
|
||||
* If the command was executed but produced no output, an empty string will be returned.
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
fun TerminalCommandBlock.getOutputText(model: TerminalOutputModel): String? {
|
||||
@@ -69,7 +135,7 @@ fun TerminalCommandBlock.getOutputText(model: TerminalOutputModel): String? {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the command was started to execute in this block, so it contains some output.
|
||||
* @return true if the command was started to execute in this block, so it can contain some output.
|
||||
*/
|
||||
@get:ApiStatus.Experimental
|
||||
val TerminalCommandBlock.wasExecuted: Boolean
|
||||
|
||||
+26
-3
@@ -3,16 +3,39 @@ package org.jetbrains.plugins.terminal.view.shellIntegration
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.util.concurrency.annotations.RequiresEdt
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
/**
|
||||
* The model that holds the information about the ranges of the shell output: terminal blocks.
|
||||
*
|
||||
* Note that the block model exists only in the context
|
||||
* of the [regular][org.jetbrains.plugins.terminal.view.TerminalOutputModelsSet.regular] output model.
|
||||
* So, all [org.jetbrains.plugins.terminal.view.TerminalOffset]'s are specified relative to it.
|
||||
*
|
||||
* The interface provides a read-only view, but the model itself is mutable and therefore should only be accessed on the mutating thread,
|
||||
* which is currently the **EDT**.
|
||||
*
|
||||
* @see TerminalBlockBase
|
||||
* @see TerminalCommandBlock
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
@ApiStatus.NonExtendable
|
||||
interface TerminalBlocksModel {
|
||||
/** The list can be mutable in the implementation, so it should not be cached. */
|
||||
@get:RequiresEdt
|
||||
/**
|
||||
* The list of the blocks in the model, it is always sorted in the order of appearance.
|
||||
* So, the first block is the oldest in the output, and the last block is the newest.
|
||||
*
|
||||
* The list is always non-empty.
|
||||
* The first block may be partially out of the regular [org.jetbrains.plugins.terminal.view.TerminalOutputModel] bounds due to trimming.
|
||||
*
|
||||
* The list can be mutable in the implementation, so it should not be cached.
|
||||
*/
|
||||
val blocks: List<TerminalBlockBase>
|
||||
|
||||
/**
|
||||
* Currently active terminal block.
|
||||
* For example, it can contain the current command a user is typing or executing.
|
||||
*/
|
||||
val activeBlock: TerminalBlockBase
|
||||
|
||||
fun addListener(parentDisposable: Disposable, listener: TerminalBlocksModelListener)
|
||||
|
||||
+11
@@ -7,8 +7,17 @@ import org.jetbrains.annotations.ApiStatus
|
||||
interface TerminalBlocksModelListener {
|
||||
fun blockAdded(event: TerminalBlockAddedEvent) {}
|
||||
|
||||
/**
|
||||
* Can be called when the block range becomes out of the regular [org.jetbrains.plugins.terminal.view.TerminalOutputModel] bounds
|
||||
* because of trimming.
|
||||
* Or when some text removing operation is performed, for example, executing `clear` command.
|
||||
*/
|
||||
fun blockRemoved(event: TerminalBlockRemovedEvent) {}
|
||||
|
||||
/**
|
||||
* Can be called when some mass text replacement operation is performed, for example,
|
||||
* when initial state of the [TerminalBlocksModel] is received from the backend.
|
||||
*/
|
||||
fun blocksReplaced(event: TerminalBlocksReplacedEvent) {}
|
||||
}
|
||||
|
||||
@@ -21,12 +30,14 @@ interface TerminalBlocksModelEvent {
|
||||
@ApiStatus.Experimental
|
||||
@ApiStatus.NonExtendable
|
||||
interface TerminalBlockAddedEvent : TerminalBlocksModelEvent {
|
||||
/** The block that was added to the model */
|
||||
val block: TerminalBlockBase
|
||||
}
|
||||
|
||||
@ApiStatus.Experimental
|
||||
@ApiStatus.NonExtendable
|
||||
interface TerminalBlockRemovedEvent : TerminalBlocksModelEvent {
|
||||
/** The block that was removed from the model */
|
||||
val block: TerminalBlockBase
|
||||
}
|
||||
|
||||
|
||||
+13
@@ -6,25 +6,38 @@ import org.jetbrains.plugins.terminal.view.TerminalOutputModel
|
||||
|
||||
@ApiStatus.Experimental
|
||||
interface TerminalCommandExecutionListener {
|
||||
/**
|
||||
* Called when the "Enter" key is received by the shell, the shell identified
|
||||
* the typed command as a complete command and going to execute it.
|
||||
*/
|
||||
fun commandStarted(event: TerminalCommandStartedEvent) {}
|
||||
|
||||
/**
|
||||
* Called when shell finished executing the command.
|
||||
* The output and other metadata can be accessed from the [TerminalCommandFinishedEvent.commandBlock].
|
||||
*/
|
||||
fun commandFinished(event: TerminalCommandFinishedEvent) {}
|
||||
}
|
||||
|
||||
@ApiStatus.Experimental
|
||||
@ApiStatus.NonExtendable
|
||||
interface TerminalCommandExecutionEvent {
|
||||
/**
|
||||
* The same as the [regular][org.jetbrains.plugins.terminal.view.TerminalOutputModelsSet.regular] output model.
|
||||
*/
|
||||
val outputModel: TerminalOutputModel
|
||||
}
|
||||
|
||||
@ApiStatus.Experimental
|
||||
@ApiStatus.NonExtendable
|
||||
interface TerminalCommandStartedEvent : TerminalCommandExecutionEvent {
|
||||
/** The block with the information about the executing command */
|
||||
val commandBlock: TerminalCommandBlock
|
||||
}
|
||||
|
||||
@ApiStatus.Experimental
|
||||
@ApiStatus.NonExtendable
|
||||
interface TerminalCommandFinishedEvent : TerminalCommandExecutionEvent {
|
||||
/** The block with the information about the finished command */
|
||||
val commandBlock: TerminalCommandBlock
|
||||
}
|
||||
+18
@@ -3,10 +3,28 @@ package org.jetbrains.plugins.terminal.view.shellIntegration
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
/**
|
||||
* Represents the state of the terminal during shell output processing.
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
@ApiStatus.NonExtendable
|
||||
interface TerminalOutputStatus {
|
||||
/**
|
||||
* The terminal is waiting until the shell prompt is received from the output.
|
||||
*
|
||||
* For example, this status is active when the shell is just started and didn't print the first prompt yet.
|
||||
* Or when we start receiving the prompt text after the command execution.
|
||||
*/
|
||||
object WaitingForPrompt : TerminalOutputStatus
|
||||
|
||||
/**
|
||||
* The prompt was received and user is invited to type the command.
|
||||
*/
|
||||
object TypingCommand : TerminalOutputStatus
|
||||
|
||||
/**
|
||||
* User typed the command and pressed Enter to execute it.
|
||||
* Now the output of the command is being received.
|
||||
*/
|
||||
object ExecutingCommand : TerminalOutputStatus
|
||||
}
|
||||
+27
@@ -5,12 +5,39 @@ import com.intellij.openapi.Disposable
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
/**
|
||||
* Declares the features provided by the terminal shell integration (when it is available).
|
||||
*
|
||||
* When we start the shell process, we inject our shell scripts into its startup.
|
||||
* To get the information about the environment and subscribe for events.
|
||||
* For example, to know the positions of the prompt, command and the command output in the shell output.
|
||||
*
|
||||
* Currently, the shell integration is available only for **Bash, Zsh and PowerShell**.
|
||||
* But in Zsh the integration is disabled when the PowerLevel10K plugin is installed.
|
||||
* Also, it is controlled by the option in the Terminal settings.
|
||||
* ([org.jetbrains.plugins.terminal.TerminalOptionsProvider.shellIntegration])
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
@ApiStatus.NonExtendable
|
||||
interface TerminalShellIntegration {
|
||||
/**
|
||||
* The model that holds the information ranges of the shell output.
|
||||
*
|
||||
* @see TerminalBlockBase
|
||||
* @see TerminalCommandBlock
|
||||
*/
|
||||
val blocksModel: TerminalBlocksModel
|
||||
|
||||
/**
|
||||
* Represents the current state of the terminal during shell output processing.
|
||||
*
|
||||
* StateFlow can be useful to await some particular state in a suspending context,
|
||||
* for example `outputStatus.first { it == TypingCommand }`.
|
||||
*/
|
||||
val outputStatus: StateFlow<TerminalOutputStatus>
|
||||
|
||||
/**
|
||||
* Allows listening for command start and finish events.
|
||||
*/
|
||||
fun addCommandExecutionListener(parentDisposable: Disposable, listener: TerminalCommandExecutionListener)
|
||||
}
|
||||
Reference in New Issue
Block a user