diff --git a/.vscode/launch.json b/.vscode/launch.json index 30669ff1..d20da3c8 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -7,7 +7,7 @@ "request": "launch", "mode": "debug", "program": "${workspaceRoot}/src", - "args": ["--config=${workspaceRoot}/themes/jandedobbeleer.omp.json"] + "args": ["--config=${workspaceRoot}/themes/jandedobbeleer.omp.json", "--shell=pwsh"] }, { "name": "Launch tests", diff --git a/src/engine.go b/src/engine.go index 4ed88023..f5052121 100644 --- a/src/engine.go +++ b/src/engine.go @@ -25,6 +25,21 @@ func (e *engine) string() string { return e.console.String() } +func (e *engine) canWriteRPrompt() bool { + prompt := e.string() + consoleWidth, err := e.env.getTerminalWidth() + if err != nil { + return true + } + promptWidth := e.ansi.lenWithoutANSI(prompt) + availableSpace := consoleWidth - promptWidth + if promptWidth > consoleWidth { + availableSpace = promptWidth - (promptWidth % consoleWidth) + } + promptBreathingRoom := 30 + return (availableSpace - e.ansi.lenWithoutANSI(e.rprompt)) >= promptBreathingRoom +} + func (e *engine) render() string { for _, block := range e.config.Blocks { e.renderBlock(block) @@ -151,7 +166,7 @@ func (e *engine) print() string { prompt += fmt.Sprintf("\nRPROMPT=\"%s\"", e.rprompt) return prompt case pwsh, powershell5, bash, plain: - if e.rprompt == "" { + if e.rprompt == "" || !e.canWriteRPrompt() { break } e.write(e.ansi.saveCursorPosition) diff --git a/src/engine_test.go b/src/engine_test.go new file mode 100644 index 00000000..8b39d62c --- /dev/null +++ b/src/engine_test.go @@ -0,0 +1,43 @@ +package main + +import ( + "errors" + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestCanWriteRPrompt(t *testing.T) { + cases := []struct { + Case string + Expected bool + TerminalWidth int + TerminalWidthError error + PromptLength int + RPromptLength int + }{ + {Case: "Width Error", Expected: true, TerminalWidthError: errors.New("burp")}, + {Case: "Terminal > Prompt enabled", Expected: true, TerminalWidth: 200, PromptLength: 100, RPromptLength: 10}, + {Case: "Terminal > Prompt enabled edge", Expected: true, TerminalWidth: 200, PromptLength: 100, RPromptLength: 70}, + {Case: "Terminal > Prompt disabled no breathing", Expected: false, TerminalWidth: 200, PromptLength: 100, RPromptLength: 71}, + {Case: "Prompt > Terminal enabled", Expected: true, TerminalWidth: 200, PromptLength: 300, RPromptLength: 70}, + {Case: "Prompt > Terminal disabled no breathing", Expected: true, TerminalWidth: 200, PromptLength: 300, RPromptLength: 80}, + {Case: "Prompt > Terminal disabled no room", Expected: true, TerminalWidth: 200, PromptLength: 400, RPromptLength: 80}, + } + + for _, tc := range cases { + env := new(MockedEnvironment) + env.On("getTerminalWidth", nil).Return(tc.TerminalWidth, tc.TerminalWidthError) + ansi := &ansiUtils{} + ansi.init(plain) + engine := &engine{ + env: env, + ansi: ansi, + } + engine.rprompt = strings.Repeat("x", tc.RPromptLength) + engine.console.WriteString(strings.Repeat("x", tc.PromptLength)) + got := engine.canWriteRPrompt() + assert.Equal(t, tc.Expected, got) + } +} diff --git a/src/environment.go b/src/environment.go index 69f178bd..2b72e3e4 100644 --- a/src/environment.go +++ b/src/environment.go @@ -16,6 +16,7 @@ import ( "github.com/distatus/battery" "github.com/shirou/gopsutil/host" "github.com/shirou/gopsutil/process" + terminal "github.com/wayneashleyberry/terminal-dimensions" ) const ( @@ -73,6 +74,7 @@ type environmentInfo interface { hasParentFilePath(path string) (fileInfo *fileInfo, err error) isWsl() bool stackCount() int + getTerminalWidth() (int, error) } type commandCache struct { @@ -323,6 +325,11 @@ func (env *environment) stackCount() int { return *env.args.StackCount } +func (env *environment) getTerminalWidth() (int, error) { + width, err := terminal.Width() + return int(width), err +} + func cleanHostName(hostName string) string { garbage := []string{ ".lan", diff --git a/src/go.mod b/src/go.mod index 4214adb5..a0d37d86 100644 --- a/src/go.mod +++ b/src/go.mod @@ -26,7 +26,8 @@ require ( github.com/stretchr/objx v0.3.0 // indirect github.com/stretchr/testify v1.7.0 github.com/tklauser/go-sysconf v0.3.5 // indirect - golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 // indirect + github.com/wayneashleyberry/terminal-dimensions v1.0.0 + golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a // indirect golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb golang.org/x/sys v0.0.0-20210324051608-47abb6519492 golang.org/x/text v0.3.5 diff --git a/src/go.sum b/src/go.sum index 94a14a0e..44385de4 100644 --- a/src/go.sum +++ b/src/go.sum @@ -101,12 +101,14 @@ github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITn github.com/tklauser/numcpus v0.2.2 h1:oyhllyrScuYI6g+h/zUvNXNp1wy7x8qQy3t/piefldA= github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM= github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= +github.com/wayneashleyberry/terminal-dimensions v1.0.0 h1:LawtS1nqKjAfqrmKOzkcrDLAjSzh38lEhC401JPjQVA= +github.com/wayneashleyberry/terminal-dimensions v1.0.0/go.mod h1:PW2XrtV6KmKOPhuf7wbtcmw1/IFnC39mryRET2XbxeE= github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w= -golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb h1:fqpd0EBDzlHRCjiphRR5Zo/RSWWQlWv34418dnEixWk= golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= diff --git a/src/segment_path_test.go b/src/segment_path_test.go index d81ea2f8..d094ed72 100644 --- a/src/segment_path_test.go +++ b/src/segment_path_test.go @@ -142,6 +142,11 @@ func (env *MockedEnvironment) isWsl() bool { return false } +func (env *MockedEnvironment) getTerminalWidth() (int, error) { + args := env.Called(nil) + return args.Int(0), args.Error(1) +} + const ( homeBill = "/home/bill" homeJan = "/usr/home/jan"