Skip to content

feat: add preview panel with Vim-like navigation and key enhancements#18

Merged
epilande merged 13 commits intoepilande:mainfrom
est7:main
May 25, 2025
Merged

feat: add preview panel with Vim-like navigation and key enhancements#18
epilande merged 13 commits intoepilande:mainfrom
est7:main

Conversation

@est7
Copy link
Copy Markdown
Contributor

@est7 est7 commented May 9, 2025

New Features Added:

  • Additional Keyboard Shortcut: Added Ctrl+G for generating output files (as an intuitive alternative to the existing g key)
  • Preview Pane Navigation: Implemented new keyboard shortcuts for easier navigation
  • Vim-style Navigation: Enhanced vim-like controls throughout the application
  • Window Focus Switching: Added functionality to switch focus between file tree and preview pane

Modified Functionality:

  • Improved Key Sequence Detection: Refined how vim-style commands like gg are detected
  • Focus Management: Enhanced how focus is handled between different UI components
  • Visual Focus Indicators: Added highlighted borders to show which pane is currently active
  • Intuitive Focus Switching: Implemented navigation using both arrow keys and vim-style commands
  • Timed Key Sequences: Added timing detection for double-key commands (e.g., pressing g twice within 500ms triggers the gg command)

Why I Made These Changes

These improvements address several usability issues:

  1. Better User Experience: The new Ctrl+G shortcut aligns with standard patterns in other applications, making the interface more intuitive
  2. Enhanced Vim Compatibility: More reliable vim-style navigation helps users who are already familiar with vim
  3. Improved Content Browsing: Additional navigation controls in the preview pane make it easier to browse file contents without changing focus
  4. More Efficient Window Management: Focus switching between panels simplifies workflow, especially when working with complex directory structures or large files

Introduced a split-view screen where users can preview file content alongside the file tree. Added Vim-style navigation, improved key-sequence handling (e.g., 'gg', 'ctrl+g'), and support for toggling the preview panel. Updated color themes for better visibility and ensured smooth transitions between the file tree and preview panel.
Copy link
Copy Markdown
Owner

@epilande epilande left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an awesome job on these new features, and the PR is looking good! The enhanced keyboard navigation, Vim-style controls, and the new preview pane are all fantastic additions that significantly improve usability. Thanks so much for tackling these!

I've left a few specific comments on the diff, and I also noticed a couple of things while testing:

  • Layout Bug on Small Screens: On smaller terminal sizes, the file and preview panels sometimes mismatch in height, causing the layout to jump.
  • Preview in Search Mode: When in search mode (after pressing /), the preview panel doesn't seem to update when navigating up and down through the search results. It correctly updates when not in search mode.

A small housekeeping item:

  • Code Comments: Some of the existing comments might now be obvious or no longer relevant. It would be great to do a quick pass to clean those up.

Please let me know if you'd like any help with these updates or if you'd prefer me to jump in and make these adjustments – I'm happy to do so as I'm definitely keen to get these great features merged in.

Overall, this is a really great contribution, and thank you again for all your work on this!

},
cursor: 0,
showTokenCount: config.ShowTokenCount,
showPreview: true,
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's default to no preview panel. This would provide a cleaner initial view, especially for users who might not need the preview immediately

// File/directory colors
Directory: lipgloss.Color("#8caaee"), // blue
File: lipgloss.Color("#c6d0f5"), // text
File: lipgloss.Color("#f4b8e4"), // pink - more visible than text
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now, I'd prefer to keep the original file colors as they were. Perhaps we can revisit theme customizations and color visibility as a separate effort in the future if there's more feedback on it

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry, just because I couldn't see it 🙈 on my terminal theme, I have rolled back all the theme modifications.

Comment on lines +187 to +189
// Don't add background padding to the end of the line
// This makes the cursor highlight only cover the actual content
return cursorIndicator + cursorLineContent
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you share a bit about the reasoning behind this specific change? I actually prefer the highlight to go all the way across.

// Subtract minimal space for borders
adjustedWidth := totalWidth - (borderWidth * 2) // Only account for essential borders
// Allocate slightly more space to the file tree (55%) and less to preview (45%)
fileTreeWidth := int(float64(adjustedWidth) * 0.55)
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the initial implementation, perhaps we could default to an even 50/50 split for the file tree and preview pane (* 0.5).

Longer-term, making this panel split configurable by the user would be a really nice enhancement, but that can definitely be a future improvement.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also I noticed that the panel width calculation logic appears in a couple of places (here and when toggling the preview pane). To keep things DRY and make it easier to manage, could we extract this logic into a reusable helper function, maybe something like ⁠calculateLayout?

Comment on lines +157 to +177
// Special handling for 'g' key in help mode
if currentKey == "g" {
// If this is the first 'g', just record it and wait for second 'g'
if m.lastKey != "g" {
m.lastKey = "g"
m.lastKeyTime = currentTime
// Don't do anything else for the first 'g'
return m, nil
} else if (currentTime - m.lastKeyTime) < 500 {
// This is the second 'g' within time window - go to top
m.lastKey = "" // Reset after handling the sequence
m.viewport.GotoTop()
return m, nil
}
}

// For non-'g' keys in help mode, update tracking info
if currentKey != "g" {
m.lastKey = currentKey
m.lastKeyTime = currentTime
}
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The core logic for detecting the gg sequence is written twice, here and at line#255. The action taken after detecting gg differs slightly based on whether help is shown or if the file/preview pane is focused. Let's consolidate the gg sequence detection logic at the beginning of the tea.KeyMsg handler. This way, we can detect the sequence first and then determine the appropriate action based on the current state (m.showHelp, m.previewFocused). i.e.

case tea.KeyMsg:
	currentKey := msg.String()
	currentTime := utils.GetCurrentTimeMillis()
	if currentKey == "g" {
		if m.lastKey == "g" && (currentTime-m.lastKeyTime) < 500 {
			m.lastKey = ""
			if m.showHelp {
				m.viewport.GotoTop()
			} else if m.previewFocused && m.showPreview {
				m.previewViewport.GotoTop()
			} else {
				m.viewport.GotoTop()
				m.cursor = 0
				m.refreshViewportContent()
			}
			return m, nil
		} else {
			m.lastKey = "g"
			m.lastKeyTime = currentTime
			return m, nil
		}
	} else {
		m.lastKey = currentKey
		m.lastKeyTime = currentTime
	}

	if m.showHelp {
		switch currentKey {
		case "q", "esc", "?":
	// ...

m.lastKeyTime = currentTime
// Don't do anything else for the first 'g'
return m, nil
} else if (currentTime - m.lastKeyTime) < 500 {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's extract the magic number 500 to be a named constant. Something like ⁠ggKeySequenceTimeoutMs or ⁠doubleKeyTimeoutMs.

@est7
Copy link
Copy Markdown
Contributor Author

est7 commented May 14, 2025

I'll handle these issues. By the way, can we add a .grab folder and use something like toml for the configuration?

est7 added 5 commits May 14, 2025 10:18
Extracted layout calculations into a reusable `calculateLayout` method to simplify and centralize logic. Consolidated 'gg' key sequence handling for better readability and consistency.
Changed the default value of `showPreview` to `false` in the model settings. This ensures previews are no longer displayed unless explicitly enabled.
Introduce `ctrl+u` and `ctrl+d` shortcuts for half-page up and down scrolling. These commands now work both in the file tree and preview panel, ensuring a seamless navigation experience across the interface.
@epilande
Copy link
Copy Markdown
Owner

By the way, can we add a .grab folder and use something like toml for the configuration?

Yes, it should be the project name tho, i.e., .codegrab, and I agree, it should be a folder. This way we can add support for your other request #12, and the custom configuration can be .codegrab/config.toml for project-specific settings and ~/.config/codegrab/config.toml for global settings.

To keep this current PR focused on the UI and navigation enhancements you've already implemented, it would be best to address the configuration file feature in a separate PR. Perhaps you could create a new issue for it, or even tackle it in a future contribution if you're interested

est7 added 7 commits May 14, 2025 14:05
Centralized UI constants like padding, headers, and borders into `panel_constants.go` to improve reusability and clarity. Refactored layout calculations in `View` and related rendering functions for accurate sizing and alignment, accommodating both single and split-pane modes with dynamic width and height adjustments.
Refined viewport height calculations to accurately account for UI elements, avoiding last line cutoffs and extra space. Updated styles across components to ensure consistent padding and spacing, improving overall UI alignment and readability. Adjusted file tree panel header to include an emoji for a more descriptive label.
Updated header, footer, and panel height calculations to use dynamic measurements via `lipgloss.Height`. This ensures accurate spacing and prevents negative values in viewport dimensions. Improved overall layout handling for better responsiveness and visuals.
Ensure names and suffixes fit within the calculated available width by truncating overly long names and appending ellipsis. This improves layout consistency and prevents visual overflow in the UI.
Updated navigation instructions to reflect the addition of ctrl+u and ctrl+d for half-page scrolling in both the file tree and preview. Removed redundant bindings for preview navigation to improve clarity.
Added padding and styling logic to ensure full-width highlighting for the preview panel when focused. Introduced a `StylePreviewContent` function to handle content styling, maintaining consistent visual behavior. Updated the view rendering logic to incorporate these enhancements.
@est7
Copy link
Copy Markdown
Contributor Author

est7 commented May 14, 2025

@epilande Please take a look! Feel free to make any modifications to my PR, and I'll be happy to accept them.

Copy link
Copy Markdown
Owner

@epilande epilande left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @est7, apologies for the late review. This looks great! There are a few minor issues, but I'll fix those upstream. Thank you again for the contribution!

Comment on lines +454 to +459
// Handle directory icon state (open/closed)
if node.IsDir && icon == "" {
if m.collapsed[node.Path] {
icon = ""
icon = "" // Collapsed icon
} else {
icon = ""
icon = "" // Expanded icon
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, looks like the icons were accidentally removed here.

footerText := "Exit: esc" // Example footer text for height calculation
footer := ui.GetStyleHelp().Render(footerText)
footerHeight := lipgloss.Height(footer)
availableHeight := m.height - headerHeight - footerHeight
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to account for the border here to fix the help screen viewport

Suggested change
availableHeight := m.height - headerHeight - footerHeight
availableHeight := m.height - headerHeight - footerHeight - (2 * ui.BorderSize)

@epilande epilande merged commit 0184d85 into epilande:main May 25, 2025
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.

2 participants