feat(pwsh): transient prompt

This commit is contained in:
Jan De Dobbeleer 2021-06-15 21:23:08 +02:00 committed by Jan De Dobbeleer
parent 7bb0c9ae0b
commit 7c72e76aff
13 changed files with 235 additions and 77 deletions

View file

@ -9,15 +9,17 @@ import TabItem from "@theme/TabItem";
## Tooltips
:::info
Due to limitations (or not having found a way just yet) this feature only work in `zsh` and `powershell` for
the time being.
:::
Tooltips are segments that are rendered as a right aligned prompt while you're typing certain keywords.
They behave similar to the other segments when it comes to how and when they are shown so you can tweak
them to act and look like you want. The key difference is that they can be invoked using `tips` which are the
commands you are typing. Due to the possibility of the use of an alias, you can define for which keyword
the segment should be rendered.
Due to limitations (or not having found a way just yet) this feature only work for `zsh` and `powershell` at
the time of writing.
### Configuration
You need to extend or create a custom theme with your tooltips. For example:
@ -87,3 +89,65 @@ Restart your shell or reload `.zshrc` using `source ~/.zshrc` for the changes to
</TabItem>
</Tabs>
## Transient prompt
:::info
This feature only works in `powershell` for the time being.
:::
Transient prompt, when enabled, replaces the prompt with a simpler one to allow more screen real estate.
You can use go [text/template][go-text-template] templates extended with [sprig][sprig] to enrich the text.
Environment variables are available, just like the [`console_title_template`][console-title] functionality.
### Configuration
You need to extend or create a custom theme with your transient prompt. For example:
```json
{
"blocks": {
...
}
"transient_prompt": {
"background": "transparent",
"foreground": "#ffffff",
"template": "{{ .Shell }}> <#f7dc66>{{ .Command }}</>"
}
}
```
The configuration has the following properties:
- background: `string` [color][colors]
- foreground: `string` [color][colors]
- template: `string` - A go [text/template][go-text-template] template extended with [sprig][sprig] utilizing the
properties below. Defaults to `{{ .Shell }}> <#f7dc66>{{ .Command }}</>`
- vertical_offset: `int` - Move the prompt up or down x lines. For example `vertical_offset: 1` moves the prompt down one line, `vertical_offset: -1`
moves it up one line. Useful when you have a multiline prompt. Defaults to `0`
#### Template Properties
- `.Command`: `string` - the shell command you typed
- `.Root`: `boolean` - is the current user root/admin or not
- `.Path`: `string` - the current working directory
- `.Folder`: `string` - the current working folder
- `.Shell`: `string` - the current shell name
- `.User`: `string` - the current user name
- `.Host`: `string` - the host name
- `.Env.VarName`: `string` - Any environment variable where `VarName` is the environment variable name
### Enable the feature
Import/invoke Oh My Posh in your `$PROFILE` and add the following line below:
```pwsh
Enable-PoshTransientPrompt
```
Restart your shell or reload your `$PROFILE` using `. $PROFILE` for the changes to take effect.
[go-text-template]: https://golang.org/pkg/text/template/
[sprig]: https://masterminds.github.io/sprig/
[console-title]: /docs/configure#console-title-template
[colors]: /docs/configure#colors

View file

@ -319,7 +319,26 @@ Note for Windows users: Windows directory separators should be specified as 4 ba
]
```
#### Colors
### Colors
#### Standard colors
Oh My Posh mainly supports three different color types being
- Typical [hex colors][hexcolors] (for example `#CB4B16`).
- The `transparent` keyword which can be used to create either a transparent foreground override
or transparent background color using the segment's foreground property.
- 16 [ANSI color names][ansicolors].
These include 8 basic ANSI colors and `default`:
`black` `red` `green` `yellow` `blue` `magenta` `cyan` `white` `default`
as well as 8 extended ANSI colors:
`darkGray` `lightRed` `lightGreen` `lightYellow` `lightBlue` `lightMagenta` `lightCyan` `lightWhite`
#### Color overrides
You have the ability to override the foreground and/or background color for text in any property that accepts it.
The syntax is custom but should be rather straighforward:
@ -345,21 +364,6 @@ To change *only* the background color, just omit the first color from the above
"prefix": "<,#FFFFFF>┏[</>",
```
Oh My Posh mainly supports three different color types being
- Typical [hex colors][hexcolors] (for example `#CB4B16`).
- The `transparent` keyword which can be used to create either a transparent foreground override
or transparent background color using the segment's foreground property.
- 16 [ANSI color names][ansicolors].
These include 8 basic ANSI colors and `default`:
`black` `red` `green` `yellow` `blue` `magenta` `cyan` `white` `default`
as well as 8 extended ANSI colors:
`darkGray` `lightRed` `lightGreen` `lightYellow` `lightBlue` `lightMagenta` `lightCyan` `lightWhite`
### Text decorations
You can make use of the following syntax to decorate text:

View file

@ -49,3 +49,5 @@ properties below. Only used when a value is set, making the above properties obs
- `POSH_SESSION_DEFAULT_USER` - used to override the hardcoded `default_user_name` property
[colors]: /docs/configure#colors
[go-text-template]: https://golang.org/pkg/text/template/
[sprig]: https://masterminds.github.io/sprig/

View file

@ -71,3 +71,6 @@ Show the current timestamp.
- StampMilli = "Jan _2 15:04:05.000"
- StampMicro = "Jan _2 15:04:05.000000"
- StampNano = "Jan _2 15:04:05.000000000"
[go-text-template]: https://golang.org/pkg/text/template/
[sprig]: https://masterminds.github.io/sprig/

View file

@ -39,10 +39,10 @@ func (a *ansiUtils) init(shell string) {
switch shell {
case zsh:
a.linechange = "%%{\x1b[%d%s%%}"
a.left = "%%{\x1b[%dC%%}"
a.right = "%%{\x1b[%dD%%}"
a.right = "%%{\x1b[%dC%%}"
a.left = "%%{\x1b[%dD%%}"
a.creset = "%{\x1b[0m%}"
a.clearEOL = "%{\x1b[K%}"
a.clearEOL = "%{\x1b[0J%}"
a.saveCursorPosition = "%{\x1b7%}"
a.restoreCursorPosition = "%{\x1b8%}"
a.title = "%%{\x1b]0;%s\007%%}"
@ -59,10 +59,10 @@ func (a *ansiUtils) init(shell string) {
a.strikethrough = "%%{\x1b[9m%%}%s%%{\x1b[29m%%}"
case bash:
a.linechange = "\\[\x1b[%d%s\\]"
a.left = "\\[\x1b[%dC\\]"
a.right = "\\[\x1b[%dD\\]"
a.right = "\\[\x1b[%dC\\]"
a.left = "\\[\x1b[%dD\\]"
a.creset = "\\[\x1b[0m\\]"
a.clearEOL = "\\[\x1b[K\\]"
a.clearEOL = "\\[\x1b[0J\\]"
a.saveCursorPosition = "\\[\x1b7\\]"
a.restoreCursorPosition = "\\[\x1b8\\]"
a.title = "\\[\x1b]0;%s\007\\]"
@ -79,10 +79,10 @@ func (a *ansiUtils) init(shell string) {
a.strikethrough = "\\[\x1b[9m\\]%s\\[\x1b[29m\\]"
default:
a.linechange = "\x1b[%d%s"
a.left = "\x1b[%dC"
a.right = "\x1b[%dD"
a.right = "\x1b[%dC"
a.left = "\x1b[%dD"
a.creset = "\x1b[0m"
a.clearEOL = "\x1b[K"
a.clearEOL = "\x1b[0J"
a.saveCursorPosition = "\x1b7"
a.restoreCursorPosition = "\x1b8"
a.title = "\x1b]0;%s\007"
@ -153,12 +153,16 @@ func (a *ansiUtils) formatText(text string) string {
}
func (a *ansiUtils) carriageForward() string {
return fmt.Sprintf(a.right, 1000)
}
func (a *ansiUtils) carriageBackward() string {
return fmt.Sprintf(a.left, 1000)
}
func (a *ansiUtils) getCursorForRightWrite(text string, offset int) string {
strippedLen := a.lenWithoutANSI(text) + -offset
return fmt.Sprintf(a.right, strippedLen)
return fmt.Sprintf(a.left, strippedLen)
}
func (a *ansiUtils) changeLine(numberOfLines int) string {

View file

@ -28,6 +28,14 @@ type Config struct {
TerminalBackground string `config:"terminal_background"`
Blocks []*Block `config:"blocks"`
Tooltips []*Segment `config:"tooltips"`
TransientPrompt *TransientPrompt `config:"transient_prompt"`
}
type TransientPrompt struct {
Template string `config:"template"`
Background string `config:"background"`
Foreground string `config:"foreground"`
VerticalOffset int `config:"vertical_offset"`
}
const (
@ -80,6 +88,11 @@ func loadConfig(env environmentInfo) (*Config, error) {
return nil, errors.New("INVALID CONFIG")
}
// initialize default values
if cfg.TransientPrompt == nil {
cfg.TransientPrompt = &TransientPrompt{}
}
return &cfg, nil
}

View file

@ -40,28 +40,11 @@ func (t *consoleTitle) getConsoleTitle() string {
}
func (t *consoleTitle) getTemplateText() string {
context := make(map[string]interface{})
context["Root"] = t.env.isRunningAsRoot()
context["Path"] = t.getPwd()
context["Folder"] = base(t.getPwd(), t.env)
context["Shell"] = t.env.getShellName()
context["User"] = t.env.getCurrentUser()
context["Host"] = ""
if host, err := t.env.getHostName(); err == nil {
context["Host"] = host
}
template := &textTemplate{
Template: t.config.ConsoleTitleTemplate,
Context: context,
Env: t.env,
}
text, err := template.render()
if err != nil {
return err.Error()
}
return text
return template.renderPlainContextTemplate(nil)
}
func (t *consoleTitle) getPwd() string {

View file

@ -217,3 +217,23 @@ func (e *engine) renderTooltip(tip string) string {
}
return ""
}
func (e *engine) renderTransientPrompt(command string) string {
promptTemplate := e.config.TransientPrompt.Template
if len(promptTemplate) == 0 {
promptTemplate = "{{ .Shell }}> <#f7dc66>{{ .Command }}</>"
}
template := &textTemplate{
Template: promptTemplate,
Env: e.env,
}
context := make(map[string]interface{})
context["Command"] = command
prompt := template.renderPlainContextTemplate(context)
e.colorWriter.write(e.config.TransientPrompt.Background, e.config.TransientPrompt.Foreground, prompt)
transientPrompt := e.ansi.carriageBackward()
if e.config.TransientPrompt.VerticalOffset != 0 {
transientPrompt += e.ansi.changeLine(e.config.TransientPrompt.VerticalOffset)
}
return transientPrompt + e.colorWriter.string() + e.ansi.clearEOL
}

View file

@ -192,11 +192,24 @@ function global:Enable-PoshTooltips {
$position = $host.UI.RawUI.CursorPosition
$omp = "::OMP::"
$config, $cleanPWD, $cleanPSWD = Get-PoshContext
$tooltip = $null
$command = $null
$cursor = $null
[Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$tooltip, [ref]$cursor)
$standardOut = @(&$omp --pwd="$cleanPWD" --pswd="$cleanPSWD" --config="$config" --tooltip="$tooltip" 2>&1)
[Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$command, [ref]$cursor)
$standardOut = @(&$omp --pwd="$cleanPWD" --pswd="$cleanPSWD" --config="$config" --command="$command" 2>&1)
Write-Host $standardOut -NoNewline
$host.UI.RawUI.CursorPosition = $position
}
}
function global:Enable-PoshTransientPrompt {
Set-PSReadlineKeyHandler -Key Enter -ScriptBlock {
$command = $null
$cursor = $null
[Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$command, [ref]$cursor)
$omp = "::OMP::"
$config, $cleanPWD, $cleanPSWD = Get-PoshContext
$standardOut = @(&$omp --pwd="$cleanPWD" --pswd="$cleanPSWD" --config="$config" --command="$command" --print-transient 2>&1)
Write-Host $standardOut -NoNewline
[Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine()
}
}

View file

@ -57,7 +57,7 @@ function self-insert() {
zle .self-insert
return
fi
tooltip=$(::OMP:: --config $POSH_THEME --shell zsh --tooltip $BUFFER)
tooltip=$(::OMP:: --config $POSH_THEME --shell zsh --command $BUFFER)
# ignore an empty tooltip
if [[ ! -z "$tooltip" ]]; then
RPROMPT=$tooltip

View file

@ -37,27 +37,28 @@ const (
)
type args struct {
ErrorCode *int
PrintConfig *bool
ConfigFormat *string
PrintShell *bool
Config *string
Shell *string
PWD *string
PSWD *string
Version *bool
Debug *bool
ExecutionTime *float64
Millis *bool
Eval *bool
Init *bool
PrintInit *bool
ExportPNG *bool
Author *string
CursorPadding *int
RPromptOffset *int
StackCount *int
ToolTip *string
ErrorCode *int
PrintConfig *bool
ConfigFormat *string
PrintShell *bool
Config *string
Shell *string
PWD *string
PSWD *string
Version *bool
Debug *bool
ExecutionTime *float64
Millis *bool
Eval *bool
Init *bool
PrintInit *bool
ExportPNG *bool
Author *string
CursorPadding *int
RPromptOffset *int
StackCount *int
Command *string
PrintTransient *bool
}
func main() {
@ -142,10 +143,14 @@ func main() {
"stack-count",
0,
"The current location stack count"),
ToolTip: flag.String(
"tooltip",
Command: flag.String(
"command",
"",
"Render a tooltip based on the string value"),
"Render a tooltip based on the command value"),
PrintTransient: flag.Bool(
"print-transient",
false,
"Print the transient prompt"),
}
flag.Parse()
env := &environment{}
@ -200,8 +205,12 @@ func main() {
fmt.Print(engine.debug())
return
}
if len(*args.ToolTip) != 0 {
fmt.Print(engine.renderTooltip(*args.ToolTip))
if *args.PrintTransient {
fmt.Print(engine.renderTransientPrompt(*args.Command))
return
}
if len(*args.Command) != 0 {
fmt.Print(engine.renderTooltip(*args.Command))
return
}
prompt := engine.render()

View file

@ -24,6 +24,29 @@ type textTemplate struct {
Env environmentInfo
}
func (t *textTemplate) renderPlainContextTemplate(context map[string]interface{}) string {
if context == nil {
context = make(map[string]interface{})
}
context["Root"] = t.Env.isRunningAsRoot()
pwd := t.Env.getcwd()
pwd = strings.Replace(pwd, t.Env.homeDir(), "~", 1)
context["Path"] = pwd
context["Folder"] = base(pwd, t.Env)
context["Shell"] = t.Env.getShellName()
context["User"] = t.Env.getCurrentUser()
context["Host"] = ""
if host, err := t.Env.getHostName(); err == nil {
context["Host"] = host
}
t.Context = context
text, err := t.render()
if err != nil {
return err.Error()
}
return text
}
func (t *textTemplate) render() (string, error) {
tmpl, err := template.New("title").Funcs(sprig.TxtFuncMap()).Parse(t.Template)
if err != nil {

View file

@ -1589,6 +1589,26 @@
},
"required": ["tips"]
}
},
"transient_prompt": {
"type": "object",
"title": "Transient Prompt Settings",
"description": "https://ohmyposh.dev/docs/beta#transient-prompt",
"default": {},
"properties": {
"template": {
"type": "string",
"title": "Transient Prompt Template",
"default": "{{ .Shell }}> <#f7dc66>{{ .Command }}</>"
},
"vertical_offset": {
"type": "integer",
"title": "Transient Prompt vertical offset",
"default": 0
},
"background": { "$ref": "#/definitions/color" },
"foreground": { "$ref": "#/definitions/color" }
}
}
}
}