Skip to content

feat: add indicator style support#117

Merged
seapagan merged 7 commits intomainfrom
feat/indicator-styles
Apr 6, 2026
Merged

feat: add indicator style support#117
seapagan merged 7 commits intomainfrom
feat/indicator-styles

Conversation

@seapagan
Copy link
Copy Markdown
Owner

@seapagan seapagan commented Apr 5, 2026

Summary

Implement configurable indicator styles across native and GNU compatibility modes.

What Changed

  • add indicator-style runtime and config support with backward compatibility for append_slash
  • add native and GNU CLI surfaces for slash, file-type, classify, and none
  • rework file rendering so symlink, directory, FIFO, socket, and executable markers follow the selected style
  • omit the symlink @ marker in long mode to match GNU ls
  • expand unit and integration coverage for parsing, config precedence, and rendered output
  • document the new options, config values, and indicator characters

Summary by CodeRabbit

  • New Features

    • Added file-type indicator flags: --file-type, -F/--classify, and --no-indicators.
    • Introduced indicator_style config: "none", "slash", "file-type", "classify".
    • File markers now include / (dir), @ (symlink), | (FIFO), = (socket) and * (executable, with classify).
  • Bug Fixes

    • Symlink indicator suppressed in native long listings to match GNU ls.
  • Documentation

    • Updated usage and config docs; append_slash = true maps to indicator_style = "slash".

seapagan added 3 commits April 5, 2026 19:25
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 5, 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: 6934b03f-0c41-467a-9bde-c7a8df0f9eb3

📥 Commits

Reviewing files that changed from the base of the PR and between 35cd200 and d143252.

📒 Files selected for processing (2)
  • tests/crate/file.rs
  • tests/integration.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/crate/file.rs
  • tests/integration.rs

📝 Walkthrough

Walkthrough

Replaces boolean append_slash with an IndicatorStyle enum (None, Slash, FileType, Classify); adds CLI flags (--file-type, -F/--classify, --no-indicators), config aliasing and precedence, refactors file-name indicator rendering and symlink display, reworks config deserialization, and updates tests and docs.

Changes

Cohort / File(s) Summary
Documentation
README.md, docs/src/config.md, docs/src/usage.md
Expanded indicator docs: added --file-type, -F/--classify, --no-indicators; enumerated indicator characters (/, @, `
Core Enum & Types
src/structs.rs
Added IndicatorStyle enum; replaced Params.append_slash: bool with Params.indicator_style: IndicatorStyle; introduced RawParams and From<RawParams> for Params with legacy append_slash mapping and precedence rules.
CLI & Flags
src/cli.rs
Replaced Flags.slash: bool with Flags.indicator_style: Option<IndicatorStyle>; added --file-type, --classify/-F, --no-indicators; expanded --indicator-style accepted values; added ArgGroup mutual exclusion and defaulted CompatMode to Native.
Public API
src/lib.rs
Re-exported IndicatorStyle alongside existing re-exports.
Configuration Loading
src/settings.rs
Deserialize into RawParams and convert to Params (.into()), so indicator_style is resolved from config with legacy alias handling.
File Display Logic
src/utils/file.rs
Centralised indicator rendering with format_name_with_indicator; unified indicator_suffix for all styles; symlink indicator suppressed in native long format; renamed symlink helper param to source_name.
Tests — Unit & Integration
tests/*, tests/crate/*, tests/integration.rs, tests/seams.rs, tests/structs.rs
Updated tests to use IndicatorStyle in Flags/Params; added Unix-only tests for FIFO/socket indicators and long-format symlink behaviour; added config alias and precedence tests; updated many assertions and help tests for new CLI flags.

Sequence Diagram(s)

sequenceDiagram
    participant CLI as Client/CLI
    participant Flags as Flags Parser (src/cli.rs)
    participant Config as Config Loader (src/settings.rs)
    participant Params as Params/Conversion (src/structs.rs)
    participant Renderer as File Renderer (src/utils/file.rs)
    CLI->>Flags: parse args (--file-type / -F / --no-indicators / --indicator-style)
    CLI->>Config: read config (config.toml)
    Flags->>Params: produce Flags.indicator_style (Option<IndicatorStyle>)
    Config->>Params: produce RawParams -> Params (map append_slash -> indicator_style)
    Params->>Renderer: merged Params (indicator_style resolved via Flags or Config)
    Renderer->>Output: format names with indicator_suffix per IndicatorStyle
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 I hopped through flags and toml lands,
Four indicators now bloom from my hands —
Slash, file-type, classify, and none,
Symlinks hush when long-format's done.
Old append_slash nods; the rabbit’s done.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add indicator style support' accurately reflects the main change: introducing configurable indicator styles for file markers across native and GNU modes.
Docstring Coverage ✅ Passed Docstring coverage is 91.67% which is sufficient. The required threshold is 80.00%.

✏️ 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 feat/indicator-styles

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 5, 2026
@seapagan seapagan added the enhancement New feature or request label Apr 5, 2026
@codacy-production
Copy link
Copy Markdown

codacy-production bot commented Apr 5, 2026

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 34 complexity · -58 duplication

Metric Results
Complexity 34
Duplication -58

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 5, 2026 18:31
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: 3

🧹 Nitpick comments (2)
tests/integration.rs (1)

862-906: Consider adding symlink to non-Unix platforms gracefully.

The tests at lines 862-906 create a symlink conditionally with #[cfg(unix)], but then assert on link and link@ unconditionally. On non-Unix platforms, the link file won't exist, potentially causing test failures or misleading passes.

♻️ Suggested fix: guard the symlink assertions
     assert!(stdout.contains("child/"));
-    assert!(stdout.contains("link"));
-    assert!(!stdout.contains("link@"));
+    #[cfg(unix)]
+    {
+        assert!(stdout.contains("link"));
+        assert!(!stdout.contains("link@"));
+    }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/integration.rs` around lines 862 - 906, In the two tests
test_gnu_compat_mode_accepts_indicator_style_slash and
test_gnu_compat_mode_accepts_short_p you create a symlink only under
#[cfg(unix)] but then assert on "link" and "link@" unconditionally; update the
tests to only perform the symlink-related assertions when the symlink exists
(e.g., wrap those assertions in #[cfg(unix)] blocks or check
std::fs::symlink_metadata(&link_path).is_ok() before asserting on stdout
containing "link" and not containing "link@"), leaving the existing child/
assertion unchanged so non-Unix platforms skip the symlink checks and the tests
remain deterministic.
src/utils/file.rs (1)

428-445: The check order could cause executable FIFOs or sockets to be misclassified, but this is unlikely in practice.

The function checks is_executable() before is_fifo() and is_socket(). Since is_executable() only checks Unix permission bits without file type guards, a FIFO or socket with executable bits set would incorrectly return * instead of | or =. However, FIFOs and sockets should not have executable bits set in normal operation, making this a theoretical rather than practical concern. If stricter classification is desired, the checks could be reordered to verify FIFO and socket types before checking executable status.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/utils/file.rs` around lines 428 - 445, The function
file_type_indicator_suffix currently checks is_executable(metadata) before
testing metadata.file_type().is_fifo() and is_socket(), which can misclassify
FIFO/socket files that happen to have executable bits set; update the check
order so that directory, symlink, FIFO (metadata.file_type().is_fifo()), and
socket (metadata.file_type().is_socket()) are tested before the
classify_executables && is_executable(metadata) branch, preserving the
classify_executables behavior and using the same return values ("/", "@", "|",
"=", "*", "") to ensure FIFOs/sockets are classified correctly even if their
permission bits include execute.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/src/usage.md`:
- Around line 15-16: Fix the unclosed backtick in the `-A` / `--almost-all`
description: locate the line mentioning `-A` / `--almost-all` (the string "`-A`
/ `--almost-all` - Show hidden files, but don't show `.` and `..") and add the
missing closing backtick around `--almost-all` so the markdown code span is
properly terminated (ensure the line reads something like `- `-A` /
`--almost-all` - Show hidden files, but don't show `.` and `..``).

In `@README.md`:
- Around line 101-102: Fix the unclosed inline code backtick in the `-A` /
`--almost-all` description: ensure the phrase "`--almost-all` - Show hidden
files, but don't show `.` and `..`" has matching opening and closing backticks
around `--almost-all` (and verify the surrounding list item formatting for `-p`
/ `--slash-dirs` remains unchanged); update the README entry for
`-A`/`--almost-all` so both code spans are properly closed.

In `@tests/crate/file.rs`:
- Around line 554-600: The two tests
test_create_file_info_omits_symlink_at_in_native_long_mode and
test_create_file_info_keeps_symlink_at_in_gnu_long_mode are duplicates: both
call create_file_info with long_format and assert that "link@ -> " is not
present; either rename the second test to reflect the actual behavior (e.g.,
test_create_file_info_omits_symlink_at_in_gnu_long_mode) or consolidate both
into a single parameterized/test-case that covers both modes, and update the
test name and assertions accordingly; reference create_file_info and the
indicator_suffix behavior when deciding which change to apply.

---

Nitpick comments:
In `@src/utils/file.rs`:
- Around line 428-445: The function file_type_indicator_suffix currently checks
is_executable(metadata) before testing metadata.file_type().is_fifo() and
is_socket(), which can misclassify FIFO/socket files that happen to have
executable bits set; update the check order so that directory, symlink, FIFO
(metadata.file_type().is_fifo()), and socket (metadata.file_type().is_socket())
are tested before the classify_executables && is_executable(metadata) branch,
preserving the classify_executables behavior and using the same return values
("/", "@", "|", "=", "*", "") to ensure FIFOs/sockets are classified correctly
even if their permission bits include execute.

In `@tests/integration.rs`:
- Around line 862-906: In the two tests
test_gnu_compat_mode_accepts_indicator_style_slash and
test_gnu_compat_mode_accepts_short_p you create a symlink only under
#[cfg(unix)] but then assert on "link" and "link@" unconditionally; update the
tests to only perform the symlink-related assertions when the symlink exists
(e.g., wrap those assertions in #[cfg(unix)] blocks or check
std::fs::symlink_metadata(&link_path).is_ok() before asserting on stdout
containing "link" and not containing "link@"), leaving the existing child/
assertion unchanged so non-Unix platforms skip the symlink checks and the tests
remain deterministic.
🪄 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: 53c087b9-4bc7-41ec-abcf-32c7dc26cab1

📥 Commits

Reviewing files that changed from the base of the PR and between 376cd74 and 29e7f58.

📒 Files selected for processing (15)
  • README.md
  • docs/src/config.md
  • docs/src/usage.md
  • src/cli.rs
  • src/lib.rs
  • src/settings.rs
  • src/structs.rs
  • src/utils/file.rs
  • tests/crate/app.rs
  • tests/crate/cli.rs
  • tests/crate/file.rs
  • tests/crate/settings.rs
  • tests/integration.rs
  • tests/seams.rs
  • tests/structs.rs

seapagan added 3 commits April 6, 2026 18:55
Signed-off-by: Grant Ramsay <seapagan@gmail.com>
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.

🧹 Nitpick comments (2)
tests/integration.rs (1)

1018-1033: Consider adding a positive assertion for the symlink arrow.

The test asserts link -> is present but doesn't verify the target is shown. Adding an assertion like assert!(stdout.contains("target.txt")) would strengthen the test by confirming the full symlink rendering in long mode.

💡 Suggested enhancement
     assert!(stdout.contains("link -> "));
     assert!(!stdout.contains("link@ -> "));
+    assert!(stdout.contains("target.txt"));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/integration.rs` around lines 1018 - 1033, The test function
test_gnu_compat_mode_omits_symlink_at_indicator_in_long_mode should also assert
the symlink target is displayed: after running Command::cargo_bin("lsp") and
capturing stdout via run_and_capture, add a positive assertion that
stdout.contains("target.txt") (or the exact expected target name shown by the
fixture created by create_indicator_fixture()) so the test validates the full
symlink rendering in long mode in addition to checking for "link -> ".
tests/crate/file.rs (1)

726-739: Consider adding an assertion for the @ marker absence.

For consistency with test_format_symlink_display_name_short_format_omits_marker_without_indicator (line 569), this test could also assert that the @ marker is absent when using the default indicator style.

💡 Suggested enhancement
     assert!(short.contains("link"));
     assert!(!short.contains('*'));
+    assert!(!short.contains('@'));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/crate/file.rs` around lines 726 - 739, Update the test function
test_format_symlink_display_name_unreadable_short_format_omits_marker_without_indicator
to also assert that the generated short string does not contain the '@' marker;
locate the call to format_symlink_display_name_with_dim("link",
Path::new("/tmp/link"), Err(io::Error::other("boom")), &Params::default(),
false) and add an assertion similar to assert!(!short.contains('@')) to mirror
the existing consistency check from
test_format_symlink_display_name_short_format_omits_marker_without_indicator.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@tests/crate/file.rs`:
- Around line 726-739: Update the test function
test_format_symlink_display_name_unreadable_short_format_omits_marker_without_indicator
to also assert that the generated short string does not contain the '@' marker;
locate the call to format_symlink_display_name_with_dim("link",
Path::new("/tmp/link"), Err(io::Error::other("boom")), &Params::default(),
false) and add an assertion similar to assert!(!short.contains('@')) to mirror
the existing consistency check from
test_format_symlink_display_name_short_format_omits_marker_without_indicator.

In `@tests/integration.rs`:
- Around line 1018-1033: The test function
test_gnu_compat_mode_omits_symlink_at_indicator_in_long_mode should also assert
the symlink target is displayed: after running Command::cargo_bin("lsp") and
capturing stdout via run_and_capture, add a positive assertion that
stdout.contains("target.txt") (or the exact expected target name shown by the
fixture created by create_indicator_fixture()) so the test validates the full
symlink rendering in long mode in addition to checking for "link -> ".

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d2c4f2b3-cfff-4360-9ca5-6b1beec8b268

📥 Commits

Reviewing files that changed from the base of the PR and between 29e7f58 and 35cd200.

📒 Files selected for processing (5)
  • README.md
  • docs/src/usage.md
  • src/utils/file.rs
  • tests/crate/file.rs
  • tests/integration.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • docs/src/usage.md
  • README.md

Signed-off-by: Grant Ramsay <seapagan@gmail.com>
@seapagan seapagan merged commit 7c11776 into main Apr 6, 2026
5 checks passed
@seapagan seapagan deleted the feat/indicator-styles branch April 6, 2026 18:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant