mirror of
https://github.com/JanDeDobbeleer/oh-my-posh.git
synced 2024-11-09 20:44:03 -08:00
refactor: simpler prompt caching logic
This commit is contained in:
parent
c5195f6668
commit
083c204694
2
src/cache/cache.go
vendored
2
src/cache/cache.go
vendored
|
@ -33,7 +33,7 @@ var (
|
|||
TEMPLATECACHE = fmt.Sprintf("template_cache_%s", pid())
|
||||
TOGGLECACHE = fmt.Sprintf("toggle_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 {
|
||||
|
|
|
@ -16,7 +16,7 @@ import (
|
|||
|
||||
var cycle *color.Cycle = &color.Cycle{}
|
||||
|
||||
type promptCache struct {
|
||||
type engineCache struct {
|
||||
Prompt string
|
||||
CurrentLineLength int
|
||||
RPrompt string
|
||||
|
@ -36,7 +36,9 @@ type Engine struct {
|
|||
activeSegment *config.Segment
|
||||
previousActiveSegment *config.Segment
|
||||
|
||||
promptCache *promptCache
|
||||
engineCache *engineCache
|
||||
|
||||
cached bool
|
||||
}
|
||||
|
||||
func (e *Engine) write(text string) {
|
||||
|
@ -510,32 +512,40 @@ func (e *Engine) adjustTrailingDiamondColorOverrides() {
|
|||
}
|
||||
}
|
||||
|
||||
func (e *Engine) checkPromptCache() bool {
|
||||
data, ok := e.Env.Cache().Get(cache.PROMPTCACHE)
|
||||
func (e *Engine) restoreEngineFromCache() bool {
|
||||
if !e.Env.Flags().Cached {
|
||||
return false
|
||||
}
|
||||
|
||||
data, ok := e.Env.Cache().Get(cache.ENGINECACHE)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
e.promptCache = &promptCache{}
|
||||
err := json.Unmarshal([]byte(data), e.promptCache)
|
||||
var engineCache engineCache
|
||||
err := json.Unmarshal([]byte(data), &engineCache)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
e.write(e.promptCache.Prompt)
|
||||
e.currentLineLength = e.promptCache.CurrentLineLength
|
||||
e.rprompt = e.promptCache.RPrompt
|
||||
e.rpromptLength = e.promptCache.RPromptLength
|
||||
e.engineCache = &engineCache
|
||||
|
||||
e.write(e.engineCache.Prompt)
|
||||
e.currentLineLength = e.engineCache.CurrentLineLength
|
||||
e.rprompt = e.engineCache.RPrompt
|
||||
e.rpromptLength = e.engineCache.RPromptLength
|
||||
|
||||
e.cached = true
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (e *Engine) updatePromptCache(value *promptCache) {
|
||||
func (e *Engine) updateEngineCache(value *engineCache) {
|
||||
cacheJSON, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
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
|
||||
|
|
|
@ -10,74 +10,10 @@ import (
|
|||
)
|
||||
|
||||
func (e *Engine) Primary() string {
|
||||
needsPrimaryRPrompt := e.needsPrimaryRPrompt()
|
||||
needsPrimaryRightPrompt := e.needsPrimaryRightPrompt()
|
||||
|
||||
var (
|
||||
useCache bool
|
||||
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()
|
||||
if !e.restoreEngineFromCache() {
|
||||
e.writePrimaryPrompt(needsPrimaryRightPrompt)
|
||||
}
|
||||
|
||||
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
|
||||
if e.isWarp() {
|
||||
e.writePrimaryRPrompt()
|
||||
e.writePrimaryRightPrompt()
|
||||
// escape double quotes contained in the prompt
|
||||
prompt := fmt.Sprintf("PS1=\"%s\"", strings.ReplaceAll(e.string(), `"`, `\"`))
|
||||
return prompt
|
||||
|
@ -100,27 +36,80 @@ func (e *Engine) Primary() string {
|
|||
|
||||
return prompt
|
||||
default:
|
||||
if updateCache {
|
||||
// Cache the new prompt.
|
||||
e.updatePromptCache(&promptCache{
|
||||
Prompt: e.prompt.String(),
|
||||
CurrentLineLength: e.currentLineLength,
|
||||
RPrompt: e.rprompt,
|
||||
RPromptLength: e.rpromptLength,
|
||||
})
|
||||
}
|
||||
|
||||
if !needsPrimaryRPrompt {
|
||||
if !needsPrimaryRightPrompt {
|
||||
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()
|
||||
}
|
||||
|
||||
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() {
|
||||
case shell.PWSH, shell.PWSH5, shell.GENERIC, shell.ZSH:
|
||||
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)
|
||||
if !OK {
|
||||
return
|
||||
|
|
|
@ -45,10 +45,10 @@ func (e *Engine) Tooltip(tip string) string {
|
|||
case shell.PWSH, shell.PWSH5:
|
||||
defer func() {
|
||||
// If a prompt cache is available, we update the right prompt to the new tooltip for reuse.
|
||||
if e.checkPromptCache() {
|
||||
e.promptCache.RPrompt = text
|
||||
e.promptCache.RPromptLength = length
|
||||
e.updatePromptCache(e.promptCache)
|
||||
if e.restoreEngineFromCache() {
|
||||
e.engineCache.RPrompt = text
|
||||
e.engineCache.RPromptLength = length
|
||||
e.updateEngineCache(e.engineCache)
|
||||
}
|
||||
}()
|
||||
|
||||
|
|
|
@ -176,6 +176,7 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock {
|
|||
"--column=$column"
|
||||
"--terminal-width=$terminalWidth"
|
||||
"--no-status=$script:NoExitCode"
|
||||
"--cached=$true"
|
||||
)
|
||||
$standardOut = (Start-Utf8Process $script:OMPExecutable $arguments) -join ''
|
||||
if (!$standardOut) {
|
||||
|
|
Loading…
Reference in a new issue