Skip to content

Fix natsort and viewer bugs, remove duplicate toggle action#22

Merged
leszek3737 merged 3 commits into
mainfrom
fix3
May 12, 2026
Merged

Fix natsort and viewer bugs, remove duplicate toggle action#22
leszek3737 merged 3 commits into
mainfrom
fix3

Conversation

@leszek3737

@leszek3737 leszek3737 commented May 12, 2026

Copy link
Copy Markdown
Owner

Summary

Improve viewer line-wrapping behavior, adjust natural sort ordering with leading zeros, refine file watcher debounce, and simplify panel hidden-toggle handling.

New Features:

  • Add visual-row-based scrolling and status reporting for wrapped text in the viewer.

Bug Fixes:

  • Fix viewer search, scrolling, and go-to-bottom behavior when line wrapping is enabled.
  • Correct natural sort ordering for numbers with leading zeros and align key-based sorting with direct comparison.
  • Ensure filesystem watcher emits rename and delete events without over-aggressive debouncing.
  • Avoid duplicate handling of hidden-panel toggling and keep panel filter reset logic consistent with panel state.

Enhancements:

  • Cache and reuse wrap layout metadata in the viewer to avoid unnecessary recomputation.
  • Document Serena language server options and additional workspace folders in project configuration.

Tests:

  • Add viewer tests covering wrapped visual scrolling, go-to-bottom, and visual/logical row mapping.
  • Extend natural sort tests to cover leading-zero cases and consistency between comparator and key.
  • Adjust or add tests around panel behavior and watcher debounce where needed.

- natsort: unify natsort_key with natsort for leading-zero numbers
- viewer: visual-row-based scroll when wrap_lines is enabled
- watcher: bypass debounce for Deleted/Renamed events
- menu_actions: remove duplicate TogglePanelHidden, merge into ToggleHiddenFiles
- main: fix search Esc wiping file list when unfiltered_entries is empty
@sourcery-ai

sourcery-ai Bot commented May 12, 2026

Copy link
Copy Markdown

Reviewer's Guide

Implements visual-row-based scrolling and layout for wrapped viewer text, adjusts viewer status line reporting, fixes natural sort behavior around leading zeros, refines filesystem watcher debounce logic, removes a duplicate panel hidden toggle action, and updates project configuration docs/tests accordingly.

Sequence diagram for viewer wrap layout and visual-row scrolling

sequenceDiagram
    participant App as AppState
    participant Main as handle_viewer_mode
    participant Viewer as ViewerState
    participant UI as render_viewer

    App->>Main: handle_viewer_mode(key, terminal_size, terminal_width)
    Main->>Viewer: update_wrap_layout(content_width)
    Viewer-->>Main: visual_heights updated

    Main->>UI: render_viewer(frame, area, ViewerState)
    UI->>Viewer: is_hex_mode()
    UI->>Viewer: visual_row_to_logical(scroll_offset)
    UI->>Viewer: max_scroll()
    UI-->>Main: paragraph rendered with wrap and sub_row scroll

    Main-->>App: updated viewer display with visual-row scrolling
Loading

File-Level Changes

Change Details Files
Add visual-row-based layout and scrolling for wrapped text in the viewer, including integration with search, status line, and input handling.
  • Extend ViewerState with visual_heights and cached_content_width to track wrapped layout metadata.
  • Introduce helper methods to convert between visual rows and logical lines and to compute total visual rows/max scroll in wrapped mode.
  • Adjust scrolling, go-to-bottom, and search navigation logic to operate on visual rows when wrapping is active and hex mode is off.
  • Add update_wrap_layout to recompute visual_heights based on current content width and line number visibility, and call it from viewer input handling.
  • Update render_viewer to compute visible slices using visual rows, apply vertical scroll inside wrapped Paragraph, and fix current-line display to map from visual to logical lines.
  • Reset visual layout caches when toggling line numbers or wrapping, and add tests to cover wrapped scrolling, narrow widths, go-to-bottom, non-wrap behavior, and visual/logical roundtrips.
src/ui/viewer.rs
src/main.rs
Correct natural sort ordering when numeric segments contain leading zeros and ensure key-based sorting matches direct comparison.
  • Change NatKeySegment::Num Ord implementation to special-case numbers with leading zeros by using raw byte comparison instead of stripping zeros.
  • Update existing natsort tests to reflect the new ordering semantics for values like pic2 vs pic02 vs pic02000 with and without case-sensitivity.
  • Add a test that verifies natsort_key-based comparisons always match direct natsort results for a variety of inputs involving leading zeros and mixed segments.
src/ops/natsort.rs
Refine filesystem watcher debounce behavior and API to better handle rename and delete events.
  • Change should_emit to accept a skip_debounce flag that, when true, records timestamps but bypasses suppression logic.
  • Adjust rename handling to always send the event while still updating debounce state for both from and to paths.
  • Skip debounce for deleted events while keeping debounce for other events by passing skip_debounce based on the event kind.
src/fs/watcher.rs
Remove the duplicate TogglePanelHidden menu action and consolidate hidden-files status messaging into the reset filter action.
  • Remove the TogglePanelHidden variant from MenuAction and its handling from panel, navigation, file, and misc action dispatch.
  • Update ResetPanelFilter handling to emit a status message describing current hidden-file visibility instead of relying on the removed TogglePanelHidden action.
  • Avoid directly restoring unfiltered_entries in search cancel handling, relying instead on panel refresh logic.
src/input/menu_actions.rs
src/menu.rs
src/main.rs
Update Serena project configuration documentation to reflect new language server options and workspace-folder support.
  • Refresh the documented list of supported language server identifiers, including angular, html, scss and related notes.
  • Add configuration docs and a default empty key for additional_workspace_folders used for cross-package LSP setups.
.serena/project.yml

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces visual line wrapping support in the file viewer, ensuring that scrolling and search navigation correctly account for lines that span multiple visual rows. It also refactors menu actions by removing the redundant TogglePanelHidden action, updates the natural sorting algorithm to handle leading zeros more predictably, and expands the project configuration to support additional language servers. The review feedback identifies a potential integer underflow in the viewer's rendering logic and a mismatch in width calculation that could lead to incorrect wrapping behavior.

Comment thread src/ui/viewer.rs Outdated
Comment thread src/main.rs Outdated

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've found 1 issue, and left some high level feedback:

  • The visual scrolling logic (e.g. is_visual_scroll in ViewerState vs the use_visual condition in render_viewer) duplicates the same predicate in multiple places; consider centralizing this into a single helper to avoid divergence if the conditions change later.
  • Both visual_row_to_logical and logical_to_visual_row walk visual_heights linearly on each call; if you expect large files or frequent calls (e.g. during scrolling), consider precomputing prefix sums or another lightweight index to avoid repeated O(n) scans.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The visual scrolling logic (e.g. `is_visual_scroll` in `ViewerState` vs the `use_visual` condition in `render_viewer`) duplicates the same predicate in multiple places; consider centralizing this into a single helper to avoid divergence if the conditions change later.
- Both `visual_row_to_logical` and `logical_to_visual_row` walk `visual_heights` linearly on each call; if you expect large files or frequent calls (e.g. during scrolling), consider precomputing prefix sums or another lightweight index to avoid repeated O(n) scans.

## Individual Comments

### Comment 1
<location path="src/ui/viewer.rs" line_range="615-624" />
<code_context>
-    let start_idx = state.scroll_offset;
-    let end_idx = (start_idx + visible_height).min(state.content.len());
+
+    let use_visual = state.wrap_lines && !state.is_hex_mode() && !state.visual_heights.is_empty();
+
+    let (start_idx, sub_row, end_idx) = if use_visual {
+        let (logical_start, sub) = state.visual_row_to_logical(state.scroll_offset);
+        let mut visual_budget = visible_height + sub;
+        let mut end = logical_start;
+        while end < state.content.len() && visual_budget > 0 {
+            visual_budget -= state.visual_heights[end];
+            end += 1;
+        }
+        (logical_start, sub, end)
+    } else {
+        let start = state.scroll_offset;
+        let end = (start + visible_height).min(state.content.len());
+        (start, 0, end)
+    };

</code_context>
<issue_to_address>
**suggestion:** Reuse `is_visual_scroll` instead of duplicating the visual-scroll condition.

`use_visual` duplicates the logic in `ViewerState::is_visual_scroll`, except for the `!self.visual_heights.is_empty()` check. Keeping this condition in two places risks them drifting apart over time. Prefer calling `state.is_visual_scroll()` here, or adjust `is_visual_scroll` to cover the required semantics so the logic is defined in one place.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread src/ui/viewer.rs Outdated
… use_visual dedup

- viewer: use saturating_sub for visual_budget to prevent underflow panic
- viewer: reuse is_visual_scroll() instead of duplicating the condition
- main: remove incorrect -2 from content_width (block has no side borders)
@leszek3737
leszek3737 merged commit 1dfb706 into main May 12, 2026
5 checks passed
@leszek3737
leszek3737 deleted the fix3 branch May 12, 2026 14:25
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.

1 participant