Skip to content

feat: modal to select a pinned directory#1345

Open
robert-zaremba wants to merge 6 commits into
yorukot:mainfrom
robert-zaremba:goto_pinned
Open

feat: modal to select a pinned directory#1345
robert-zaremba wants to merge 6 commits into
yorukot:mainfrom
robert-zaremba:goto_pinned

Conversation

@robert-zaremba
Copy link
Copy Markdown
Contributor

@robert-zaremba robert-zaremba commented Feb 3, 2026

Features

  • Press b to open the modal
  • Fuzzy search through pinned directories using fzf
  • Arrow keys (j/k/up/down) to navigate results
  • Enter to navigate to selected directory
  • Esc to close modal
  • Shows directory name and path in results
  • Properly integrates with existing file panel navigation The implementation follows the same pattern as the zoxide modal

Summary by CodeRabbit

  • New Features

    • Pinned-items modal overlay: searchable/filterable list, keyboard navigation (cursor/page), confirm/cancel, responsive sizing, and overlay rendering that blocks background input.
  • Configuration

    • New global hotkey to open the pinned modal (default: 'b') added to default and Vim hotkey configs.
  • UX

    • Help menu documents the "Goto pinned directory" hotkey; sidebar exposes pinned directories to the modal.
  • Tests

    • Unit tests added covering modal lifecycle, navigation, filtering, and query handling.

Features
- Press b to open the modal
- Fuzzy search through pinned directories using fzf
- Arrow keys (j/k/up/down) to navigate results
- Enter to navigate to selected directory
- Esc to close modal
- Shows directory name and path in results
- Properly integrates with existing file panel navigation
The implementation follows the same pattern as the zoxide modal

Signed-off-by: Robert Zaremba <robert@zaremba.ch>
Copilot AI review requested due to automatic review settings February 3, 2026 19:22
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 3, 2026

📝 Walkthrough

Walkthrough

Adds a new "pinned modal" feature: hotkey config and handling, default model initialization, model integration (update/render/overlay sizing), sidebar accessor for pinned directories, a new pinnedmodal UI package (types, lifecycle, filtering, navigation, rendering, selection), and unit tests.

Changes

Cohort / File(s) Summary
Configuration
src/internal/common/config_type.go, src/superfile_config/hotkeys.toml, src/superfile_config/vimHotkeys.toml
Added GotoPinned []string to HotkeysType and TOML mappings (goto_pinned = ['b', '']).
Model Init & Types
src/internal/default_config.go, src/internal/type.go
Added unexported pinnedModal field to model and initialized it in default config; added pinned modal import alias.
Key Handling
src/internal/key_function.go
Hotkey dispatch now handles GotoPinned by calling m.openPinnedModal().
Core Model Integration
src/internal/model.go, src/internal/model_render.go, src/internal/validation.go
Integrated pinned modal into Update routing, overlay checks, component sizing (setPinnedModalSize), overlay rendering, action application, and added pinnedModalRender() accessor and openPinnedModal() handler.
Pinned Modal UI Package
src/internal/ui/pinnedmodal/type.go, .../consts.go, .../model.go, .../navigation.go, .../render.go, .../utils.go
New package implementing Directory/Model/UpdateMsg types, constructors (DefaultModel/GenerateModel), open/close, sizing, text input handling, fuzzy filtering (GetQueryCmd), navigation, rendering, and selection emission (ModelAction on confirm).
Sidebar Integration
src/internal/ui/sidebar/sidebar.go
Added GetPinnedDirectories() to expose pinned directories with nil/disabled guards.
Help Menu
src/internal/ui/helpmenu/data.go
Added GotoPinned entry to help hotkeys list.
Tests
src/internal/ui/pinnedmodal/model_test.go
New unit tests covering model lifecycle, sizing, navigation, filtering, UpdateMsg application, and LoadPinnedDirs.

Sequence Diagram

sequenceDiagram
    participant User
    participant KeyHandler as Key Handler
    participant Model
    participant Sidebar
    participant PinnedModal as Pinned Modal
    participant Renderer

    User->>KeyHandler: press 'b' (goto_pinned)
    KeyHandler->>Model: trigger GotoPinned
    Model->>Sidebar: GetPinnedDirectories()
    Sidebar-->>Model: pinned dirs
    Model->>PinnedModal: LoadPinnedDirs(dirs)
    Model->>PinnedModal: Open()
    PinnedModal-->>Model: tea.Cmd (init)

    User->>PinnedModal: type / navigate / confirm
    PinnedModal->>PinnedModal: Filter & navigate
    PinnedModal-->>Model: UpdateMsg / ModelAction (selection)
    Model->>Model: applyPinnedModalAction()

    Model->>Renderer: updateRenderForOverlay()
    Renderer->>PinnedModal: pinnedModal.Render()
    PinnedModal-->>Renderer: rendered overlay
    Renderer-->>User: display modal
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

new feature, test related, bug fixes

Suggested reviewers

  • lazysegtree
  • yorukot

Poem

🐇 I found a pin and gave a hop,
I open doors and never stop,
A tiny list, a typed delight,
I point, you jump — in morning light,
Hooray, the pins make work feel light!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.79% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: modal to select a pinned directory' accurately describes the main feature introduced in the changeset - a new modal UI component for selecting pinned directories.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Signed-off-by: Robert Zaremba <robert@zaremba.ch>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a new “pinned directories” navigation modal (triggered via a new goto_pinned hotkey) that lets users fuzzy-search pinned directories and jump the active file panel to the selected directory, modeled after the existing zoxide modal.

Changes:

  • Introduces a new pinnedmodal UI component (model/navigation/rendering) and integrates it into the main Bubble Tea update/render flow.
  • Adds a new goto_pinned hotkey (b) to the default and vim hotkey configs and exposes it in the help menu.
  • Wires pinned-directory data from the sidebar’s pinned manager into the new modal.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
src/superfile_config/vimHotkeys.toml Adds goto_pinned hotkey mapping.
src/superfile_config/hotkeys.toml Adds goto_pinned hotkey mapping.
src/internal/validation.go Treats pinned modal as an overlay model for validation/interaction logic.
src/internal/ui/sidebar/sidebar.go Exposes pinned directories for consumption by the pinned modal.
src/internal/ui/pinnedmodal/utils.go Adds open/close/sizing helpers for the pinned modal.
src/internal/ui/pinnedmodal/type.go Defines pinned modal model/message types and directory DTO.
src/internal/ui/pinnedmodal/render.go Implements pinned modal rendering (input + results list).
src/internal/ui/pinnedmodal/navigation.go Adds cursor movement + scrolling logic for results list.
src/internal/ui/pinnedmodal/model.go Implements pinned modal update handling, filtering, and confirm action.
src/internal/ui/pinnedmodal/consts.go Adds pinned modal UI constants.
src/internal/ui/helpmenu/data.go Adds help menu entry describing the new hotkey.
src/internal/type.go Adds pinnedModal to the main model struct.
src/internal/model_render.go Adds a pinned modal render helper.
src/internal/model.go Integrates pinned modal sizing, update handling, and overlay placement; adds openPinnedModal().
src/internal/key_function.go Hooks goto_pinned hotkey to open the pinned modal.
src/internal/default_config.go Initializes the pinned modal in the default model config.
src/internal/common/config_type.go Adds GotoPinned to the hotkeys config type for TOML parsing.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/internal/ui/pinnedmodal/model.go Outdated
Comment thread src/internal/ui/pinnedmodal/model.go Outdated
Comment thread src/internal/ui/pinnedmodal/model.go Outdated
Comment on lines +71 to +75
func (m *Model) handleNormalKeyInput(msg tea.KeyMsg) tea.Cmd {
var cmd tea.Cmd
m.textInput, cmd = m.textInput.Update(msg)
m.FilterPinnedDirs(m.textInput.Value())
return cmd
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

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

handleNormalKeyInput calls FilterPinnedDirs synchronously on every keypress. FilterPinnedDirs uses utils.FzfSearch, which blocks on a results channel (see utils/fzf_utils.go) and can freeze the UI for slow queries. Consider following the zoxide modal pattern: return tea.Batch(cmd, m.GetQueryCmd(query)) and have the cmd compute results and send an UpdateMsg so the search runs asynchronously.

Copilot uses AI. Check for mistakes.
Comment thread src/internal/ui/pinnedmodal/render.go Outdated
Comment thread src/internal/ui/pinnedmodal/utils.go
Comment thread src/internal/ui/sidebar/sidebar.go
Comment thread src/internal/ui/pinnedmodal/model.go Outdated
Comment thread src/internal/ui/sidebar/sidebar.go
Comment thread src/internal/ui/pinnedmodal/model.go
Comment thread src/internal/ui/pinnedmodal/utils.go
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@src/internal/ui/pinnedmodal/model.go`:
- Around line 30-59: The HandleUpdate method currently prevents alphanumeric
list hotkeys by using the !isKeyAlphaNum guard; update HandleUpdate to check
hotkey matches for common.Hotkeys.ListUp and common.Hotkeys.ListDown (and
common.Hotkeys.Quit) before deferring to text input so alphanumeric bindings
like "j"/"k" are handled by navigateUp()/navigateDown() (and trigger
Close()/quit handling) instead of being forwarded into handleNormalKeyInput;
specifically remove or invert the isKeyAlphaNum condition around the
ListUp/ListDown cases (or move the slices.Contains checks above the default
text-input branch) and add a case to handle common.Hotkeys.Quit so the quit
hotkey is not absorbed by m.textInput.Update.
- Around line 92-124: In FilterPinnedDirs, the haystack entries are built as
"Name Location" but dirMap is keyed by dir.Location, causing lookup failures
when utils.FzfSearch returns matches keyed by the haystack string; update the
dirMap key to use the same searchText (the "Name Location" string stored in
haystack) so that match.Key can be looked up successfully (adjust the loop that
builds dirMap in Model.FilterPinnedDirs to set dirMap[searchText] = dir).

In `@src/internal/ui/pinnedmodal/render.go`:
- Around line 34-49: In Model.renderVisibleResults ensure availablePathWidth is
clamped to a non-negative value before dividing: compute availablePathWidth :=
max(0, m.width - columnWidth) and then derive leftWidth/rightWidth (e.g.,
availablePathWidth/2 and availablePathWidth - availablePathWidth/2) to pass
non-negative integers to common.TruncateTextBeginning for name and path; update
references to availablePathWidth/2 in the TruncateTextBeginning calls so both
truncation widths are safe on narrow terminals.

Comment thread src/internal/ui/pinnedmodal/model.go
Comment thread src/internal/ui/pinnedmodal/model.go Outdated
Comment thread src/internal/ui/pinnedmodal/render.go
robert-zaremba and others added 4 commits February 3, 2026 23:02
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Robert Zaremba <robert@zaremba.ch>
Signed-off-by: Robert Zaremba <robert@zaremba.ch>
Signed-off-by: Robert Zaremba <robert@zaremba.ch>
@yorukot
Copy link
Copy Markdown
Owner

yorukot commented Mar 14, 2026

@robert-zaremba Could you fix the merge conflicts? Thanks!

@yorukot yorukot added pr needs work PR needs work before it can be further reviewed/merged and removed awaiting pr review labels Mar 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr needs work PR needs work before it can be further reviewed/merged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants