Skip to content

Feature/nested groups#1

Merged
S33G merged 17 commits intomainfrom
feature/nested-groups
Jan 22, 2026
Merged

Feature/nested groups#1
S33G merged 17 commits intomainfrom
feature/nested-groups

Conversation

@S33G
Copy link
Owner

@S33G S33G commented Jan 19, 2026

🚀 Monorepo Support, subfolders & enhanced shell integration

Overview

This PR introduces comprehensive monorepo/nested project support with grouped navigation and enhanced shell integration system for the proj TUI project navigator. The implementation includes significant scanner improvements, UX enhancements, and a streamlined shell integration approach.

(I should probably have broken this PR down a bit)

🎯 Key Features

🏗️ Monorepo & Nested Project Support

  • Grouped View: Scan and display projects with 1-level nesting support
  • Smart Navigation: Navigate into project groups to see child projects
  • Enhanced Scanner: Show ALL directories (not just project indicators) for better UX
  • F5 Refresh: Manual refresh capability with group context preservation
  • Auto-reload: Automatic project list updates when navigating back from actions

🐚 Shell Integration System

  • Per-shell Integration Files: Individual shell scripts for bash, zsh, and fish
  • Smart Installer: Auto-detects current shell and downloads appropriate integration
  • Non-blocking Setup: Warns about unsupported shells but continues installation
  • Comprehensive Documentation: Setup guides and contribution instructions

📋 Changes Made

Core Scanner Enhancements

  • Enhanced scanner.go: New scanWithGroups() method for nested project detection
  • Show All Directories: Modified findChildProjects() to display all directories, not just project roots
  • Improved Project Detection: Better isProjectRoot() logic with more project indicators
  • Group Support: Added IsGroup and SubProjectCount fields to Project struct

Application Logic Updates

  • Group Navigation: Added ViewGroup state with dedicated group list view
  • Refresh Functionality: Implemented loadProjectsAndRefreshGroup() for context-aware refreshing
  • Enhanced UX: F5 key binding for manual refresh, improved navigation flow
  • Auto-reload: Automatic project list updates when returning from actions

Shell Integration Improvements

  • Individual Shell Files: Created bash.sh, zsh.sh, and fish.fish
  • Enhanced Installer: Added shell detection and automatic integration setup
  • Graceful Handling: Non-blocking warnings for unsupported shells with helpful guidance
  • Simplified Approach: Removed complex multi-shell automation in favor of focused per-shell files

Documentation & Contribution Guide

  • Installation Guide: Comprehensive shell integration setup instructions
  • Contributing Guide: Detailed guide for adding support for new shells
  • Shell Integration Examples: Manual setup examples for bash, zsh, and fish
  • Clear Contribution Path: Links to documentation for extending shell support

🎨 User Experience Improvements

Monorepo Navigation

  • Intuitive Groups: Project groups are clearly marked and navigable
  • Breadcrumb Context: Clear indication when viewing projects within a group
  • Seamless Navigation: Enter groups with Enter key, exit with Escape
  • Smart Refresh: F5 refreshes current view (main list or group) maintaining context

Shell Integration UX

  • Auto-detection: Installer automatically detects bash/zsh/fish shells
  • Clear Instructions: Step-by-step setup guidance for each supported shell
  • Helpful Errors: Unsupported shells get links to documentation and contribution guides
  • Non-blocking: Installation continues even for unsupported shells

📖 Documentation Updates

Enhanced Installation Guide (INSTALL.md)

  • Complete shell integration section with automatic and manual setup
  • Examples for bash, zsh, and fish shells
  • Troubleshooting guide for shell integration issues
  • Links to contribution documentation

Detailed Contributing Guide (CONTRIBUTING.md)

  • Comprehensive guide for adding new shell support
  • Technical implementation details and patterns
  • Testing instructions and best practices
  • List of requested shells for community contributions

Updated README (README.md)

  • Shell integration overview with supported shells list
  • Clear links to setup and contribution documentation
  • Updated feature descriptions reflecting monorepo support

🧪 Testing & Quality

Enhanced Test Coverage

  • Scanner Tests: Extended tests for grouped scanning and directory visibility
  • Git Integration Tests: Comprehensive git status and branch detection tests
  • Shell Integration: Manual testing across bash, zsh, and fish environments

Code Quality

  • Linting: All code passes golangci-lint checks
  • Error Handling: Robust error handling for shell detection and file operations
  • Resource Cleanup: Proper cleanup of temporary files and resources

🔄 Migration & Backward Compatibility

Seamless Upgrade

  • Configuration Compatibility: All existing config options remain functional
  • No Breaking Changes: Existing workflows continue to work without changes
  • Optional Features: Monorepo support activates automatically when nested projects detected

Shell Integration Migration

  • Simplified Setup: New per-shell approach is easier to maintain and extend
  • Clear Migration Path: Existing users get upgrade instructions through installer
  • Fallback Support: Works without shell integration for users who prefer it

S33G added 10 commits January 19, 2026 15:16
- Implement grouped project view with 1-level nesting for organized project categories
- Add nested folder support allowing parent directories with sub-projects to display as category headers
- Non-selectable category headers show sub-project counts and visual hierarchy
- Support for monorepo patterns with projects organized under category folders
- New Project struct fields: Depth (nesting level), SubProjectCount, IsGroup, Expanded
- Add ViewGroup for navigating into grouped projects
- Display child projects indented under parent groups with intuitive UI
- Navigation between main view and group view with proper back/forward handling
- Comprehensive documentation of grouped project feature in NESTED_PROJECTS.md
…atibility

- Implement FeatureConfig interface to allow Config to work with feature system
- Stub implementation returns false for all features (ready for future enhancement)
…ject indicators

Previously only directories containing project files (.git, package.json, etc.)
were displayed in project listings. This caused newly created empty directories
to be invisible until they contained project files, creating the appearance of
a caching issue.

Now all directories are shown in listings, with empty directories marked
appropriately (no language, no git status) to distinguish them from actual
projects while still being selectable for potential project initialization.

Resolves issue where 'when I create a new folder and re-run proj I cant see the folder'
Previously when creating a new project while viewing a group, the shouldReload
flag would only refresh the main projects list but not the group projects view.
This caused newly created projects within groups to not appear until manually
navigating back and forth.

Added loadProjectsAndRefreshGroup() method that:
- Reloads the main projects list
- Refreshes group projects if currently viewing a group
- Updates both project list and group list models
- Ensures UI consistency after project creation within groups
Fixed fundamental issue where groups only showed directories containing project
indicators (.git, package.json, etc.), causing most directories to be invisible.

Scanner changes:
- findChildProjects now shows ALL directories, not just project roots
- Empty directories are marked appropriately (no language, no git status)
- Consistent behavior with top-level directory scanning

New features:
- Added F5 and 'r' key bindings to refresh/rescan projects
- Works in both main project view and group view
- Updated help text to show refresh shortcuts

This fixes the issue where gamedev showed only 2 of 6 directories.
Clarified which display options are actually implemented vs planned:

Working options:
- showHiddenDirs: ✅ implemented
- sortBy: ✅ implemented

Documented but not yet implemented:
- showGitStatus: defined in config but not used (always shows)
- showLanguage: defined in config but not used (always shows)

Not in config struct (planned only):
- showNestedProjects: removed from example, noted as always-on
- maxScanDepth: removed from example, noted as always 1

Updated NESTED_PROJECTS.md with notes about current hardcoded behavior
vs planned configurable options.
Removed showGitStatus and showLanguage from:
- DisplayConfig struct
- DefaultConfig()
- viper defaults
- CONFIG.md documentation

These options were defined but never wired up to the display code.
Git status and language are always shown - no config needed.

Also cleaned up NESTED_PROJECTS.md to remove misleading 'planned'
configuration options that don't exist in the config struct.

Display config now only contains working options:
- showHiddenDirs: controls hidden directory visibility
- sortBy: controls project sort order
Added comprehensive shell integration for multiple shells:

New shell-integration.sh script:
- Auto-detects shell type (bash, zsh, fish, nushell, elvish, powershell)
- Automatically adds integration function to appropriate config file
- Handles edge cases like existing functions and directory creation

Enhanced install.sh:
- Added fish shell support with proper syntax
- Improved shell detection and setup flow
- Better error handling for unsupported shells

Updated documentation:
- README.md: Added fish shell integration example
- INSTALL.md: Added 6 shell examples plus auto-setup instructions
- Covers bash, zsh, fish, nushell, elvish, powershell

This addresses the issue where fish users had to manually figure out
the correct function syntax and provides broader shell ecosystem support.
Removed all shell integration setup functionality:
- Deleted scripts/shell-integration.sh (173 lines)
- Removed shell integration functions from scripts/install.sh (149 lines)
- Removed shell integration documentation from docs/INSTALL.md (115 lines)
- Removed shell integration examples from README.md (32 lines)

Total reduction: 468 lines

This simplifies the project by removing complex multi-shell integration
setup that was adding maintenance overhead.
Shell Integration Features:
- Created shell-specific integration files (bash, zsh, fish) in scripts/shells/
- Enhanced install.sh to detect current shell and download appropriate integration
- Added graceful handling for unsupported shells with helpful error messages
- Installer warns but doesn't block when shell is unsupported

Documentation Updates:
- Added comprehensive shell integration section to docs/INSTALL.md
- Enhanced docs/CONTRIBUTING.md with detailed guide for adding new shell support
- Updated README.md with shell integration overview and supported shells list
- Included links to contribution guide for extending shell support

Files Added:
- scripts/shells/bash.sh - Bash integration with wrapper function
- scripts/shells/zsh.sh - Zsh integration with wrapper function
- scripts/shells/fish.fish - Fish integration with wrapper function

Enhanced User Experience:
- Auto-detection of current shell during installation
- Automatic download and setup of shell integration files
- Clear instructions for manual setup when auto-setup fails
- Helpful links to documentation and contribution guides for unsupported shells
@codecov-commenter
Copy link

Welcome to Codecov 🎉

Once you merge this PR into your default branch, you're all set! Codecov will compare coverage reports and display results in all future pull requests.

Thanks for integrating Codecov - We've got you covered ☂️

Copy link
Contributor

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

This pull request adds comprehensive monorepo and nested project support with grouped navigation, alongside an enhanced shell integration system that supports bash, zsh, and fish shells. The changes enable users to work with project hierarchies (1-level nesting) and provide better shell integration with per-shell scripts and automatic detection.

Changes:

  • New grouped scanning functionality to detect and display nested projects (groups, monorepos)
  • Enhanced shell integration with dedicated scripts for bash, zsh, and fish shells
  • Improved UX with group navigation, refresh functionality, and visual indicators for groups/monorepos

Reviewed changes

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

Show a summary per file
File Description
scripts/shells/bash.sh New bash shell integration script with wrapper function for directory changing
scripts/shells/zsh.sh New zsh shell integration script with wrapper function for directory changing
scripts/shells/fish.fish New fish shell integration script with wrapper function for directory changing
scripts/install.sh Enhanced installer with shell auto-detection and integration setup
internal/project/scanner.go Major refactoring to support nested/grouped project scanning with 1-level depth
internal/project/scanner_test.go Minor test updates to add project markers for existing tests
internal/tui/views/project_list.go Enhanced rendering to show groups, monorepos, and nested projects with icons
internal/tui/keys.go Added refresh key binding (F5/r)
internal/app/app.go New ViewGroup state with navigation, group-aware project creation, and refresh
internal/config/config.go Removed unused display config options, added stub feature flag function
go.mod Moved cobra from indirect to direct dependency
docs/INSTALL.md Updated with comprehensive shell integration documentation
docs/CONTRIBUTING.md Added detailed guide for contributing new shell support
docs/CONFIG.md Removed documentation for deleted config options
README.md Updated with shell integration overview and supported shells

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

Comment on lines +114 to +122
// Calculate padding for alignment
visibleLen := len(prefix) + len(p.Name)
if hasChildren {
visibleLen += len(fmt.Sprintf(" (%d)", p.SubProjectCount))
}
if isGroup || hasChildren {
visibleLen += 3 // icon
}
padding := 35 - visibleLen
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

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

The padding calculation uses len() on strings that may contain emoji characters (like "📁" and "📦"). In Go, len() returns the byte count, not the visual character count. Emoji characters typically take 3-4 bytes but display as 1 character width. This will cause misalignment in the rendered output. Consider using a library that properly counts grapheme clusters or visible width (like github.com/mattn/go-runewidth).

Copilot uses AI. Check for mistakes.
Comment on lines +258 to +259
if len(actions) > insertIdx {
actions = append(actions[:insertIdx+1], append([]views.Action{childAction}, actions[insertIdx+1:]...)...)
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

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

This slice manipulation uses a complex nested append pattern that is difficult to read and error-prone. Consider using a clearer approach: create a new slice with explicit elements, or use a temporary slice to build the action list before combining.

Copilot uses AI. Check for mistakes.
Comment on lines +123 to +136
} else {
// It's a regular directory (not a project yet, but still show it)
// This allows users to see directories they create and potentially initialize as projects
proj, err := s.scanProject(entry.Name(), dirPath, 0)
if err != nil {
continue
}
// Mark as not a real project yet (no language, no git status)
proj.Language = ""
proj.IsGitRepo = false
proj.GitBranch = ""
proj.GitDirty = false
projects = append(projects, proj)
}
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

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

The scanner now shows ALL directories regardless of whether they are projects (lines 123-136). This significantly changes the UX by cluttering the project list with empty directories. Combined with the overly broad isProjectRoot check (which includes README files), this could show many unrelated directories. Consider adding a configuration option to control this behavior or being more selective about which empty directories to show.

Copilot uses AI. Check for mistakes.
Comment on lines +54 to +141
// scanWithGroups scans top level and detects groups vs projects
func (s *Scanner) scanWithGroups(basePath string) ([]*Project, error) {
entries, err := os.ReadDir(basePath)
if err != nil {
return nil, err
}

projects := make([]*Project, 0)

for _, entry := range entries {
// Skip files, only process directories
if !entry.IsDir() {
continue
}

// Skip hidden directories unless enabled
if !s.showHidden && strings.HasPrefix(entry.Name(), ".") {
continue
}

// Skip excluded patterns
if s.isExcluded(entry.Name()) {
continue
}

projectPath := filepath.Join(expandedPath, entry.Name())
dirPath := filepath.Join(basePath, entry.Name())
isProject := isProjectRoot(dirPath)

// Check if this directory contains projects (making it a group)
childProjects := s.findChildProjects(dirPath)

if isProject {
// It's a project (and possibly also contains sub-projects - monorepo)
proj, err := s.scanProject(entry.Name(), dirPath, 0)
if err != nil {
continue
}
proj.SubProjectCount = len(childProjects)
proj.Expanded = true // Projects with children are expanded by default
projects = append(projects, proj)

// Add child projects
for _, child := range childProjects {
child.ParentPath = dirPath
child.Depth = 1
projects = append(projects, child)
}
} else if len(childProjects) > 0 {
// It's a group folder (not a project itself, but contains projects)
group := &Project{
Name: entry.Name(),
Path: dirPath,
Depth: 0,
IsGroup: true,
SubProjectCount: len(childProjects),
Expanded: true,
}

// Get last modified from directory
info, _ := os.Stat(dirPath)
if info != nil {
group.LastModified = info.ModTime()
}

projects = append(projects, group)

// Add child projects
for _, child := range childProjects {
child.ParentPath = dirPath
child.Depth = 1
projects = append(projects, child)
}
} else {
// It's a regular directory (not a project yet, but still show it)
// This allows users to see directories they create and potentially initialize as projects
proj, err := s.scanProject(entry.Name(), dirPath, 0)
if err != nil {
continue
}
// Mark as not a real project yet (no language, no git status)
proj.Language = ""
proj.IsGitRepo = false
proj.GitBranch = ""
proj.GitDirty = false
projects = append(projects, proj)
}
// No longer skip any directories - show all
}

return projects, nil
}
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

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

The new grouped/nested project scanning functionality (including IsGroup, SubProjectCount, Depth, ParentPath fields and the scanWithGroups/findChildProjects methods) lacks test coverage. The existing tests in scanner_test.go were only minimally updated to add project markers but don't test the new nested/group behavior. Add comprehensive tests for group detection, monorepo scenarios, parent-child relationships, and the depth-based filtering.

Copilot uses AI. Check for mistakes.
S33G and others added 7 commits January 22, 2026 12:27
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@S33G S33G merged commit 1fa2dee into main Jan 22, 2026
3 checks passed
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.

3 participants