From 6e9c013e60e59660cb7ae6289af5ed129ca85996 Mon Sep 17 00:00:00 2001 From: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com> Date: Mon, 25 Jul 2022 07:40:40 +0530 Subject: [PATCH] feat: Enable transience for Cmd and PowerShell (#4143) --- docs/advanced-config/README.md | 61 ++++++++++++++++++++++++++++++++++ src/init/starship.lua | 12 +++++++ src/init/starship.ps1 | 49 +++++++++++++++++++++++++-- 3 files changed, 120 insertions(+), 2 deletions(-) diff --git a/docs/advanced-config/README.md b/docs/advanced-config/README.md index 7856e672..ea71bc1b 100644 --- a/docs/advanced-config/README.md +++ b/docs/advanced-config/README.md @@ -10,6 +10,67 @@ The configurations in this section are subject to change in future releases of S ::: +## TransientPrompt in PowerShell + +It is possible to replace the previous-printed prompt with a custom string. This +is useful in cases where all the prompt information is not always needed. To enable +this, run `Enable-TransientPrompt` in the shell session. To make it permanent, put +this statement in your `$PROFILE`. Transience can be disabled on-the-fly with +`Disable-TransientPrompt`. + +By default, the left side of input gets replaced with `>`. To customize this, +define a new function called `Invoke-Starship-TransientFunction`. For example, to +display Starship's `character` module here, you would do + +```powershell +function Invoke-Starship-TransientFunction { + &starship module character +} + +Invoke-Expression (&starship init powershell) + +Enable-TransientPrompt +``` + +## TransientPrompt and TransientRightPrompt in Cmd + +Clink allows you to replace the previous-printed prompt with custom strings. This +is useful in cases where all the prompt information is not always needed. To enable +this, run `clink set prompt.transient ` where \ can be one of: + +- `always`: always replace the previous prompt +- `same_dir`: replace the previous prompt only if the working directory is same +- `off`: do not replace the prompt (i.e. turn off transience) + +You need to do this only once. Make the following changes to your `starship.lua` +to customize what gets displayed on the left and on the right: + +- By default, the left side of input gets replaced with `>`. To customize this, + define a new function called `starship_transient_prompt_func`. This function + receives the current prompt as a string that you can utilize. For example, to + display Starship's `character` module here, you would do + +```lua +function starship_transient_prompt_func(prompt) + return io.popen("starship module character" + .." --keymap="..rl.getvariable('keymap') + ):read("*a") +end +load(io.popen('starship init cmd'):read("*a"))() +``` + +- By default, the right side of input is empty. To customize this, define a new + function called `starship_transient_rprompt_func`. This function receives the + current prompt as a string that you can utilize. For example, to display + the time at which the last command was started here, you would do + +```lua +function starship_transient_rprompt_func(prompt) + return io.popen("starship module time"):read("*a") +end +load(io.popen('starship init cmd'):read("*a"))() +``` + ## Custom pre-prompt and pre-execution Commands in Cmd Clink provides extremely flexible APIs to run pre-prompt and pre-exec commands diff --git a/src/init/starship.lua b/src/init/starship.lua index accbc976..22996298 100644 --- a/src/init/starship.lua +++ b/src/init/starship.lua @@ -49,6 +49,18 @@ function starship_prompt:rightfilter(prompt) ):read("*a") end +if starship_transient_prompt_func ~= nil then + function starship_prompt:transientfilter(prompt) + return starship_transient_prompt_func(prompt) + end +end + +if starship_transient_rprompt_func ~= nil then + function starship_prompt:transientrightfilter(prompt) + return starship_transient_rprompt_func(prompt) + end +end + local characterset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" local randomkey = "" math.randomseed(os.time()) diff --git a/src/init/starship.ps1 b/src/init/starship.ps1 index 6b9c1d29..a877aa7f 100755 --- a/src/init/starship.ps1 +++ b/src/init/starship.ps1 @@ -64,6 +64,36 @@ $null = New-Module starship { $process.StandardOutput.ReadToEnd(); } + function Enable-TransientPrompt { + Set-PSReadLineKeyHandler -Key Enter -ScriptBlock { + $previousOutputEncoding = [Console]::OutputEncoding + try { + $parseErrors = $null + [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$null, [ref]$null, [ref]$parseErrors, [ref]$null) + if ($parseErrors.Count -eq 0) { + $script:TransientPrompt = $true + [Console]::OutputEncoding = [Text.Encoding]::UTF8 + [Microsoft.PowerShell.PSConsoleReadLine]::InvokePrompt() + } + } finally { + if ($script:DoesUseLists) { + # If PSReadline is set to display suggestion list, this workaround is needed to clear the buffer below + # before accepting the current commandline. The max amount of items in the list is 10, so 12 lines + # are cleared (10 + 1 more for the prompt + 1 more for current commandline). + [Microsoft.PowerShell.PSConsoleReadLine]::Insert("`n" * [math]::Min($Host.UI.RawUI.WindowSize.Height - $Host.UI.RawUI.CursorPosition.Y - 1, 12)) + [Microsoft.PowerShell.PSConsoleReadLine]::Undo() + } + [Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine() + [Console]::OutputEncoding = $previousOutputEncoding + } + } + } + + function Disable-TransientPrompt { + Set-PSReadLineKeyHandler -Key Enter -Function AcceptLine + $script:TransientPrompt = $false + } + function global:prompt { $origDollarQuestion = $global:? $origLastExitCode = $global:LASTEXITCODE @@ -106,7 +136,16 @@ $null = New-Module starship { $arguments += "--status=$($lastExitCodeForPrompt)" # Invoke Starship - $promptText = Invoke-Native -Executable ::STARSHIP:: -Arguments $arguments + $promptText = if ($script:TransientPrompt) { + $script:TransientPrompt = $false + if (Test-Path function:Invoke-Starship-TransientFunction) { + Invoke-Starship-TransientFunction + } else { + "$([char]0x1B)[1;32m❯$([char]0x1B)[0m " + } + } else { + Invoke-Native -Executable ::STARSHIP:: -Arguments $arguments + } # Set the number of extra lines in the prompt for PSReadLine prompt redraw. Set-PSReadLineOption -ExtraPromptLineCount ($promptText.Split("`n").Length - 1) @@ -141,6 +180,9 @@ $null = New-Module starship { # Disable virtualenv prompt, it breaks starship $ENV:VIRTUAL_ENV_DISABLE_PROMPT=1 + $script:TransientPrompt = $false + $script:DoesUseLists = (Get-PSReadLineOption).PredictionViewStyle -eq 'ListView' + if ($PSVersionTable.PSVersion.Major -gt 5) { $ENV:STARSHIP_SHELL = "pwsh" } else { @@ -158,5 +200,8 @@ $null = New-Module starship { ) ) - Export-ModuleMember + Export-ModuleMember -Function @( + "Enable-TransientPrompt" + "Disable-TransientPrompt" + ) }