Skip to content

fix: color symlink targets by type#112

Merged
seapagan merged 5 commits intomainfrom
fix/symlink-target-coloring
Apr 4, 2026
Merged

fix: color symlink targets by type#112
seapagan merged 5 commits intomainfrom
fix/symlink-target-coloring

Conversation

@seapagan
Copy link
Copy Markdown
Owner

@seapagan seapagan commented Apr 4, 2026

Summary

  • color long-format symlink targets by the resolved target type while keeping the link name styled as a symlink
  • remove the completed symlink-target-coloring TODO entry
  • update the README and mdBook usage docs to include the missing -I/--gitignore and -V/--version options and fix the --no-icons spelling

Why

This makes symlink output match the intended behavior for target coloring and brings the usage docs back in sync with the current CLI flags.

Summary by CodeRabbit

  • New Features

    • Added -I / --gitignore to dim Git-ignored entries
    • Added -V / --version to print version and exit
    • Symlink targets in long format are now coloured by target type
  • Bug Fixes

    • Corrected documented disabling flag to --no-icons
  • Documentation

    • Updated README and usage docs; removed a TODO about symlink colouring
  • Tests

    • Added tests verifying coloured symlink-target rendering

seapagan added 3 commits April 4, 2026 09:43
Signed-off-by: Grant Ramsay <seapagan@gmail.com>
Signed-off-by: Grant Ramsay <seapagan@gmail.com>
Signed-off-by: Grant Ramsay <seapagan@gmail.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 4, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 42f96492-b8df-4c4e-aad1-a4c4d2aaebd2

📥 Commits

Reviewing files that changed from the base of the PR and between b320d05 and 3a56c11.

📒 Files selected for processing (1)
  • src/utils/file.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/utils/file.rs

📝 Walkthrough

Walkthrough

Docs: added -I/--gitignore and -V/--version flags and corrected --no-icons usage. Code: centralised filename colour logic and applied type-specific colouring to symlink targets. Tests: added unit and updated integration tests to assert ANSI‑coloured symlink targets.

Changes

Cohort / File(s) Summary
Documentation
README.md, docs/src/usage.md
Documented new -I / --gitignore and -V / --version flags; corrected icon flag from -no-icons to --no-icons.
Removed TODO
TODO.md
Removed a TODO about symlink rendering.
Symlink colourisation logic
src/utils/file.rs
Removed executable field; added colorize_name_by_metadata() helper; delegated name colouring to it; updated long-format symlink rendering to attempt fs::symlink_metadata on targets and apply type-specific ANSI colouring for dir, file, symlink, executable; fallback to uncoloured display on metadata failure.
Tests
tests/crate/file.rs, tests/integration.rs
Expanded inline colour imports; added Unix-only test verifying coloured symlink-target display per target type; updated integration test to capture raw stdout and assert ANSI‑coloured -> target output.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Poem

🐰 I nibble code and colour the trail,
Symlinks gleam cyan, directories sail,
Executables hop in bold green light,
Targets now glow when metadata's bright,
A cosy tree by lanterned night.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% 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 'fix: color symlink targets by type' accurately and concisely summarizes the main change—implementing type-based coloring for symlink targets in long format output.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/symlink-target-coloring

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.

@seapagan seapagan self-assigned this Apr 4, 2026
@seapagan seapagan added the bug Something isn't working label Apr 4, 2026
@codacy-production
Copy link
Copy Markdown

codacy-production bot commented Apr 4, 2026

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 0 complexity · 0 duplication

Metric Results
Complexity 0
Duplication 0

View in Codacy

TIP This summary will be updated as you push new changes. Give us feedback

@seapagan seapagan marked this pull request as ready for review April 4, 2026 08:56
Copy link
Copy Markdown

@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.

🧹 Nitpick comments (1)
src/utils/file.rs (1)

407-422: Consider lazy evaluation of get_file_details for performance.

get_file_details performs system calls to resolve user/group names, but the result is only needed when checking the executable flag for regular files. For symlinks and directories, it's wasted work.

♻️ Proposed optimisation
 fn colorize_name_by_metadata(
     safe_name: &str,
     metadata: &fs::Metadata,
 ) -> String {
-    let details = get_file_details(metadata);
-
     if metadata.is_symlink() {
         format!("{color_cyan}{safe_name}")
     } else if metadata.is_dir() {
         format!("{color_blue}{safe_name}")
-    } else if details.executable {
+    } else if is_executable(metadata) {
         format!("{style_bold}{color_green}{safe_name}")
     } else {
         format!("{color_reset}{safe_name}")
     }
 }
+
+#[cfg(unix)]
+fn is_executable(metadata: &fs::Metadata) -> bool {
+    metadata.permissions().mode() & 0o111 != 0
+}
+
+#[cfg(windows)]
+fn is_executable(_metadata: &fs::Metadata) -> bool {
+    false
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/utils/file.rs` around lines 407 - 422, In colorize_name_by_metadata,
avoid calling get_file_details unconditionally; remove the eager let details =
get_file_details(metadata) and instead call get_file_details(metadata) lazily
only when needed (i.e., in the branch that handles regular files) to avoid
unnecessary system calls for symlinks and directories; change the branches to
first check metadata.is_symlink() and metadata.is_dir(), then in the else branch
call get_file_details(metadata) and inspect details.executable to decide between
the bold/green and reset formats, keeping the same returned String format and
using the existing function name colorize_name_by_metadata and helper
get_file_details.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/utils/file.rs`:
- Around line 407-422: In colorize_name_by_metadata, avoid calling
get_file_details unconditionally; remove the eager let details =
get_file_details(metadata) and instead call get_file_details(metadata) lazily
only when needed (i.e., in the branch that handles regular files) to avoid
unnecessary system calls for symlinks and directories; change the branches to
first check metadata.is_symlink() and metadata.is_dir(), then in the else branch
call get_file_details(metadata) and inspect details.executable to decide between
the bold/green and reset formats, keeping the same returned String format and
using the existing function name colorize_name_by_metadata and helper
get_file_details.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8b86f82b-d27d-49c5-af64-fefeab8d39e4

📥 Commits

Reviewing files that changed from the base of the PR and between 59f7d27 and b4a4316.

📒 Files selected for processing (6)
  • README.md
  • TODO.md
  • docs/src/usage.md
  • src/utils/file.rs
  • tests/crate/file.rs
  • tests/integration.rs
💤 Files with no reviewable changes (1)
  • TODO.md

Signed-off-by: Grant Ramsay <seapagan@gmail.com>
Copy link
Copy Markdown

@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

🧹 Nitpick comments (1)
src/utils/file.rs (1)

416-421: Avoid recomputing full file details just to detect executability.

At Line [416], calling get_file_details(metadata) repeats extra metadata/user/group work already done earlier in this code path. This can add avoidable overhead in large directory listings.

♻️ Suggested refactor
-        let details = get_file_details(metadata);
-
-        if details.executable {
+        let executable = metadata.permissions().mode() & 0o111 != 0;
+        if executable {
             format!("{style_bold}{color_green}{safe_name}")
         } else {
             format!("{color_reset}{safe_name}")
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/utils/file.rs` around lines 416 - 421, Don't call
get_file_details(metadata) just to check executability; instead derive the
executable flag directly from the provided metadata (e.g., inspect
metadata.permissions().mode() on Unix or use the platform-appropriate permission
check) and use that boolean in place of details.executable. Update the code
around the format branch that currently calls get_file_details(metadata)
(referencing get_file_details and the local metadata variable) to compute a
simple is_executable boolean from metadata and use that to pick the green bold
vs reset formatting, avoiding the expensive full get_file_details call.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/utils/file.rs`:
- Around line 441-445: The code is calling fs::symlink_metadata(&target_path)
which returns the symlink's own metadata; replace this with
fs::metadata(&target_path) so the resolved target's metadata (following any
intermediate symlinks) is used when calling colorize_name_by_metadata on
display_target; update the call site where symlink_metadata is used (around
display_target / target_path) to use fs::metadata and keep the same error
handling (map(...).unwrap_or(display_target)) so non-existent targets still fall
back to the original display_target.

---

Nitpick comments:
In `@src/utils/file.rs`:
- Around line 416-421: Don't call get_file_details(metadata) just to check
executability; instead derive the executable flag directly from the provided
metadata (e.g., inspect metadata.permissions().mode() on Unix or use the
platform-appropriate permission check) and use that boolean in place of
details.executable. Update the code around the format branch that currently
calls get_file_details(metadata) (referencing get_file_details and the local
metadata variable) to compute a simple is_executable boolean from metadata and
use that to pick the green bold vs reset formatting, avoiding the expensive full
get_file_details call.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b5f91922-e3e6-4e82-be0b-1ee3d786aca1

📥 Commits

Reviewing files that changed from the base of the PR and between b4a4316 and b320d05.

📒 Files selected for processing (1)
  • src/utils/file.rs

Signed-off-by: Grant Ramsay <seapagan@gmail.com>
@seapagan seapagan merged commit a31c18e into main Apr 4, 2026
5 checks passed
@seapagan seapagan deleted the fix/symlink-target-coloring branch April 4, 2026 09:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant