Skip to content

feat: add bottom preview layout with P keybinding#800

Open
sideshowbarker wants to merge 2 commits intodlvhdr:mainfrom
sideshowbarker:feat/horizontal-split-preview
Open

feat: add bottom preview layout with P keybinding#800
sideshowbarker wants to merge 2 commits intodlvhdr:mainfrom
sideshowbarker:feat/horizontal-split-preview

Conversation

@sideshowbarker
Copy link
Copy Markdown
Contributor

@sideshowbarker sideshowbarker commented Mar 7, 2026

Add a “bottom” preview position that renders the preview pane below the main content rather than to the right. You can toggle between “right” and “bottom” with the P key while the preview is open.

New config options

defaults:
  preview:
    position: auto   # auto | right | bottom
    height: 0.40     # how tall the preview pane is (% or rows)

position

  • auto (default) — uses “right” when the terminal is wide enough for both the main content and the preview, falls back to “bottom” when the main content would have fewer than 80 columns.
  • right — preview pane to the right (vertical split).
  • bottom — preview pane below the main content (horizontal split).

height

  • how tall the preview pane is in “bottom” mode (default: 0.40). Values less than 1 are treated as a percentage of the screen height; values 1 or greater are treated as a fixed number of rows.

The P key toggles between right and bottom at runtime, without persisting the change. Fixes #107.

image image

@sideshowbarker sideshowbarker force-pushed the feat/horizontal-split-preview branch 2 times, most recently from b506d1f to 10291c0 Compare March 11, 2026 22:30
@dlvhdr
Copy link
Copy Markdown
Owner

dlvhdr commented Mar 13, 2026

I am noticing some artifacts when using the auto layout. To reproduce it I open a tmux split which causes dash to change layout to vertical.
image

Or this one when switching tabs in the sidebar:
image

But I must say the auto option is great! Previously opening a tmux pane made dash unusable.

@sideshowbarker sideshowbarker force-pushed the feat/horizontal-split-preview branch from 10291c0 to 7b777dd Compare March 14, 2026 05:16
@sideshowbarker
Copy link
Copy Markdown
Contributor Author

I am noticing some artifacts when using the auto layout. To reproduce it I open a tmux split which causes dash to change layout to vertical.

Thanks for catching that. I had a bug with calculating the width in bottom mode. Pushed a change (amended) that fixes it, and that I think should fix at least the problem in the first screenshot above. Not completely sure about the second, though.

Anyway, please give it a try and lemme know.

@dlvhdr
Copy link
Copy Markdown
Owner

dlvhdr commented Mar 21, 2026

Seems like the sidebar changes width when going between tabs

Screen.Recording.2026-03-21.at.18.03.00.mov

@sideshowbarker
Copy link
Copy Markdown
Contributor Author

Seems like the sidebar changes width when going between tabs

Pushed a fix.

Add a “bottom” preview position that renders the preview pane below the
main content rather than to the right. You can toggle between “right”
and “bottom” with the P key while the preview is open.

New config options:

  defaults.preview.position: auto | right | bottom
  defaults.preview.height: <integer>

The “auto” default picks “right” when the terminal is wide enough for
both the main content and the preview, and “bottom” otherwise. The P key
toggles the position at runtime without persisting the change.

Fixes dlvhdr#107
Bug: Preview shifts horizontally when switching between views with “s”.

Cause: ContainerStyle had no width constraint, so the rendered width
depended on column content. Different views have different column layouts,
and so different widths. JoinHorizontal put the sidebar at the end of the
section content —so in different views, it landed at a different position.

Fix: Set .Width(MainContentWidth) on the ContainerStyle in View() — so
every section renders at exactly MainContentWidth regardless of content.
@sideshowbarker sideshowbarker force-pushed the feat/horizontal-split-preview branch from 9910162 to f6d5cf7 Compare March 25, 2026 00:17
@dlvhdr
Copy link
Copy Markdown
Owner

dlvhdr commented Mar 27, 2026

@sideshowbarker seems like there are few more issues, but I'm not certain all are related to this PR.

  1. On startup the width of the input box is too narrow, leading to overflow - this one I'm not sure if it's an existing bug or not.
image

Note that once I switch tabs the issue goes away.

  1. If I move to the 2nd tab -> wait for all messages to finish so the UI is static -> open a 2nd window to the right - then the sidebar's header width is wrong. Also fixed by any message.
image

@sideshowbarker
Copy link
Copy Markdown
Contributor Author

@dlvhdr Can you please try with the following patch applied, and let me know the patch fixes the problems?

diff --git a/internal/tui/components/search/search.go b/internal/tui/components/search/search.go
index e5872a2..4cb3c70 100644
--- a/internal/tui/components/search/search.go
+++ b/internal/tui/components/search/search.go
@@ -75,6 +75,7 @@ func (m Model) View(ctx *context.ProgramContext) string {
 	return lipgloss.NewStyle().
 		Border(lipgloss.RoundedBorder()).
 		BorderForeground(m.ctx.Theme.PrimaryBorder).
+		MaxWidth(ctx.MainContentWidth - ctx.Styles.Section.ContainerPadding*2).
 		Render(m.textInput.View())
 }
 
@@ -102,14 +103,19 @@ func (m *Model) UpdateProgramContext(ctx *context.ProgramContext) {
 }
 
 func (m *Model) getInputWidth(ctx *context.ProgramContext) int {
-	// leave space for at least 2 characters - one character of the input and 1 for the cursor
-	// - deduce 4 - 2 for the padding, 2 for the borders
-	// - deduce 1 for the cursor
-	// - deduce 1 for the spacing between the prompt and text
+	// Available width inside the bordered search box:
+	//   MainContentWidth
+	//   - ContainerPadding*2 (section container left+right padding)
+	//   - 2 (border left+right)
+	//   - prompt width
+	//   - 1 (cursor)
+	//   - 1 (spacing between prompt and text)
 	return max(
 		2,
-		ctx.MainContentWidth-lipgloss.Width(m.textInput.Prompt)-4-1-1,
-	) // borders + cursor
+		ctx.MainContentWidth-ctx.Styles.Section.ContainerPadding*2-2-lipgloss.Width(
+			m.textInput.Prompt,
+		)-1-1,
+	)
 }
 
 func (m Model) Value() string {

@dlvhdr
Copy link
Copy Markdown
Owner

dlvhdr commented Mar 27, 2026

@sideshowbarker seems a bit worse as now switching tabs doesn't fix the search width and the right border is cut off
image

The 2nd bug was not solved

@sideshowbarker
Copy link
Copy Markdown
Contributor Author

Another attempt:

diff --git a/internal/tui/components/search/search.go b/internal/tui/components/search/search.go
index e5872a2..bdcba62 100644
--- a/internal/tui/components/search/search.go
+++ b/internal/tui/components/search/search.go
@@ -75,6 +75,7 @@ func (m Model) View(ctx *context.ProgramContext) string {
 	return lipgloss.NewStyle().
 		Border(lipgloss.RoundedBorder()).
 		BorderForeground(m.ctx.Theme.PrimaryBorder).
+		Width(ctx.MainContentWidth - ctx.Styles.Section.ContainerPadding*2).
 		Render(m.textInput.View())
 }
 
@@ -102,14 +103,17 @@ func (m *Model) UpdateProgramContext(ctx *context.ProgramContext) {
 }
 
 func (m *Model) getInputWidth(ctx *context.ProgramContext) int {
-	// leave space for at least 2 characters - one character of the input and 1 for the cursor
-	// - deduce 4 - 2 for the padding, 2 for the borders
-	// - deduce 1 for the cursor
-	// - deduce 1 for the spacing between the prompt and text
+	// .Width() on the bordered style sets total rendered width (including
+	// borders), so the content area is total - 2 (left+right border).
+	//   totalWidth = MainContentWidth - ContainerPadding*2
+	//   contentArea = totalWidth - 2
+	//   inputWidth = contentArea - promptWidth - cursor - spacing
 	return max(
 		2,
-		ctx.MainContentWidth-lipgloss.Width(m.textInput.Prompt)-4-1-1,
-	) // borders + cursor
+		ctx.MainContentWidth-ctx.Styles.Section.ContainerPadding*2-2-lipgloss.Width(
+			m.textInput.Prompt,
+		)-1-1,
+	)
 }
 
 func (m Model) Value() string {

@dlvhdr
Copy link
Copy Markdown
Owner

dlvhdr commented Mar 30, 2026

It's better @sideshowbarker, but still has issues.
Are you not near a computer to test it or can't reproduce it?

  • On initial rendering, the search takes a height of 2 if you have lots of filters.
  • The sidebar content doesn't respond to width changes (see image)
  • Can we make the separator between the list and the sidebar a double width border?
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support Horizontal split preview

2 participants