refactor: simpler prompt caching logic

This commit is contained in:
Jan De Dobbeleer 2024-07-20 23:50:26 +02:00 committed by Jan De Dobbeleer
parent c5195f6668
commit 083c204694
5 changed files with 99 additions and 99 deletions

2
src/cache/cache.go vendored
View file

@ -33,7 +33,7 @@ var (
TEMPLATECACHE = fmt.Sprintf("template_cache_%s", pid()) TEMPLATECACHE = fmt.Sprintf("template_cache_%s", pid())
TOGGLECACHE = fmt.Sprintf("toggle_cache_%s", pid()) TOGGLECACHE = fmt.Sprintf("toggle_cache_%s", pid())
PROMPTCOUNTCACHE = fmt.Sprintf("prompt_count_cache_%s", pid()) PROMPTCOUNTCACHE = fmt.Sprintf("prompt_count_cache_%s", pid())
PROMPTCACHE = fmt.Sprintf("prompt_cache_%s", pid()) ENGINECACHE = fmt.Sprintf("engine_cache_%s", pid())
) )
type Entry struct { type Entry struct {

View file

@ -16,7 +16,7 @@ import (
var cycle *color.Cycle = &color.Cycle{} var cycle *color.Cycle = &color.Cycle{}
type promptCache struct { type engineCache struct {
Prompt string Prompt string
CurrentLineLength int CurrentLineLength int
RPrompt string RPrompt string
@ -36,7 +36,9 @@ type Engine struct {
activeSegment *config.Segment activeSegment *config.Segment
previousActiveSegment *config.Segment previousActiveSegment *config.Segment
promptCache *promptCache engineCache *engineCache
cached bool
} }
func (e *Engine) write(text string) { func (e *Engine) write(text string) {
@ -510,32 +512,40 @@ func (e *Engine) adjustTrailingDiamondColorOverrides() {
} }
} }
func (e *Engine) checkPromptCache() bool { func (e *Engine) restoreEngineFromCache() bool {
data, ok := e.Env.Cache().Get(cache.PROMPTCACHE) if !e.Env.Flags().Cached {
return false
}
data, ok := e.Env.Cache().Get(cache.ENGINECACHE)
if !ok { if !ok {
return false return false
} }
e.promptCache = &promptCache{} var engineCache engineCache
err := json.Unmarshal([]byte(data), e.promptCache) err := json.Unmarshal([]byte(data), &engineCache)
if err != nil { if err != nil {
return false return false
} }
e.write(e.promptCache.Prompt) e.engineCache = &engineCache
e.currentLineLength = e.promptCache.CurrentLineLength
e.rprompt = e.promptCache.RPrompt e.write(e.engineCache.Prompt)
e.rpromptLength = e.promptCache.RPromptLength e.currentLineLength = e.engineCache.CurrentLineLength
e.rprompt = e.engineCache.RPrompt
e.rpromptLength = e.engineCache.RPromptLength
e.cached = true
return true return true
} }
func (e *Engine) updatePromptCache(value *promptCache) { func (e *Engine) updateEngineCache(value *engineCache) {
cacheJSON, err := json.Marshal(value) cacheJSON, err := json.Marshal(value)
if err != nil { if err != nil {
return return
} }
e.Env.Cache().Set(cache.PROMPTCACHE, string(cacheJSON), 1440) e.Env.Cache().Set(cache.ENGINECACHE, string(cacheJSON), 1440)
} }
// New returns a prompt engine initialized with the // New returns a prompt engine initialized with the

View file

@ -10,74 +10,10 @@ import (
) )
func (e *Engine) Primary() string { func (e *Engine) Primary() string {
needsPrimaryRPrompt := e.needsPrimaryRPrompt() needsPrimaryRightPrompt := e.needsPrimaryRightPrompt()
var ( if !e.restoreEngineFromCache() {
useCache bool e.writePrimaryPrompt(needsPrimaryRightPrompt)
updateCache bool
)
if e.Env.Shell() == shell.PWSH || e.Env.Shell() == shell.PWSH5 {
// For PowerShell, use a cached prompt if available, otherwise render a new prompt.
if e.Env.Flags().Cached && e.checkPromptCache() {
useCache = true
} else {
updateCache = true
}
}
if !useCache {
if e.Config.ShellIntegration {
exitCode, _ := e.Env.StatusCodes()
e.write(terminal.CommandFinished(exitCode, e.Env.Flags().NoExitCode))
e.write(terminal.PromptStart())
}
// cache a pointer to the color cycle
cycle = &e.Config.Cycle
var cancelNewline, didRender bool
for i, block := range e.Config.Blocks {
// do not print a leading newline when we're at the first row and the prompt is cleared
if i == 0 {
row, _ := e.Env.CursorPosition()
cancelNewline = e.Env.Flags().Cleared || e.Env.Flags().PromptCount == 1 || row == 1
}
// skip setting a newline when we didn't print anything yet
if i != 0 {
cancelNewline = !didRender
}
if block.Type == config.RPrompt && !needsPrimaryRPrompt {
continue
}
if e.renderBlock(block, cancelNewline) {
didRender = true
}
}
if len(e.Config.ConsoleTitleTemplate) > 0 && !e.Env.Flags().Plain {
title := e.getTitleTemplateText()
e.write(terminal.FormatTitle(title))
}
if e.Config.FinalSpace {
e.write(" ")
e.currentLineLength++
}
if e.Config.ITermFeatures != nil && e.isIterm() {
host, _ := e.Env.Host()
e.write(terminal.RenderItermFeatures(e.Config.ITermFeatures, e.Env.Shell(), e.Env.Pwd(), e.Env.User(), host))
}
if e.Config.ShellIntegration && e.Config.TransientPrompt == nil {
e.write(terminal.CommandStart())
}
e.pwd()
} }
switch e.Env.Shell() { switch e.Env.Shell() {
@ -88,7 +24,7 @@ func (e *Engine) Primary() string {
// Warp doesn't support RPROMPT so we need to write it manually // Warp doesn't support RPROMPT so we need to write it manually
if e.isWarp() { if e.isWarp() {
e.writePrimaryRPrompt() e.writePrimaryRightPrompt()
// escape double quotes contained in the prompt // escape double quotes contained in the prompt
prompt := fmt.Sprintf("PS1=\"%s\"", strings.ReplaceAll(e.string(), `"`, `\"`)) prompt := fmt.Sprintf("PS1=\"%s\"", strings.ReplaceAll(e.string(), `"`, `\"`))
return prompt return prompt
@ -100,27 +36,80 @@ func (e *Engine) Primary() string {
return prompt return prompt
default: default:
if updateCache { if !needsPrimaryRightPrompt {
// Cache the new prompt.
e.updatePromptCache(&promptCache{
Prompt: e.prompt.String(),
CurrentLineLength: e.currentLineLength,
RPrompt: e.rprompt,
RPromptLength: e.rpromptLength,
})
}
if !needsPrimaryRPrompt {
break break
} }
e.writePrimaryRPrompt() e.writePrimaryRightPrompt()
}
if !e.cached {
e.updateEngineCache(&engineCache{
Prompt: e.prompt.String(),
CurrentLineLength: e.currentLineLength,
RPrompt: e.rprompt,
RPromptLength: e.rpromptLength,
})
} }
return e.string() return e.string()
} }
func (e *Engine) needsPrimaryRPrompt() bool { func (e *Engine) writePrimaryPrompt(needsPrimaryRPrompt bool) {
if e.Config.ShellIntegration {
exitCode, _ := e.Env.StatusCodes()
e.write(terminal.CommandFinished(exitCode, e.Env.Flags().NoExitCode))
e.write(terminal.PromptStart())
}
// cache a pointer to the color cycle
cycle = &e.Config.Cycle
var cancelNewline, didRender bool
for i, block := range e.Config.Blocks {
// do not print a leading newline when we're at the first row and the prompt is cleared
if i == 0 {
row, _ := e.Env.CursorPosition()
cancelNewline = e.Env.Flags().Cleared || e.Env.Flags().PromptCount == 1 || row == 1
}
// skip setting a newline when we didn't print anything yet
if i != 0 {
cancelNewline = !didRender
}
if block.Type == config.RPrompt && !needsPrimaryRPrompt {
continue
}
if e.renderBlock(block, cancelNewline) {
didRender = true
}
}
if len(e.Config.ConsoleTitleTemplate) > 0 && !e.Env.Flags().Plain {
title := e.getTitleTemplateText()
e.write(terminal.FormatTitle(title))
}
if e.Config.FinalSpace {
e.write(" ")
e.currentLineLength++
}
if e.Config.ITermFeatures != nil && e.isIterm() {
host, _ := e.Env.Host()
e.write(terminal.RenderItermFeatures(e.Config.ITermFeatures, e.Env.Shell(), e.Env.Pwd(), e.Env.User(), host))
}
if e.Config.ShellIntegration && e.Config.TransientPrompt == nil {
e.write(terminal.CommandStart())
}
e.pwd()
}
func (e *Engine) needsPrimaryRightPrompt() bool {
switch e.Env.Shell() { switch e.Env.Shell() {
case shell.PWSH, shell.PWSH5, shell.GENERIC, shell.ZSH: case shell.PWSH, shell.PWSH5, shell.GENERIC, shell.ZSH:
return true return true
@ -129,7 +118,7 @@ func (e *Engine) needsPrimaryRPrompt() bool {
} }
} }
func (e *Engine) writePrimaryRPrompt() { func (e *Engine) writePrimaryRightPrompt() {
space, OK := e.canWriteRightBlock(e.rpromptLength, true) space, OK := e.canWriteRightBlock(e.rpromptLength, true)
if !OK { if !OK {
return return

View file

@ -45,10 +45,10 @@ func (e *Engine) Tooltip(tip string) string {
case shell.PWSH, shell.PWSH5: case shell.PWSH, shell.PWSH5:
defer func() { defer func() {
// If a prompt cache is available, we update the right prompt to the new tooltip for reuse. // If a prompt cache is available, we update the right prompt to the new tooltip for reuse.
if e.checkPromptCache() { if e.restoreEngineFromCache() {
e.promptCache.RPrompt = text e.engineCache.RPrompt = text
e.promptCache.RPromptLength = length e.engineCache.RPromptLength = length
e.updatePromptCache(e.promptCache) e.updateEngineCache(e.engineCache)
} }
}() }()

View file

@ -176,6 +176,7 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock {
"--column=$column" "--column=$column"
"--terminal-width=$terminalWidth" "--terminal-width=$terminalWidth"
"--no-status=$script:NoExitCode" "--no-status=$script:NoExitCode"
"--cached=$true"
) )
$standardOut = (Start-Utf8Process $script:OMPExecutable $arguments) -join '' $standardOut = (Start-Utf8Process $script:OMPExecutable $arguments) -join ''
if (!$standardOut) { if (!$standardOut) {