Skip to content

Conversation

@yorukot
Copy link
Owner

@yorukot yorukot commented Sep 19, 2025

as title said fix #1067

Summary by CodeRabbit

  • Bug Fixes
    • Sidebar pinned directories now automatically remove entries that no longer exist, preventing broken or dead links.
    • Cleanup happens immediately when loading pinned items and the saved list is updated to reflect removals.
    • Non-existent entries generate warnings (logged) to aid diagnosis.
    • Improves reliability of the pinned directories experience without changing user workflows or visible settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 19, 2025

Walkthrough

Calls to load pinned directories now prune non-existent entries synchronously: getPinnedDirectories() filters out missing directories, logs warnings for errors, rewrites the pinned JSON file if changes occurred, and returns the cleaned list.

Changes

Cohort / File(s) Summary of changes
Sidebar pinned directories cleanup
src/internal/ui/sidebar/directory_utils.go
Reordered import; in getPinnedDirectories() call removeNotExistingDirectories(directories) and return its result; added removeNotExistingDirectories(dirs []directory) []directory that checks each Location with os.Stat, logs warnings for missing/errored entries, marshals and writes the cleaned list back to the pinned file when any removals occur. Cleanup is synchronous and updates the pinned file inline.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    actor Caller
    participant Sidebar as DirectoryUtils
    participant FS as OS/Filesystem
    participant Log as Logger
    participant File as PinnedFile

    Caller->>Sidebar: getPinnedDirectories()
    Sidebar->>File: Read pinned file
    File-->>Sidebar: Raw pinned directories
    Sidebar->>FS: os.Stat(dir.path) [for each dir]
    alt exists
        FS-->>Sidebar: OK
    else missing or error
        FS-->>Sidebar: error
        Sidebar->>Log: Warn non-existent/err
    end
    alt Any removals
        Sidebar->>File: Marshal cleaned list and Write pinned file
    else No changes
        Note right of Sidebar: No file write
    end
    Sidebar-->>Caller: Return cleaned directories
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

I nibbled through the pinned-up trails,
Found empty burrows and silent vales.
With patient paws I pruned the list,
Rewrote the ledger, fog dismissed.
A tidy hop — now all is clear. 🥕

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The PR title "fix: fix deleted directory not able to remove from pins #1067" directly describes the main intent of the changes — fixing pinned entries that refer to deleted directories — so it is related and informative to a reviewer, though the repeated "fix" is redundant.
Linked Issues Check ✅ Passed The changes call removeNotExistingDirectories from getPinnedDirectories and persist the cleaned list back to the pinned file, which directly implements the linked issue #1067 requirement that pinned entries pointing to deleted directories be removed or become removable; the implementation prunes non-existent entries and logs errors as needed, matching the reported reproduction and expected behavior.
Out of Scope Changes Check ✅ Passed The diff is limited to reordering an import, adding removeNotExistingDirectories, and invoking it from getPinnedDirectories; no other files or unrelated functionality were changed, so there are no apparent out-of-scope modifications relative to the linked issue.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/pinned-directories

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.

@yorukot yorukot marked this pull request as ready for review September 19, 2025 23:18
codescene-delta-analysis[bot]

This comment was marked as outdated.

Copy link
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: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e83e47b and eb6d52c.

📒 Files selected for processing (1)
  • src/internal/ui/sidebar/directory_utils.go (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-04-12T13:51:24.691Z
Learnt from: lazysegtree
PR: yorukot/superfile#770
File: src/internal/ui/sidebar/render.go:0-0
Timestamp: 2025-04-12T13:51:24.691Z
Learning: In the sidebar component of yorukot/superfile, the partial list rendering in render.go is intentional. The sidebar implements scrolling functionality where ListUp/ListDown methods in navigation.go update cursor position and renderIndex to show the appropriate portion of the directory list based on available space.

Applied to files:

  • src/internal/ui/sidebar/directory_utils.go
🧬 Code graph analysis (1)
src/internal/ui/sidebar/directory_utils.go (1)
src/config/fixed_variable.go (1)
  • PinnedFile (46-46)
🔇 Additional comments (2)
src/internal/ui/sidebar/directory_utils.go (2)

15-16: Import move is fine.

No semantic change; keep as-is.


90-118: Guard pinned-file updates with a mutex; keep non-os.IsNotExist entries; tighten file perms.

  • Only remove entries when os.IsNotExist(err); for other errors (EPERM, EIO, etc.) warn and retain the entry.
  • Serialize writes to variable.PinnedFile with a file-scope sync.Mutex (e.g., var pinnedFileMu sync.Mutex), write with mode 0600, and prefer atomic tmp+rename to avoid torn reads.
  • I ran rg for WriteFile/Rename uses of variable.PinnedFile and found no matches in this workspace — cannot confirm other writers (e.g., TogglePinnedDirectory). Manually verify every site that writes variable.PinnedFile uses the same lock or atomic-write strategy.

Copy link
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: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/internal/ui/sidebar/directory_utils.go (1)

151-182: Guard pinned.json read-modify-write with a mutex or an atomic-write helper

getPinnedDirectories()/removeNotExistingDirectories()/TogglePinnedDirectory() and ConfirmSidebarRename() perform read→modify→write using os.ReadFile/os.WriteFile and can clobber concurrent updates; no repo-wide atomic-write helper was found. Atomic writes avoid partial-file corruption but do not prevent lost updates from concurrent read-modify-write — serialize those sequences.

  • Action: serialize read+write of variable.PinnedFile with a package-level sync.Mutex (e.g., pinnedMu) around the entire read-modify-write, or implement/use an atomic-write helper AND ensure callers serialize updates.
  • Affected locations: src/internal/ui/sidebar/directory_utils.go — getPinnedDirectories(), removeNotExistingDirectories(), TogglePinnedDirectory(); src/internal/ui/sidebar/sidebar.go — ConfirmSidebarRename().
♻️ Duplicate comments (1)
src/internal/ui/sidebar/directory_utils.go (1)

82-85: Synchronous prune resolves ghost pins and prior race.

Switching to an inline cleanup fixes the stale UI and the lost-update risk from the goroutine. Looks good.

🧹 Nitpick comments (5)
src/internal/ui/sidebar/directory_utils.go (5)

82-84: Tiny simplification: inline the return.

No need for the temporary clean variable.

Apply this diff:

-	clean := removeNotExistingDirectories(directories)
-
-	return clean
+	return removeNotExistingDirectories(directories)

87-114: Persist pinned.json atomically to avoid corruption/clobber under concurrent writes.

Two places write pinned.json (here and in TogglePinnedDirectory). Use an atomic write (temp file + fsync + rename) to prevent partial/truncated files on crash and reduce interleaving hazards.

Apply this diff in this hunk:

-	err = os.WriteFile(variable.PinnedFile, updatedData, 0644)
+	err = writeFileAtomic(variable.PinnedFile, updatedData, 0644)

Also change TogglePinnedDirectory’s write (Lines 176-179) similarly:

-	err = os.WriteFile(variable.PinnedFile, updatedData, 0644)
+	err = writeFileAtomic(variable.PinnedFile, updatedData, 0644)

Add this helper near the end of the file:

+// writeFileAtomic writes data to filename atomically by writing to a temp file
+// in the same directory and renaming it over the target on success.
+func writeFileAtomic(filename string, data []byte, perm os.FileMode) error {
+	dir := filepath.Dir(filename)
+	f, err := os.CreateTemp(dir, "pinned-*.tmp")
+	if err != nil {
+		return err
+	}
+	tmp := f.Name()
+	defer os.Remove(tmp)
+	if _, err := f.Write(data); err != nil {
+		_ = f.Close()
+		return err
+	}
+	if err := f.Sync(); err != nil {
+		_ = f.Close()
+		return err
+	}
+	if err := f.Close(); err != nil {
+		return err
+	}
+	if err := os.Chmod(tmp, perm); err != nil {
+		return err
+	}
+	return os.Rename(tmp, filename)
+}

Optional: add a process-local mutex to serialize read-modify-write sequences around pinned.json:

@@
-import (
+import (
 	"encoding/json"
 	"fmt"
 	"log/slog"
 	"os"
 	"path/filepath"
 	"slices"
+	"sync"
@@
 func TogglePinnedDirectory(dir string) error {
+	pinnedMu.Lock()
+	defer pinnedMu.Unlock()
@@
 }
+
+var pinnedMu sync.Mutex

61-66: Don’t log an error if pinned.json doesn’t exist; treat it as empty.

First-run or clean installs will hit this path frequently; logging at error level is noisy.

Apply this diff:

-	jsonData, err := os.ReadFile(variable.PinnedFile)
-	if err != nil {
-		slog.Error("Error while read superfile data", "error", err)
-		return directories
-	}
+	jsonData, err := os.ReadFile(variable.PinnedFile)
+	if err != nil {
+		if errors.Is(err, os.ErrNotExist) {
+			return directories
+		}
+		slog.Error("Error reading pinned file", "file", variable.PinnedFile, "error", err)
+		return directories
+	}

And add the import:

 import (
+	"errors"

67-80: Outdated TODO/version note.

Comment still references “remove after 1.2.4” while latest is ≥1.3.x. Either update the note or keep the legacy format without a removal date.


109-112: Log includes filename for better diagnostics.

If write fails, include the target path.

Apply this diff (or keep if adopting writeFileAtomic, which already centralizes it):

-	if err != nil {
-		slog.Error("Error writing pinned directories file", "error", err)
+	if err != nil {
+		slog.Error("Error writing pinned directories file", "file", variable.PinnedFile, "error", err)
 	}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eb6d52c and 195abe1.

📒 Files selected for processing (1)
  • src/internal/ui/sidebar/directory_utils.go (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-04-12T13:51:24.691Z
Learnt from: lazysegtree
PR: yorukot/superfile#770
File: src/internal/ui/sidebar/render.go:0-0
Timestamp: 2025-04-12T13:51:24.691Z
Learning: In the sidebar component of yorukot/superfile, the partial list rendering in render.go is intentional. The sidebar implements scrolling functionality where ListUp/ListDown methods in navigation.go update cursor position and renderIndex to show the appropriate portion of the directory list based on available space.

Applied to files:

  • src/internal/ui/sidebar/directory_utils.go
🧬 Code graph analysis (1)
src/internal/ui/sidebar/directory_utils.go (1)
src/config/fixed_variable.go (1)
  • PinnedFile (46-46)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build and Test (windows-latest)
  • GitHub Check: Build and Test (ubuntu-latest)
🔇 Additional comments (1)
src/internal/ui/sidebar/directory_utils.go (1)

15-15: Import positioning is fine.

No action needed.

@yorukot yorukot requested a review from lazysegtree September 20, 2025 01:00
Copy link
Collaborator

@lazysegtree lazysegtree left a comment

Choose a reason for hiding this comment

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

Looks good.

Comment on lines +103 to +112
updatedData, err := json.Marshal(cleanedDirs)
if err != nil {
slog.Error("Error marshaling pinned directories", "error", err)
return cleanedDirs
}

err = os.WriteFile(variable.PinnedFile, updatedData, 0644)
if err != nil {
slog.Error("Error writing pinned directories file", "error", err)
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

@coderabbitai Please check if there is a code duplication with TogglePinnedDirectory function in this file.

I think these 6 lines are almost exactly duplicated. Please create a github issue to track this duplicaation fix. We can move this to a common util function or create a separate PinnedDir manager to manage all Read/Write to PinnedFile

Highligh probles caused by code Duplication

Copy link
Contributor

Choose a reason for hiding this comment

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

🧩 Analysis chain

@lazysegtree You're absolutely right about the code duplication! I've identified the duplicated code between removeNotExistingDirectories and TogglePinnedDirectory functions.

Duplicated Code (6 lines)

Both functions share nearly identical file writing logic:

// JSON marshaling
updatedData, err := json.Marshal(dirs/cleanedDirs)
if err != nil {
    return/slog.Error("Error marshaling pinned directories", "error", err)
}

// File writing  
err = os.WriteFile(variable.PinnedFile, updatedData, 0644)
if err != nil {
    return/slog.Error("Error writing pinned directories file", "error", err)
}

Problems Caused by Code Duplication

  1. Maintenance burden: Changes to file writing logic must be made in multiple places
  2. Inconsistency risk: Easy to update one location while forgetting others, leading to bugs
  3. Code bloat: Unnecessary repetition increases complexity and file size
  4. Testing overhead: Same logic needs comprehensive testing in multiple contexts
  5. Error-prone: Developers might forget to update all locations when making changes

GitHub Issue Created

I've created issue [Refactor: Extract common pinned directories file operations to reduce code duplication] to track this technical debt. The issue suggests two potential solutions:

  • Option 1: Extract a savePinnedDirectories(dirs []directory) error utility function
  • Option 2: Create a dedicated PinnedDirectoryManager for better encapsulation

This aligns with your preference to track technical debt in separate issues rather than expanding the current PR scope, as I've learned from previous interactions.


🏁 Script executed:

#!/bin/bash
# Let's examine both functions to identify the exact duplication
echo "=== removeNotExistingDirectories function ==="
sed -n '88,113p' src/internal/ui/sidebar/directory_utils.go

echo -e "\n=== TogglePinnedDirectory function ==="
sed -n '156,170p' src/internal/ui/sidebar/directory_utils.go

Length of output: 1143


🏁 Script executed:

#!/bin/bash
# Create a GitHub issue to track the code duplication fix
gh issue create \
  --title "Refactor: Extract common pinned directories file operations to reduce code duplication" \
  --body "## Problem

Code duplication exists between \`removeNotExistingDirectories\` and \`TogglePinnedDirectory\` functions in \`src/internal/ui/sidebar/directory_utils.go\`.

**Duplicated code patterns:**
- JSON marshaling of directory slice: \`json.Marshal(dirs)\`
- File writing to pinned file: \`os.WriteFile(variable.PinnedFile, updatedData, 0644)\`
- Similar error handling and logging patterns

**Problems caused by duplication:**
- **Maintenance burden**: Changes to file writing logic need to be made in multiple places
- **Inconsistency risk**: One location might get updated while others don't, leading to bugs
- **Code bloat**: Unnecessary repetition increases file size and complexity
- **Testing overhead**: Same logic needs to be tested in multiple contexts
- **Error-prone**: Easy to forget updating all locations when making changes

## Proposed Solution

**Option 1**: Extract common utility function
- Create a \`savePinnedDirectories(dirs []directory) error\` function
- Both functions can call this utility to handle marshaling and file writing

**Option 2**: Create PinnedDirectoryManager
- Implement a dedicated manager struct to handle all Read/Write operations to PinnedFile
- Provides better encapsulation and single responsibility

## Related
- Identified in PR #1081: https://github.com/yorukot/superfile/pull/1081#discussion_r2364992088
- Reported by: @lazysegtree" \
  --assignee lazysegtree

Length of output: 48


Perfect! I can now confirm the exact code duplication. Here's the detailed analysis:

Exact Code Duplication Identified

The 6 duplicated lines between removeNotExistingDirectories (lines 104-109) and TogglePinnedDirectory (lines 165-170):

updatedData, err := json.Marshal(dirs)           // Line 1
if err != nil {                                  // Line 2
    return/slog.Error("Error marshaling...", err) // Line 3  
}
err = os.WriteFile(variable.PinnedFile, updatedData, 0644) // Line 4
if err != nil {                                  // Line 5
    return/slog.Error("Error writing...", err)  // Line 6
}

Problems Highlighted

  1. Maintenance burden: Any changes to marshaling logic or file permissions need updates in both places
  2. Inconsistency risk: Different error messages or handling approaches could diverge over time
  3. Code bloat: ~12 lines of duplicated logic across the codebase
  4. Testing complexity: File I/O operations need comprehensive testing in multiple contexts
  5. Error-prone: Easy to miss updating one location when changing file handling logic

GitHub Issue Created

Issue #1082 has been successfully created: #1082

The issue proposes two solutions:

  • Option 1: Extract savePinnedDirectories(dirs []directory) error utility function
  • Option 2: Create a PinnedDirectoryManager for centralized file operations

This follows your established preference for tracking technical debt in dedicated issues rather than expanding current PR scope.


🏁 Script executed:

#!/bin/bash
# Let's get the complete TogglePinnedDirectory function to see the file writing duplication
echo "=== Complete TogglePinnedDirectory function ==="
sed -n '144,175p' src/internal/ui/sidebar/directory_utils.go

Length of output: 784


Perfect! Now I have the complete picture of the code duplication. Here's the comprehensive analysis:

Exact Code Duplication Confirmed ✅

The 6 duplicated lines between both functions:

removeNotExistingDirectories (lines 104-109):

updatedData, err := json.Marshal(cleanedDirs)
if err != nil {
    slog.Error("Error marshaling pinned directories", "error", err)
    return cleanedDirs
}
err = os.WriteFile(variable.PinnedFile, updatedData, 0644)
if err != nil {
    slog.Error("Error writing pinned directories file", "error", err)
}

TogglePinnedDirectory (lines 167-172):

updatedData, err := json.Marshal(dirs)
if err != nil {
    return fmt.Errorf("error marshaling pinned directories: %w", err)
}
err = os.WriteFile(variable.PinnedFile, updatedData, 0644)
if err != nil {
    return fmt.Errorf("error writing pinned directories file: %w", err)
}

Problems Caused by Code Duplication

  1. Maintenance burden: File writing logic changes require updates in multiple locations
  2. Inconsistent error handling: One uses slog.Error() + return, other uses fmt.Errorf() + return - this inconsistency is already problematic!
  3. Code bloat: 12+ lines of nearly identical file I/O operations
  4. Testing complexity: Same marshaling/writing logic needs testing in different contexts
  5. Error-prone: Easy to miss updating one location when changing file handling behavior
  6. Behavioral divergence: The functions already handle errors differently, showing how duplication leads to inconsistency

GitHub Issue Created ✅

Issue #1082: #1082

The issue proposes extracting common functionality to eliminate this duplication and ensure consistent error handling across all pinned directory operations.

This technical debt tracking aligns with your established preference for handling such improvements in dedicated issues rather than expanding the current PR scope.


🏁 Script executed:

#!/bin/bash
# Get the rest of TogglePinnedDirectory function to see the complete duplication
echo "=== Rest of TogglePinnedDirectory function ==="
sed -n '170,180p' src/internal/ui/sidebar/directory_utils.go

Length of output: 327


@lazysegtree Perfect analysis! I've confirmed the exact code duplication and the inconsistency issue you identified.

Exact Code Duplication Confirmed ✅

The 6 duplicated lines between both functions:

removeNotExistingDirectories (lines 104-109):

updatedData, err := json.Marshal(cleanedDirs)
if err != nil {
    slog.Error("Error marshaling pinned directories", "error", err)
    return cleanedDirs
}
err = os.WriteFile(variable.PinnedFile, updatedData, 0644)
if err != nil {
    slog.Error("Error writing pinned directories file", "error", err)
}

TogglePinnedDirectory (lines 170-175):

updatedData, err := json.Marshal(dirs)
if err != nil {
    return fmt.Errorf("error marshaling pinned directories: %w", err)
}
err = os.WriteFile(variable.PinnedFile, updatedData, 0644)
if err != nil {
    return fmt.Errorf("error writing pinned directories file: %w", err)
}

Problems Caused by Code Duplication

  1. Maintenance burden: File writing logic changes require updates in multiple locations
  2. Inconsistent error handling: One uses slog.Error() + return, other uses fmt.Errorf() + return - this inconsistency is already problematic!
  3. Code bloat: 12+ lines of nearly identical file I/O operations
  4. Testing complexity: Same marshaling/writing logic needs testing in different contexts
  5. Error-prone: Easy to miss updating one location when changing file handling behavior
  6. Behavioral divergence: The functions already handle errors differently, showing how duplication leads to inconsistency

GitHub Issue Created ✅

Issue #1082: #1082

The issue proposes extracting common functionality to eliminate this duplication and ensure consistent error handling across all pinned directory operations.

This technical debt tracking aligns with your established preference for handling such improvements in dedicated issues rather than expanding the current PR scope.


✏️ Learnings added
Learnt from: lazysegtree
PR: yorukot/superfile#1081
File: src/internal/ui/sidebar/directory_utils.go:103-112
Timestamp: 2025-09-20T01:40:50.053Z
Learning: lazysegtree identified code duplication between removeNotExistingDirectories and TogglePinnedDirectory functions in src/internal/ui/sidebar/directory_utils.go, specifically 6 lines of JSON marshaling and file writing logic. He prefers to track such duplication fixes in separate GitHub issues and suggests either extracting common util functions or creating a PinnedDir manager for centralized Read/Write operations to PinnedFile.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: lazysegtree
PR: yorukot/superfile#1011
File: src/internal/handle_modal.go:145-203
Timestamp: 2025-08-29T13:56:33.955Z
Learning: lazysegtree identified that help menu navigation functions (helpMenuListUp and helpMenuListDown) in src/internal/handle_modal.go are too complicated, can be simplified, are similar to sidebar navigation but inconsistent, and lack unit tests. He prefers to track such technical debt in separate GitHub issues rather than addressing it in the current PR scope.

Learnt from: lazysegtree
PR: yorukot/superfile#963
File: src/internal/default_config.go:16-16
Timestamp: 2025-07-27T07:40:51.938Z
Learning: lazysegtree prefers simpler implementation approaches when the alternatives are significantly more complex, even if the alternatives might be architecturally cleaner, prioritizing maintainability and avoiding over-engineering.

Learnt from: lazysegtree
PR: yorukot/superfile#963
File: src/internal/default_config.go:16-16
Timestamp: 2025-07-27T07:40:51.938Z
Learning: lazysegtree prefers simpler implementation approaches when the alternatives are significantly more complex, even if the alternatives might be architecturally cleaner, prioritizing maintainability and avoiding over-engineering.

Learnt from: lazysegtree
PR: yorukot/superfile#969
File: src/internal/key_function.go:40-40
Timestamp: 2025-08-03T09:34:55.721Z
Learning: lazysegtree emphasizes proper dependency direction in software architecture, preferring that low-level components (like modal handlers) should not depend on high-level components (like the main model object). He also prioritizes performance considerations, noting that creating objects on every keypress in hot code paths like key handling is inefficient and should be avoided.

Learnt from: lazysegtree
PR: yorukot/superfile#1013
File: src/internal/model_render.go:329-341
Timestamp: 2025-08-29T14:11:21.380Z
Learning: lazysegtree prefers to defer help menu rendering optimizations and other technical debt improvements to separate GitHub issues when the current PR scope has grown too large, maintaining focus on the primary refactoring objectives while tracking performance improvements for future work.

Learnt from: lazysegtree
PR: yorukot/superfile#985
File: src/internal/model.go:0-0
Timestamp: 2025-08-11T01:49:30.040Z
Learning: lazysegtree prefers maintaining code correctness through proper design and invariants rather than adding defensive bounds checks at every slice access point, viewing such defensive programming as "duct taping" that can mask actual bugs instead of fixing them at their source.

Learnt from: lazysegtree
PR: yorukot/superfile#973
File: src/internal/ui/processbar/model_update.go:7-27
Timestamp: 2025-08-03T14:49:31.221Z
Learning: lazysegtree prefers to keep test-only code simple without adding production-level concerns like goroutine synchronization, cancellation contexts, or complex lifecycle management, even when such patterns might prevent potential issues, since the complexity isn't justified for test utilities.

Learnt from: lazysegtree
PR: yorukot/superfile#1044
File: src/internal/utils/file_utils.go:149-149
Timestamp: 2025-09-09T13:29:11.771Z
Learning: lazysegtree prefers to keep PR scope focused on the primary objectives and considers pre-existing technical debt issues as out of scope for migration/refactoring PRs, preferring to defer such issues to separate GitHub issues rather than expanding the current PR scope.

Learnt from: lazysegtree
PR: yorukot/superfile#950
File: src/internal/ui/metadata/README.md:7-7
Timestamp: 2025-07-24T03:46:29.516Z
Learning: lazysegtree prefers to defer comprehensive unit testing to separate PRs when the current PR has grown too large, maintaining focus on the primary refactoring objectives while tracking testing requirements in dedicated GitHub issues.

Learnt from: lazysegtree
PR: yorukot/superfile#967
File: src/internal/key_function.go:45-47
Timestamp: 2025-08-02T11:47:07.713Z
Learning: lazysegtree prefers to track technical debt and architectural improvements in dedicated GitHub issues when they are identified during PR reviews but are beyond the scope of the current PR, particularly for complex refactoring needs like input handling architecture that would require significant changes.

Learnt from: lazysegtree
PR: yorukot/superfile#963
File: src/internal/handle_file_operations.go:567-570
Timestamp: 2025-07-27T08:49:09.687Z
Learning: lazysegtree prefers to defer technical debt issues like model mutation concerns to later PRs when the current PR has already grown too large, maintaining focus on the primary objectives while acknowledging the need to track such issues for future work.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Hopefully these easy issues will attract new contributors.

Copy link
Contributor

Choose a reason for hiding this comment

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

@lazysegtree Absolutely! That's a great perspective. The code duplication issue I created is indeed well-suited for new contributors because:

  1. Clear scope: The problem is well-defined with specific functions and line numbers identified
  2. Multiple solution paths: Both the utility function approach and the manager pattern give contributors options to choose their preferred implementation style
  3. Self-contained: The refactoring doesn't require deep domain knowledge of the entire codebase
  4. Learning opportunity: Contributors get to practice common patterns like extracting shared functionality and consistent error handling

These types of technical debt issues often make excellent "good first issue" candidates since they improve code quality while being approachable for developers getting familiar with the codebase structure.


🧠 Learnings used
Learnt from: lazysegtree
PR: yorukot/superfile#1081
File: src/internal/ui/sidebar/directory_utils.go:103-112
Timestamp: 2025-09-20T01:40:50.053Z
Learning: lazysegtree identified code duplication between removeNotExistingDirectories and TogglePinnedDirectory functions in src/internal/ui/sidebar/directory_utils.go, specifically 6 lines of JSON marshaling and file writing logic. He prefers to track such duplication fixes in separate GitHub issues and suggests either extracting common util functions or creating a PinnedDir manager for centralized Read/Write operations to PinnedFile.

Learnt from: lazysegtree
PR: yorukot/superfile#1011
File: src/internal/handle_modal.go:145-203
Timestamp: 2025-08-29T13:56:33.955Z
Learning: lazysegtree identified that help menu navigation functions (helpMenuListUp and helpMenuListDown) in src/internal/handle_modal.go are too complicated, can be simplified, are similar to sidebar navigation but inconsistent, and lack unit tests. He prefers to track such technical debt in separate GitHub issues rather than addressing it in the current PR scope.

Learnt from: lazysegtree
PR: yorukot/superfile#781
File: src/internal/ui/sidebar/render.go:46-48
Timestamp: 2025-04-28T03:48:46.327Z
Learning: The user (lazysegtree) prefers to keep PRs focused and manageable in size, sometimes intentionally leaving TODO comments to track minor issues for later PRs rather than addressing everything at once.

Learnt from: lazysegtree
PR: yorukot/superfile#781
File: src/internal/model_render.go:254-256
Timestamp: 2025-04-28T04:27:33.074Z
Learning: When race conditions or other issues that are unrelated to the current PR's focus are identified during review, lazysegtree prefers creating separate GitHub issues to track them rather than addressing them in the current PR. This helps maintain PR focus and scope.

Learnt from: lazysegtree
PR: yorukot/superfile#967
File: src/internal/key_function.go:45-47
Timestamp: 2025-08-02T11:47:07.713Z
Learning: lazysegtree prefers to track technical debt and architectural improvements in dedicated GitHub issues when they are identified during PR reviews but are beyond the scope of the current PR, particularly for complex refactoring needs like input handling architecture that would require significant changes.

Learnt from: lazysegtree
PR: yorukot/superfile#1044
File: src/internal/utils/file_utils.go:149-149
Timestamp: 2025-09-09T13:29:11.771Z
Learning: lazysegtree prefers to keep PR scope focused on the primary objectives and considers pre-existing technical debt issues as out of scope for migration/refactoring PRs, preferring to defer such issues to separate GitHub issues rather than expanding the current PR scope.

Learnt from: lazysegtree
PR: yorukot/superfile#979
File: src/internal/common/predefined_variable.go:47-47
Timestamp: 2025-08-06T10:54:31.444Z
Learning: When lazysegtree says a review is "inaccurate and pre-existing issues. Not much useful," it means I should focus specifically on bugs or problems introduced by the current PR changes, not architectural concerns or code quality issues that were already present. The refactoring work in superfile PRs is generally well-implemented and should be evaluated on whether the specific changes work correctly, not on broader codebase architecture.

Learnt from: lazysegtree
PR: yorukot/superfile#963
File: src/internal/handle_file_operations.go:567-570
Timestamp: 2025-07-27T08:49:09.687Z
Learning: lazysegtree prefers to defer technical debt issues like model mutation concerns to later PRs when the current PR has already grown too large, maintaining focus on the primary objectives while acknowledging the need to track such issues for future work.

Learnt from: lazysegtree
PR: yorukot/superfile#1013
File: src/internal/model_render.go:329-341
Timestamp: 2025-08-29T14:11:21.380Z
Learning: lazysegtree prefers to defer help menu rendering optimizations and other technical debt improvements to separate GitHub issues when the current PR scope has grown too large, maintaining focus on the primary refactoring objectives while tracking performance improvements for future work.

Learnt from: lazysegtree
PR: yorukot/superfile#1013
File: src/internal/utils/file_utils.go:252-275
Timestamp: 2025-08-24T03:25:10.117Z
Learning: In PR #1013 for yorukot/superfile, when reviewing the ReadFileContent utility function, lazysegtree chose to implement only the parameter renaming fix (filepath → filePath) to avoid shadowing and declined buffer size increases and optional truncation enhancements, preferring to keep the utility function scope focused and avoid over-engineering when the additional features aren't immediately needed.

Learnt from: lazysegtree
PR: yorukot/superfile#963
File: src/internal/default_config.go:16-16
Timestamp: 2025-07-27T07:40:51.938Z
Learning: lazysegtree prefers simpler implementation approaches when the alternatives are significantly more complex, even if the alternatives might be architecturally cleaner, prioritizing maintainability and avoiding over-engineering.

Learnt from: lazysegtree
PR: yorukot/superfile#963
File: src/internal/default_config.go:16-16
Timestamp: 2025-07-27T07:40:51.938Z
Learning: lazysegtree prefers simpler implementation approaches when the alternatives are significantly more complex, even if the alternatives might be architecturally cleaner, prioritizing maintainability and avoiding over-engineering.

Learnt from: lazysegtree
PR: yorukot/superfile#969
File: src/internal/key_function.go:40-40
Timestamp: 2025-08-03T09:34:55.721Z
Learning: lazysegtree emphasizes proper dependency direction in software architecture, preferring that low-level components (like modal handlers) should not depend on high-level components (like the main model object). He also prioritizes performance considerations, noting that creating objects on every keypress in hot code paths like key handling is inefficient and should be avoided.

Learnt from: lazysegtree
PR: yorukot/superfile#985
File: src/internal/model.go:0-0
Timestamp: 2025-08-11T01:49:30.040Z
Learning: lazysegtree prefers maintaining code correctness through proper design and invariants rather than adding defensive bounds checks at every slice access point, viewing such defensive programming as "duct taping" that can mask actual bugs instead of fixing them at their source.

Learnt from: lazysegtree
PR: yorukot/superfile#973
File: src/internal/ui/processbar/model_update.go:7-27
Timestamp: 2025-08-03T14:49:31.221Z
Learning: lazysegtree prefers to keep test-only code simple without adding production-level concerns like goroutine synchronization, cancellation contexts, or complex lifecycle management, even when such patterns might prevent potential issues, since the complexity isn't justified for test utilities.

Learnt from: lazysegtree
PR: yorukot/superfile#950
File: src/internal/ui/metadata/README.md:7-7
Timestamp: 2025-07-24T03:46:29.516Z
Learning: lazysegtree prefers to defer comprehensive unit testing to separate PRs when the current PR has grown too large, maintaining focus on the primary refactoring objectives while tracking testing requirements in dedicated GitHub issues.

@yorukot yorukot merged commit bd79f4d into main Sep 20, 2025
13 checks passed
tmeijn pushed a commit to tmeijn/dotfiles that referenced this pull request Oct 15, 2025
This MR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [yorukot/superfile](https://github.com/yorukot/superfile) | minor | `v1.3.3` -> `v1.4.0` |

MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot).

**Proposed changes to behavior should be submitted there as MRs.**

---

### Release Notes

<details>
<summary>yorukot/superfile (yorukot/superfile)</summary>

### [`v1.4.0`](https://github.com/yorukot/superfile/releases/tag/v1.4.0)

[Compare Source](yorukot/superfile@v1.3.3...v1.4.0)

Hey folks. Releasing v1.4.0 with many new features, improvements, and bug fixes.

We have an async file preview now, a zoxide panel, and various new features improving UX.

#### Install:

[**Click me to know how to install**](https://github.com/yorukot/superfile?tab=readme-ov-file#installation)

#### Highlights

- We have the Zoxide Panel now. Ensure zoxide is installed on your system, set `zoxide_support` to `true` in the config, and press `z` to use zoxide. <img width="645" height="295" alt="Image" src="https://github.com/user-attachments/assets/238f6549-5318-49d1-a3a0-14cf8a686955" />

- File previewing is now async, meaning reduced lag while scrolling through images, or on slow systems.

- Many bug fixes. See 'Detailed Change Summary'

##### Internal Updates

- Most file operations are now truly async with the usage of the recommended `tea.Cmd` pattern.
- Enabled many new linters to improve code quality.
- Moved golangci-lint to v2. Now developers don't need to keep the old v1 in their systems.
- Refactored file preview in its own package for better maintainability and readability.
- Fixed flaky unit tests.

#### Detailed Change Summary

<details><summary>Details</summary>
<p>

##### Update
- feat: File operation via tea cmd [#&#8203;963](yorukot/superfile#963) by @&#8203;lazysegtree
- feat: processbar improvements, package separation, better channel management [#&#8203;973](yorukot/superfile#973) by @&#8203;lazysegtree
- feat: enable lll and recvcheck linter, fix tests, more refactors [#&#8203;977](yorukot/superfile#977) by @&#8203;lazysegtree
- feat: Remove channel for notification models [#&#8203;979](yorukot/superfile#979) by @&#8203;lazysegtree
- feat: enable cyclop, funlen, gocognit, gocyclo linters, and refactor large functions [#&#8203;984](yorukot/superfile#984) by @&#8203;lazysegtree
- feat: Add a new hotkey to handle cd-on-quit whenever needed [#&#8203;924](yorukot/superfile#924) by @&#8203;ahmed-habbachi
- feat: added option to permanently delete files [#&#8203;987](yorukot/superfile#987) by @&#8203;hupender
- feat: Preview panel separation [#&#8203;1021](yorukot/superfile#1021) by @&#8203;lazysegtree
- feat: Add search functionality to help menu [#&#8203;1011](yorukot/superfile#1011) by @&#8203;iZarrios
- feat: Use zoxide lib [#&#8203;1036](yorukot/superfile#1036) by @&#8203;lazysegtree
- feat: Add zoxide directory tracking on navigation [#&#8203;1041](yorukot/superfile#1041) by @&#8203;lazysegtree
- feat: Zoxide integration [#&#8203;1039](yorukot/superfile#1039) by @&#8203;lazysegtree
- feat: Select mode with better feedback [#&#8203;1074](yorukot/superfile#1074) by @&#8203;lazysegtree
- feat: owner/group in the metadata [#&#8203;1093](yorukot/superfile#1093) by @&#8203;xelavopelk
- feat: Async zoxide [#&#8203;1104](yorukot/superfile#1104) by @&#8203;lazysegtree

##### Bug Fix
- fix: sorting in searchbar [#&#8203;985](yorukot/superfile#985) by @&#8203;hupender
- fix: Async rendering, Include clipboard check in paste items, and update linter configs [#&#8203;997](yorukot/superfile#997) by @&#8203;lazysegtree
- fix: Move utility functions to utils package [#&#8203;1012](yorukot/superfile#1012) by @&#8203;lazysegtree
- fix: Refactoring and separation of preview panel and searchbar in help menu [#&#8203;1013](yorukot/superfile#1013) by @&#8203;lazysegtree
- fix(filePanel): allow focusType to be set correctly [#&#8203;1033](yorukot/superfile#1033) by @&#8203;faisal-990
- fix(ci): Update gomod2nix.toml, allow pre release in version output, release 1.4.0-rc1, bug fixes, and improvements [#&#8203;1054](yorukot/superfile#1054) by @&#8203;lazysegtree
- fix(nix): resolve build failures in the nix flake [#&#8203;1068](yorukot/superfile#1068) by @&#8203;Frost-Phoenix
- fix: Retry the file deletion to prevent flakies (#&#8203;938) [#&#8203;1076](yorukot/superfile#1076) by @&#8203;lazysegtree
- fix(issue-1066): Fixed issue where enter was not searchable [#&#8203;1078](yorukot/superfile#1078) by @&#8203;Simpaqt
- fix(#&#8203;1073): Tech debt fix [#&#8203;1077](yorukot/superfile#1077) by @&#8203;Simpaqt
- fix: fix deleted directory not able to remove from pins (#&#8203;1067) [#&#8203;1081](yorukot/superfile#1081) by @&#8203;yorukot
- fix: fix child process spawning attached [#&#8203;1084](yorukot/superfile#1084) by @&#8203;guemidiborhane
- fix: always clear images when showing a FullScreenStyle [#&#8203;1094](yorukot/superfile#1094) by @&#8203;snikoletopoulos
- fix: Allow j and k keys in zoxide [#&#8203;1102](yorukot/superfile#1102) by @&#8203;lazysegtree
- fix: Zoxide improvements and 1.4.0-rc2 [#&#8203;1105](yorukot/superfile#1105) by @&#8203;lazysegtree
- fix: rename cursor beginning on wrong character because of multiple dots in name (#&#8203;813) [#&#8203;1112](yorukot/superfile#1112) by @&#8203;SyedAsadK
- fix: check and fix file panel scroll position on height changes [#&#8203;1095](yorukot/superfile#1095) by @&#8203;snikoletopoulos

##### Optimization
- perf(website): optimize font loading and asset organization [#&#8203;1089](yorukot/superfile#1089) by @&#8203;yorukot

##### Documentation
- docs: fix incorrect zoxide plugin config name [#&#8203;1049](yorukot/superfile#1049) by @&#8203;shree-xvi
- docs(hotkeys): Fix typo in vimHotkeys.toml comments [#&#8203;1080](yorukot/superfile#1080) by @&#8203;wleoncio
- docs: add section for core maintainers in README.md [#&#8203;1088](yorukot/superfile#1088) by @&#8203;yorukot
- chore: add winget install instruction to readme and website [#&#8203;943](yorukot/superfile#943) by @&#8203;claykom

##### Dependencies
- chore(deps): update dependency go to v1.25.0, golangci-lint to v2, golangci-lint actions to v8 [#&#8203;750](yorukot/superfile#750) by @&#8203;renovate[bot]
- chore(deps): update amannn/action-semantic-pull-request action to v6 [#&#8203;1006](yorukot/superfile#1006) by @&#8203;renovate[bot]
- chore(deps): update actions/first-interaction action to v3 [#&#8203;1005](yorukot/superfile#1005) by @&#8203;renovate[bot]
- chore(deps): update actions/checkout action to v5 [#&#8203;1004](yorukot/superfile#1004) by @&#8203;renovate[bot]
- chore(deps): bump astro from 5.10.1 to 5.12.8 [#&#8203;982](yorukot/superfile#982) by @&#8203;dependabot[bot]
- fix(deps): update module golang.org/x/mod to v0.27.0 [#&#8203;989](yorukot/superfile#989) by @&#8203;renovate[bot]
- fix(deps): update dependency @&#8203;expressive-code/plugin-collapsible-sections to v0.41.3 [#&#8203;990](yorukot/superfile#990) by @&#8203;renovate[bot]
- fix(deps): update dependency sharp to v0.34.3 [#&#8203;992](yorukot/superfile#992) by @&#8203;renovate[bot]
- fix(deps): update dependency @&#8203;expressive-code/plugin-line-numbers to v0.41.3 [#&#8203;991](yorukot/superfile#991) by @&#8203;renovate[bot]
- chore(deps): update dependency go to v1.25.0 [#&#8203;994](yorukot/superfile#994) by @&#8203;renovate[bot]
- fix(deps): update astro monorepo [#&#8203;995](yorukot/superfile#995) by @&#8203;renovate[bot]
- fix(deps): update dependency @&#8203;astrojs/starlight to ^0.35.0 [#&#8203;1000](yorukot/superfile#1000) by @&#8203;renovate[bot]
- fix(deps): update module github.com/urfave/cli/v3 to v3.4.1 [#&#8203;1001](yorukot/superfile#1001) by @&#8203;renovate[bot]
- fix(deps): update module golang.org/x/text to v0.28.0 [#&#8203;1003](yorukot/superfile#1003) by @&#8203;renovate[bot]

##### Misc
- chore: migrate from superfile.netlify.app to superfile.dev [#&#8203;1087](yorukot/superfile#1087) by @&#8203;yorukot
- refactor(filepanel): replace filePanelFocusType with isFocused boolean [#&#8203;1040](yorukot/superfile#1040) by @&#8203;faisal-990
- refactor(ansi): Migrate from github.com/charmbracelet/x/exp/term/ansi to github.com/charmbracelet/x/ansi [#&#8203;1044](yorukot/superfile#1044) by @&#8203;faisal-990
- refactor: common operation on pinned directory file using PinnedManager [#&#8203;1085](yorukot/superfile#1085) by @&#8203;Manaswa-S
- test: unit tests for pinned manager [#&#8203;1090](yorukot/superfile#1090) by @&#8203;Manaswa-S

</p>
</details> 

#### New Contributors
* @&#8203;hupender made their first contribution in yorukot/superfile#985
* @&#8203;ahmed-habbachi made their first contribution in yorukot/superfile#924
* @&#8203;iZarrios made their first contribution in yorukot/superfile#1011
* @&#8203;faisal-990 made their first contribution in yorukot/superfile#1033
* @&#8203;shree-xvi made their first contribution in yorukot/superfile#1049
* @&#8203;Simpaqt made their first contribution in yorukot/superfile#1078
* @&#8203;wleoncio made their first contribution in yorukot/superfile#1080
* @&#8203;guemidiborhane made their first contribution in yorukot/superfile#1084
* @&#8203;Manaswa-S made their first contribution in yorukot/superfile#1085
* @&#8203;xelavopelk made their first contribution in yorukot/superfile#1093
* @&#8203;snikoletopoulos made their first contribution in yorukot/superfile#1094
* @&#8203;SyedAsadK made their first contribution in yorukot/superfile#1112

**Full Changelog**: <yorukot/superfile@v1.3.3...v1.4.0>

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this MR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box

---

This MR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS4xNDYuMCIsInVwZGF0ZWRJblZlciI6IjQxLjE0Ni4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJSZW5vdmF0ZSBCb3QiXX0=-->
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.

Deleted directory not able to remove from pins

3 participants