From 3ff23407e6d1f4c590beb7cfa842382b12264db1 Mon Sep 17 00:00:00 2001 From: Tucker Beck Date: Tue, 26 Nov 2024 17:31:00 -0800 Subject: [PATCH] feat(block): allow templates for filler text MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change allows the user to specify a template for filler so that different behavior can be configured when the block is handling an overflow. An example configuration might be: ```yaml - type: prompt alignment: right filler: "{{ if .Overflow }} {{ else }}<#3d59a1,transparent>━{{ end }}" overflow: break ``` This would draw filler text ("-") when there is no overflow and empty space when there is an overflow. --- src/prompt/engine.go | 12 ++- src/prompt/engine_test.go | 111 +++++++++++++++++++++++++++ website/docs/configuration/block.mdx | 21 +++++ 3 files changed, 143 insertions(+), 1 deletion(-) diff --git a/src/prompt/engine.go b/src/prompt/engine.go index 72829bc42f6a..2ed895aba2fe 100644 --- a/src/prompt/engine.go +++ b/src/prompt/engine.go @@ -20,9 +20,11 @@ type Engine struct { activeSegment *config.Segment previousActiveSegment *config.Segment rprompt string + Overflow config.Overflow prompt strings.Builder currentLineLength int rpromptLength int + Padding int Plain bool } @@ -157,7 +159,13 @@ func (e *Engine) shouldFill(filler string, padLength int) (string, bool) { return "", false } - if padLength <= 0 { + tmpl := &template.Text{ + Template: filler, + Context: e, + } + + var err error + if filler, err = tmpl.Render(); err != nil { return "", false } @@ -218,6 +226,7 @@ func (e *Engine) renderBlock(block *config.Block, cancelNewline bool) bool { // we can't print the right block as there's not enough room available if !OK { + e.Overflow = block.Overflow switch block.Overflow { case config.Break: e.writeNewline() @@ -234,6 +243,7 @@ func (e *Engine) renderBlock(block *config.Block, cancelNewline bool) bool { defer func() { e.currentLineLength = 0 + e.Overflow = "" }() // validate if we have a filler and fill if needed diff --git a/src/prompt/engine_test.go b/src/prompt/engine_test.go index 4cf42b30bf02..a16e41f8533e 100644 --- a/src/prompt/engine_test.go +++ b/src/prompt/engine_test.go @@ -2,9 +2,11 @@ package prompt import ( "errors" + "strings" "testing" "github.com/jandedobbeleer/oh-my-posh/src/cache" + "github.com/jandedobbeleer/oh-my-posh/src/color" "github.com/jandedobbeleer/oh-my-posh/src/config" "github.com/jandedobbeleer/oh-my-posh/src/maps" "github.com/jandedobbeleer/oh-my-posh/src/runtime" @@ -276,3 +278,112 @@ func TestGetConsoleTitleIfGethostnameReturnsError(t *testing.T) { assert.Equal(t, tc.Expected, got) } } + +func TestShouldFill(t *testing.T) { + cases := []struct { + Case string + Overflow config.Overflow + ExpectedFiller string + Block config.Block + Padding int + ExpectedBool bool + }{ + { + Case: "Plain single character with no padding", + Padding: 0, + ExpectedFiller: "", + ExpectedBool: true, + Block: config.Block{ + Overflow: config.Hide, + Filler: "-", + }, + }, + { + Case: "Plain single character with 1 padding", + Padding: 1, + ExpectedFiller: "-", + ExpectedBool: true, + Block: config.Block{ + Overflow: config.Hide, + Filler: "-", + }, + }, + { + Case: "Plain single character with lots of padding", + Padding: 200, + ExpectedFiller: strings.Repeat("-", 200), + ExpectedBool: true, + Block: config.Block{ + Overflow: config.Hide, + Filler: "-", + }, + }, + { + Case: "Plain multi-character with some padding", + Padding: 20, + ExpectedFiller: strings.Repeat("-^-", 6) + " ", + ExpectedBool: true, + Block: config.Block{ + Overflow: config.Hide, + Filler: "-^-", + }, + }, + { + Case: "Template conditional on overflow with no overflow", + Padding: 3, + ExpectedFiller: strings.Repeat("X", 3), + ExpectedBool: true, + Block: config.Block{ + Overflow: config.Hide, + Filler: "{{ if .Overflow -}} O {{- else -}} X {{- end }}", + }, + }, + { + Case: "Template conditional on overflow with an overflow", + Overflow: config.Break, + Padding: 3, + ExpectedFiller: strings.Repeat("O", 3), + ExpectedBool: true, + Block: config.Block{ + Overflow: config.Hide, + Filler: "{{ if .Overflow -}} O {{- else -}} X {{- end }}", + }, + }, + { + Case: "Template conditional on overflow break", + Overflow: config.Break, + Padding: 3, + ExpectedFiller: strings.Repeat("O", 3), + ExpectedBool: true, + Block: config.Block{ + Overflow: config.Break, + Filler: `{{ if eq .Overflow "break" -}} O {{- else -}} X {{- end }}`, + }, + }, + } + + for _, tc := range cases { + env := new(mock.Environment) + env.On("Shell").Return(shell.GENERIC) + + engine := &Engine{ + Env: env, + Overflow: tc.Overflow, + } + + template.Cache = &cache.Template{ + Shell: shell.GENERIC, + Segments: maps.NewConcurrent(), + } + template.Init(env, nil) + + terminal.Init(shell.GENERIC) + terminal.Plain = true + terminal.Colors = &color.Defaults{} + + gotFiller, gotBool := engine.shouldFill(tc.Block.Filler, tc.Padding) + + assert.Equal(t, tc.ExpectedFiller, gotFiller, tc.Case) + assert.Equal(t, tc.ExpectedBool, gotBool, tc.Case) + } +} diff --git a/website/docs/configuration/block.mdx b/website/docs/configuration/block.mdx index 41968474350f..59338a3d7c25 100644 --- a/website/docs/configuration/block.mdx +++ b/website/docs/configuration/block.mdx @@ -71,6 +71,27 @@ to be repeated to this property. Add this property to the _right_ aligned block. }} /> +Filler allows you to specify a template to tweak the text used as filler. This template behaves the same as +Segment templates, however, fewer properties are available. + +| Name | Type | Description | +| ----------- | ------ | --------------------------------------------------------------------- | +| `.Overflow` | `text` | if no overflow was needed, this is empty. Otherwise `hide` or `break` | +| `.Padding` | `int` | the computed length of the padding between left and right blocks | + +This can be very useful if you wish to use a filler text when there is no overflow and use +empty space when the right block is hidden or drawn on a newline due to overflow. + + + ### Overflow - `break`