Skip to content

refactor(tui): split tui module#288

Open
Darkroom4364 wants to merge 1 commit intomainfrom
273-tui-submodules
Open

refactor(tui): split tui module#288
Darkroom4364 wants to merge 1 commit intomainfrom
273-tui-submodules

Conversation

@Darkroom4364
Copy link
Copy Markdown
Collaborator

@Darkroom4364 Darkroom4364 commented May 4, 2026

Summary

  • split the monolithic TUI implementation into state, input, views, widgets, and top-level module files
  • rebuilt the split on current main so newer mouse-list interactions are preserved
  • fixed valid TUI review findings: quoted EDITOR parsing, dotted-directory path resolution, rescan debounce while scanning, partial source/sink dataflow rendering, display-cell-aware source-context carets, scroll-event preservation, and async/cache-driven source context loading
  • moved the existing TUI unit tests into src/tui/tests.rs and added focused regression coverage

Verification

  • cargo fmt --check
  • cargo clippy
  • cargo test

Refs #273

Summary by CodeRabbit

  • New Features

    • Full-screen interactive terminal UI for browsing scan results with mouse & keyboard, search/editable query, filtering, sorting, session confidence toggles, and spinner/status updates
    • Open findings in external editor and view source context with accurate caret/highlighting
    • Export results to CBOM/JSON/SARIF with on-screen success/failure and “empty CBOM” notice
    • Triage actions: disable rules, severity overrides, previews, and launch-mode controls
    • CNSA 2.0 compliance strip and deadline reporting
  • Tests

    • Extensive TUI tests covering rendering, interaction, exports, background loading, and triage behavior

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 4, 2026

Warning

Rate limit exceeded

@Darkroom4364 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 10 minutes and 33 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 38e0b03c-4caa-42d5-b809-d748a21b2e63

📥 Commits

Reviewing files that changed from the base of the PR and between a9e2f53 and 9c589b8.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (8)
  • Cargo.toml
  • src/tui.rs
  • src/tui/input.rs
  • src/tui/mod.rs
  • src/tui/state.rs
  • src/tui/tests.rs
  • src/tui/views.rs
  • src/tui/widgets.rs
📝 Walkthrough

Walkthrough

Implements a full interactive terminal UI: new TUI state, rendering, input/mouse dispatch, modal dialogs (launch/search/help/action/export/severity), export writers (CBOM/JSON/SARIF), terminal session lifecycle, external-open integration, source-context caching/worker loads, and comprehensive unit tests.

Changes

TUI feature (single cohesive DAG)

Layer / File(s) Summary
Data Shape & State
src/tui/state.rs
Introduces TuiApp core state (scan lifecycle, selection, filtering/sorting, review/runtime metadata), new fields (list_state, list_area, hover_index), selection helpers (select_filtered_index), source-context cache types, enums (LaunchMode, OpenFocus, TriageAction, ReviewState, ExportFormat, ExportMenu, SeverityPicker, SortMode), and request-id tracking.
Core Input & Control Flow
src/tui/input.rs
Adds ControlFlow and comprehensive input handling: handle_key plus modal handlers (handle_search_key, handle_launch_key, handle_action_menu_key, handle_severity_picker_key, handle_export_menu_key), mouse handling (can_handle_finding_mouse, handle_mouse), action plumbing (open_action_menu, available_actions_for_finding, action_enabled, apply_action, action_preview), export flow (open_export_menu, export_findings, export_findings_to), open-target execution helpers, and utility controls (cycle_session_min_confidence, cycle_sort_mode, open_severity_picker).
Rendering / Widgets
src/tui/views.rs, src/tui/widgets.rs
Implements TuiApp::draw and sub-drawers (launch, header, body, loading, footer, help, action/export/severity dialogs, compliance panel), list/detail rendering, dataflow/open-target visuals, source-context rendering with grapheme-aware caret/ellipsis, severity/confidence/crypto chips, shimmer loading, hit-testing/layout helpers, and many UI constants.
Terminal Lifecycle & Event Loop
src/tui/mod.rs
Adds run_scan_tui entrypoint and event loop, TerminalSession lifecycle (enter/suspend/resume/Drop), worker messages and background spawn (start_tui_execution, start_source_context_load), editor/open-command construction (open_command_spec_from_editor), and resolve_finding_path.
Tests
src/tui/tests.rs
Adds extensive unit tests covering path resolution, editor command parsing, event stash, input/control flows, rendering helpers, source-context worker/cache behavior, triage persistence and actions, compliance panel, and export output validation.
Deps / Manifest
Cargo.toml
Adds dependencies: shlex, unicode-segmentation, and unicode-width (for editor parsing and grapheme/width handling).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Terminal as Terminal (crossterm/ratatui)
    participant TUI as TuiApp
    participant Worker as Background Worker
    participant FS as Filesystem
    participant Editor as External Editor

    User->>Terminal: key / mouse event
    Terminal->>TUI: deliver event
    TUI->>TUI: handle_key / handle_mouse (modal routing)
    alt Rescan requested
        TUI->>Worker: start_tui_execution (spawn thread)
        Worker->>TUI: WorkerMessage::Scan via channel
        TUI->>TUI: handle_worker_messages (store result, update cache)
        TUI->>Terminal: redraw frame
    end
    alt Open target requested
        TUI->>FS: resolve_finding_path / read source context (optional)
        TUI->>Terminal: suspend TerminalSession
        TUI->>Editor: spawn external command
        Editor-->>TUI: exit
        TUI->>Terminal: resume TerminalSession, push runtime notice
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • peaktwilight

Poem

🐰
I hopped into the terminal glow,
Badges bright where findings show,
Keys and clicks, I sort and stream,
Triage done — a carrot dream,
Hop, export, and off I go.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 44.59% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'refactor(tui): split tui module' accurately reflects the main change: splitting the monolithic TUI implementation into separate module files while preserving existing behavior.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 273-tui-submodules

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
Review rate limit: 0/1 reviews remaining, refill in 10 minutes and 33 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

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: 4

🤖 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/rules/manifest.rs`:
- Around line 329-332: The selection of best from reached_seeds using only
a.confidence.total_cmp makes the result non-deterministic when confidences tie;
update the comparator in the max_by call (the expression that computes best) to
add a deterministic tie-breaker such as comparing a stable field (e.g., seed id,
seed text, or another canonical key) after the confidence comparison — for
example chain the Ordering from total_cmp with then(a.seed_id.cmp(&b.seed_id))
or then(a.seed.cmp(&b.seed)) so reached_seeds.values().max_by(...) always yields
a stable best.

In `@src/tui/input.rs`:
- Line 136: The handler that maps KeyCode::Char('r') to ControlFlow::Rescan must
be changed to check whether a scan is already running and only return
ControlFlow::Rescan when no scan is in progress; otherwise return a no-op flow
(e.g., ControlFlow::None or ControlFlow::Ignore). Locate the input handling
branch that matches KeyCode::Char('r') in src/tui/input.rs and consult the
shared scan state or an accessor like is_scanning()/scan_in_progress flag
exposed by the scan controller (or add one) to gate the Rescan emission; ensure
the scan-starting path sets the flag and clears it on completion so repeated 'r'
presses are debounced/blocked while a run is active.

In `@src/tui/mod.rs`:
- Around line 257-263: The code incorrectly treats a path with an extension as a
file (scan_root_is_file = scan_root.is_file() ||
scan_root.extension().is_some()), which misclassifies dotted directory names;
remove the extension-based check and base file detection solely on filesystem
metadata (e.g., use scan_root.is_file() or std::fs::metadata/metadata.is_file()
to handle symlinks/exists cases) so that scan_root_is_file, base, and later
resolve_finding_path use the actual file/dir state of scan_root rather than its
extension.
- Around line 179-183: The current split_whitespace() call on the editor string
will break quoted paths/flags; replace this with a shell-aware tokenizer (e.g.,
use shlex::split or the shell-words crate) to parse the editor command into
tokens while preserving quoted segments, then collect those tokens into the
parts Vec<String> used downstream (keep existing variable names like editor and
parts and ensure you handle the Result/Option from the tokenizer and fall back
or error appropriately).
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 958e93b8-0df1-484e-aa33-1878c168d446

📥 Commits

Reviewing files that changed from the base of the PR and between 981de86 and 82c5a15.

📒 Files selected for processing (9)
  • src/report/sarif.rs
  • src/rules/manifest.rs
  • src/tui.rs
  • src/tui/input.rs
  • src/tui/mod.rs
  • src/tui/state.rs
  • src/tui/tests.rs
  • src/tui/views.rs
  • src/tui/widgets.rs

Comment thread src/rules/manifest.rs Outdated
Comment thread src/tui/input.rs Outdated
Comment thread src/tui/mod.rs Outdated
Comment thread src/tui/mod.rs Outdated
@Darkroom4364 Darkroom4364 force-pushed the 273-tui-submodules branch from 82c5a15 to f028491 Compare May 4, 2026 15:01
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: 2

🤖 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/tui/widgets.rs`:
- Around line 479-570: The code currently indexes and slices source lines by
char count which breaks alignment for tabs, wide glyphs, and combining marks;
update render_context_line, highlight_range_for_line, and context_caret_line to
operate on terminal display-cell widths instead of .chars(): iterate the line as
grapheme clusters (unicode_segmentation::UnicodeSegmentation::graphemes) and
measure each cluster's display width
(unicode_width::UnicodeWidthStr/UnicodeWidthChar) to compute
window_start/window_end, visible_highlight offsets, and caret_offset; ensure
highlight_range_for_line returns character-indexed boundaries that you then
convert to cumulative display-cell offsets when rendering; keep using
CONTEXT_LINE_MAX_CHARS and CONTEXT_FOCUS_LEAD but treat them as cell counts, and
adjust context_caret_line to accept caret_offset/caret_width in display cells so
the "^" markers line up with the rendered text.
- Around line 232-272: The current dataflow step pushes for source/sink only
when both finding.source_line and finding.source_description (and same for sink)
are Some, which hides entries if either field is present alone; update the
conditional blocks that build the steps (the ones referencing
finding.source_line, finding.source_description, finding.sink_line,
finding.sink_description and pushing tuples with
OpenFocus::Source/OpenFocus::Sink) to accept either field being Some: if line is
Some use format!("{}:{}", display_path(&finding.file), line) as the label,
otherwise use display_path(&finding.file) (or another sensible fallback) and
still pass description.clone() when present (or None when absent); keep the same
OpenFocus variants and colors (Color::Yellow/Color::Red) so entries render when
only a location or only a description exists and align with
available_open_focuses/open_target_lines.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 9ec4181a-15c3-4936-a3ea-4fb3813650d8

📥 Commits

Reviewing files that changed from the base of the PR and between 82c5a15 and f028491.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (8)
  • Cargo.toml
  • src/tui.rs
  • src/tui/input.rs
  • src/tui/mod.rs
  • src/tui/state.rs
  • src/tui/tests.rs
  • src/tui/views.rs
  • src/tui/widgets.rs
✅ Files skipped from review due to trivial changes (2)
  • src/tui/tests.rs
  • src/tui/views.rs
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/tui/mod.rs
  • src/tui/state.rs
  • src/tui/input.rs

Comment thread src/tui/widgets.rs Outdated
Comment thread src/tui/widgets.rs
@Darkroom4364 Darkroom4364 force-pushed the 273-tui-submodules branch from f028491 to 024a02e Compare May 4, 2026 15:28
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 4, 2026

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":502,"request":{"method":"PATCH","url":"https://api.github.com/repos/PwnKit-Labs/foxguard/issues/comments/4369155910","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- walkthrough_start -->\n\n<details>\n<summary>📝 Walkthrough</summary>\n\n## Walkthrough\n\nImplements a complete interactive TUI: state, rendering, input handling, modal dialogs (action/export/severity/search/launch/help), export writers (CBOM/JSON/SARIF), terminal lifecycle, external-open integration, source-context caching, mouse hit-testing, and extensive unit tests.\n\n## Changes\n\n**TUI feature (single cohesive DAG)**\n\n|Layer / File(s)|Summary|\n|---|---|\n|**Data Shape & State** <br> `src/tui/state.rs`|Adds TuiApp fields (`list_state`, `list_area`, `hover_index`) and types/enums (LaunchMode, OpenFocus, TriageAction, ReviewState, ExportFormat, ExportMenu, SeverityPicker, SortMode, SourceContextCache/keys). Adds `select_filtered_index`, scanning lifecycle fields and filter/sort/session state.|\n|**Core Input & Control Flow** <br> `src/tui/input.rs`|Adds `ControlFlow` and many `TuiApp` handlers: `handle_key`, modal handlers (`handle_search_key`, `handle_launch_key`, `handle_action_menu_key`, `handle_severity_picker_key`, `handle_export_menu_key`), mouse handling (`can_handle_finding_mouse`, `handle_mouse`), action plumbing (`open_action_menu`, `available_actions_for_finding`, `action_enabled`, `apply_action`, `action_preview`), export logic (`open_export_menu`, `export_findings(_to)`), open-target execution (`open_selected_finding`, `open_target`, open-source/sink helpers), and utilities (`cycle_session_min_confidence`, `cycle_sort_mode`, `open_severity_picker`).|\n|**Rendering / Widgets** <br> `src/tui/views.rs`, `src/tui/widgets.rs`|Implements `TuiApp::draw` and sub-drawers (launch, header, body, loading, footer, help, action/export/severity dialogs, compliance panel), source-context loading with cache, list/detail rendering, dataflow and open-target visuals, severity/confidence/crypto chips, shimmer loading, hit-testing and layout helpers, and many UI constants.|\n|**Terminal Lifecycle & Event Loop** <br> `src/tui/mod.rs`|Adds `run_scan_tui` entrypoint, `TerminalSession` lifecycle (enter/suspend/resume/Drop), worker thread spawn (`start_tui_execution`), worker message type, editor/OS open command construction (`open_command_spec_from_editor`), and `resolve_finding_path` logic.|\n|**Tests** <br> `src/tui/tests.rs`|Adds comprehensive unit tests covering hit-testing, path resolution, editor command parsing, scan start/rescan behaviors, rendering helpers, dataflow/source-context rendering, input interactions and modal behaviors, triage action persistence, compliance UI, chip styling, and export success/no-op cases.|\n|**Deps / Manifest** <br> `Cargo.toml`|Adds `shlex = \"1\"` dependency for editor command parsing. |\n\n## Sequence Diagram(s)\n\n```mermaid\nsequenceDiagram\n    participant User\n    participant Terminal as Terminal (crossterm/ratatui)\n    participant TUI as TuiApp\n    participant Worker as Background Scan Worker\n    participant FS as Filesystem\n    participant Editor as External Editor/Viewer\n\n    User->>Terminal: key/mouse event\n    Terminal->>TUI: deliver event\n    TUI->>TUI: handle_key / handle_mouse (modal routing)\n    alt Rescan requested\n        TUI->>Worker: start_tui_execution (spawn thread)\n        Worker->>TUI: WorkerMessage (result) via channel\n        TUI->>TUI: handle_worker_messages (update result)\n        TUI->>Terminal: redraw frame\n    end\n    alt Open file target\n        TUI->>FS: resolve_finding_path / read source (optional)\n        TUI->>Terminal: suspend TerminalSession\n        TUI->>Editor: spawn external command\n        Editor-->>TUI: exit code\n        TUI->>Terminal: resume TerminalSession and show notice\n    end\n```\n\n## Estimated code review effort\n\n🎯 4 (Complex) | ⏱️ ~60 minutes\n\n## Possibly related PRs\n\n- PwnKit-Labs/foxguard#259 — Overlaps TUI export flow and CBOM/JSON/SARIF export builders used by this PR.  \n- PwnKit-Labs/foxguard#281 — Related changes to list-state, mouse handling, and hover/select hit-testing now surfaced on TuiApp.\n\n## Suggested reviewers\n\n- peaktwilight\n\n## Poem\n\n> 🐰  \n> *I hopped into the terminal night,*  \n> *Colored badges glowing bright,*  \n> *Keys and clicks, a tidy stream,*  \n> *Findings sorted — hop! — a dream,*  \n> *Triage done with rabbit might.*\n\n</details>\n\n<!-- walkthrough_end -->\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 4 | ❌ 1</summary>\n\n### ❌ Failed checks (1 warning)\n\n|     Check name     | Status     | Explanation                                                                           | Resolution                                                                         |\n| :----------------: | :--------- | :------------------------------------------------------------------------------------ | :--------------------------------------------------------------------------------- |\n| Docstring Coverage | ⚠️ Warning | Docstring coverage is 45.58% which is insufficient. The required threshold is 80.00%. | Write docstrings for the functions missing them to satisfy the coverage threshold. |\n\n<details>\n<summary>✅ Passed checks (4 passed)</summary>\n\n|         Check name         | Status   | Explanation                                                                                                                                                                                                                           |\n| :------------------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n|      Description Check     | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled.                                                                                                                                                                           |\n|         Title check        | ✅ Passed | The title \"refactor(tui): split tui module\" clearly describes the main change—splitting a monolithic TUI implementation into separate module files—which aligns with the substantial refactoring across six files and 898+ new lines. |\n|     Linked Issues check    | ✅ Passed | Check skipped because no linked issues were found for this pull request.                                                                                                                                                              |\n| Out of Scope Changes check | ✅ Passed | Check skipped because no linked issues were found for this pull request.                                                                                                                                                              |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing Touches</summary>\n\n<details>\n<summary>📝 Generate docstrings</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> Create stacked PR\n- [ ] <!-- {\"checkboxId\": \"3e1879ae-f29b-4d0d-8e06-d12b7ba33d98\"} --> Commit on current branch\n\n</details>\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"6ba7b810-9dad-11d1-80b4-00c04fd430c8\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Commit unit tests in branch `273-tui-submodules`\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n<!-- tips_start -->\n\n---\n\n\n<!-- review_rate_limit_status_start -->\n<sub>Review rate limit: 9/10 reviews remaining, refill in 6 minutes.</sub>\n<!-- review_rate_limit_status_end -->\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- 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 -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"signal":{},"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/PwnKit-Labs/foxguard/issues/comments/4369155910","status":502,"headers":{"content-length":"32","content-type":"application/json","date":"Mon, 04 May 2026 15:36:25 GMT","etag":"\"69f8a486-20\"","server":"github.com","vary":"Accept-Encoding, Accept, X-Requested-With","x-github-request-id":"431C:ED956:182D11D:601EBC7:69F8BCEE","x-ratelimit-limit":"5000","x-ratelimit-remaining":"4847","x-ratelimit-reset":"1777910516","x-ratelimit-resource":"core","x-ratelimit-used":"153"},"data":{"message":"Server Error"}}}

1 similar comment
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 4, 2026

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":502,"request":{"method":"PATCH","url":"https://api.github.com/repos/PwnKit-Labs/foxguard/issues/comments/4369155910","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- walkthrough_start -->\n\n<details>\n<summary>📝 Walkthrough</summary>\n\n## Walkthrough\n\nImplements a complete interactive TUI: state, rendering, input handling, modal dialogs (action/export/severity/search/launch/help), export writers (CBOM/JSON/SARIF), terminal lifecycle, external-open integration, source-context caching, mouse hit-testing, and extensive unit tests.\n\n## Changes\n\n**TUI feature (single cohesive DAG)**\n\n|Layer / File(s)|Summary|\n|---|---|\n|**Data Shape & State** <br> `src/tui/state.rs`|Adds TuiApp fields (`list_state`, `list_area`, `hover_index`) and types/enums (LaunchMode, OpenFocus, TriageAction, ReviewState, ExportFormat, ExportMenu, SeverityPicker, SortMode, SourceContextCache/keys). Adds `select_filtered_index`, scanning lifecycle fields and filter/sort/session state.|\n|**Core Input & Control Flow** <br> `src/tui/input.rs`|Adds `ControlFlow` and many `TuiApp` handlers: `handle_key`, modal handlers (`handle_search_key`, `handle_launch_key`, `handle_action_menu_key`, `handle_severity_picker_key`, `handle_export_menu_key`), mouse handling (`can_handle_finding_mouse`, `handle_mouse`), action plumbing (`open_action_menu`, `available_actions_for_finding`, `action_enabled`, `apply_action`, `action_preview`), export logic (`open_export_menu`, `export_findings(_to)`), open-target execution (`open_selected_finding`, `open_target`, open-source/sink helpers), and utilities (`cycle_session_min_confidence`, `cycle_sort_mode`, `open_severity_picker`).|\n|**Rendering / Widgets** <br> `src/tui/views.rs`, `src/tui/widgets.rs`|Implements `TuiApp::draw` and sub-drawers (launch, header, body, loading, footer, help, action/export/severity dialogs, compliance panel), source-context loading with cache, list/detail rendering, dataflow and open-target visuals, severity/confidence/crypto chips, shimmer loading, hit-testing and layout helpers, and many UI constants.|\n|**Terminal Lifecycle & Event Loop** <br> `src/tui/mod.rs`|Adds `run_scan_tui` entrypoint, `TerminalSession` lifecycle (enter/suspend/resume/Drop), worker thread spawn (`start_tui_execution`), worker message type, editor/OS open command construction (`open_command_spec_from_editor`), and `resolve_finding_path` logic.|\n|**Tests** <br> `src/tui/tests.rs`|Adds comprehensive unit tests covering hit-testing, path resolution, editor command parsing, scan start/rescan behaviors, rendering helpers, dataflow/source-context rendering, input interactions and modal behaviors, triage action persistence, compliance UI, chip styling, and export success/no-op cases.|\n|**Deps / Manifest** <br> `Cargo.toml`|Adds `shlex = \"1\"` dependency for editor command parsing. |\n\n## Sequence Diagram(s)\n\n```mermaid\nsequenceDiagram\n    participant User\n    participant Terminal as Terminal (crossterm/ratatui)\n    participant TUI as TuiApp\n    participant Worker as Background Scan Worker\n    participant FS as Filesystem\n    participant Editor as External Editor/Viewer\n\n    User->>Terminal: key/mouse event\n    Terminal->>TUI: deliver event\n    TUI->>TUI: handle_key / handle_mouse (modal routing)\n    alt Rescan requested\n        TUI->>Worker: start_tui_execution (spawn thread)\n        Worker->>TUI: WorkerMessage (result) via channel\n        TUI->>TUI: handle_worker_messages (update result)\n        TUI->>Terminal: redraw frame\n    end\n    alt Open file target\n        TUI->>FS: resolve_finding_path / read source (optional)\n        TUI->>Terminal: suspend TerminalSession\n        TUI->>Editor: spawn external command\n        Editor-->>TUI: exit code\n        TUI->>Terminal: resume TerminalSession and show notice\n    end\n```\n\n## Estimated code review effort\n\n🎯 4 (Complex) | ⏱️ ~60 minutes\n\n## Possibly related PRs\n\n- PwnKit-Labs/foxguard#259 — Overlaps TUI export flow and CBOM/JSON/SARIF export builders used by this PR.  \n- PwnKit-Labs/foxguard#281 — Related changes to list-state, mouse handling, and hover/select hit-testing now surfaced on TuiApp.\n\n## Suggested reviewers\n\n- peaktwilight\n\n## Poem\n\n> 🐰  \n> *I hopped into the terminal night,*  \n> *Colored badges glowing bright,*  \n> *Keys and clicks, a tidy stream,*  \n> *Findings sorted — hop! — a dream,*  \n> *Triage done with rabbit might.*\n\n</details>\n\n<!-- walkthrough_end -->\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 4 | ❌ 1</summary>\n\n### ❌ Failed checks (1 warning)\n\n|     Check name     | Status     | Explanation                                                                           | Resolution                                                                         |\n| :----------------: | :--------- | :------------------------------------------------------------------------------------ | :--------------------------------------------------------------------------------- |\n| Docstring Coverage | ⚠️ Warning | Docstring coverage is 45.58% which is insufficient. The required threshold is 80.00%. | Write docstrings for the functions missing them to satisfy the coverage threshold. |\n\n<details>\n<summary>✅ Passed checks (4 passed)</summary>\n\n|         Check name         | Status   | Explanation                                                                                                                                                                                                                           |\n| :------------------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n|      Description Check     | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled.                                                                                                                                                                           |\n|         Title check        | ✅ Passed | The title \"refactor(tui): split tui module\" clearly describes the main change—splitting a monolithic TUI implementation into separate module files—which aligns with the substantial refactoring across six files and 898+ new lines. |\n|     Linked Issues check    | ✅ Passed | Check skipped because no linked issues were found for this pull request.                                                                                                                                                              |\n| Out of Scope Changes check | ✅ Passed | Check skipped because no linked issues were found for this pull request.                                                                                                                                                              |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing Touches</summary>\n\n<details>\n<summary>📝 Generate docstrings</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> Create stacked PR\n- [ ] <!-- {\"checkboxId\": \"3e1879ae-f29b-4d0d-8e06-d12b7ba33d98\"} --> Commit on current branch\n\n</details>\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"6ba7b810-9dad-11d1-80b4-00c04fd430c8\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Commit unit tests in branch `273-tui-submodules`\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n<!-- tips_start -->\n\n---\n\n\n<!-- review_rate_limit_status_start -->\n<sub>Review rate limit: 9/10 reviews remaining, refill in 6 minutes.</sub>\n<!-- review_rate_limit_status_end -->\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- 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 -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"signal":{},"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/PwnKit-Labs/foxguard/issues/comments/4369155910","status":502,"headers":{"content-length":"32","content-type":"application/json","date":"Mon, 04 May 2026 15:36:25 GMT","etag":"\"69f8a486-20\"","server":"github.com","vary":"Accept-Encoding, Accept, X-Requested-With","x-github-request-id":"431C:ED956:182D11D:601EBC7:69F8BCEE","x-ratelimit-limit":"5000","x-ratelimit-remaining":"4847","x-ratelimit-reset":"1777910516","x-ratelimit-resource":"core","x-ratelimit-used":"153"},"data":{"message":"Server Error"}}}

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: 2

♻️ Duplicate comments (1)
src/tui/widgets.rs (1)

15-22: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Keep open-target selection aligned with description-only dataflow steps.

dataflow_lines() now renders source/sink entries when only the description exists, but available_open_focuses() still only checks source_line / sink_line. That leaves detail nodes that are visible but unreachable via Tab/Enter, and open_target_lines() omits them entirely.

♻️ Minimal fix
 pub(super) fn available_open_focuses(finding: &Finding) -> Vec<OpenFocus> {
     let mut focuses = vec![OpenFocus::Finding];
-    if finding.source_line.is_some() {
+    if finding.source_line.is_some() || finding.source_description.is_some() {
         focuses.push(OpenFocus::Source);
     }
-    if finding.sink_line.is_some() {
+    if finding.sink_line.is_some() || finding.sink_description.is_some() {
         focuses.push(OpenFocus::Sink);
     }
     focuses
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/tui/widgets.rs` around lines 15 - 22, available_open_focuses currently
only adds Source/Sink when finding.source_line / sink_line exist, but
dataflow_lines also renders entries when only source_description /
sink_description exist; update available_open_focuses (and mirror the same
predicate in open_target_lines) to consider description-only cases by checking
finding.source_line.is_some() || finding.source_description.is_some() and
finding.sink_line.is_some() || finding.sink_description.is_some() so the focus
options match what dataflow_lines renders and open_target_lines exposes.
🤖 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/tui/views.rs`:
- Around line 700-721: The sync fs::read_to_string call inside
source_context_lines (invoked from detail_text) must be removed and replaced
with a cache-driven async load: on selection change (where detail_text is
triggered) or via a background worker, call a loader that uses spawn_blocking/ a
threadpool to read the file found by resolve_finding_path and then compute
render_source_context, storing the resulting Vec<Line<'static>> into
source_context_cache (or a new enum state like Cached/Loading/Error) keyed by
SourceContextCacheKey; have source_context_lines simply read from
source_context_cache and return None or the cached lines immediately (no IO),
and ensure the loader posts an update/redraw when the cache is filled or on
error so the UI updates.

In `@src/tui/widgets.rs`:
- Around line 52-60: drain_queued_scroll_events is currently consuming the first
non-scroll Event and losing it; change the logic so that when event::read()
returns a non-scroll event you do not drop it but store it into a small shared
stash (e.g., a one-slot Mutex<Option<Event>> like STASHED_EVENT) and then break,
and update the global event-reading path to check and consume STASHED_EVENT
first before calling event::read(); implement helper functions (e.g.,
stash_event(event: Event) and pop_stashed_event() -> Option<Event>) and update
any callers to use pop_stashed_event_or_read() so the first non-scroll event is
preserved instead of being discarded by drain_queued_scroll_events.

---

Duplicate comments:
In `@src/tui/widgets.rs`:
- Around line 15-22: available_open_focuses currently only adds Source/Sink when
finding.source_line / sink_line exist, but dataflow_lines also renders entries
when only source_description / sink_description exist; update
available_open_focuses (and mirror the same predicate in open_target_lines) to
consider description-only cases by checking finding.source_line.is_some() ||
finding.source_description.is_some() and finding.sink_line.is_some() ||
finding.sink_description.is_some() so the focus options match what
dataflow_lines renders and open_target_lines exposes.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 78526d66-bba9-4bb6-8f6f-99025a31efcf

📥 Commits

Reviewing files that changed from the base of the PR and between f028491 and 024a02e.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (8)
  • Cargo.toml
  • src/tui.rs
  • src/tui/input.rs
  • src/tui/mod.rs
  • src/tui/state.rs
  • src/tui/tests.rs
  • src/tui/views.rs
  • src/tui/widgets.rs
✅ Files skipped from review due to trivial changes (3)
  • Cargo.toml
  • src/tui/state.rs
  • src/tui/mod.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/tui/input.rs
  • src/tui/tests.rs

Comment thread src/tui/views.rs Outdated
Comment thread src/tui/widgets.rs
@Darkroom4364 Darkroom4364 force-pushed the 273-tui-submodules branch from 024a02e to a9e2f53 Compare May 4, 2026 17:54
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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/tui/mod.rs`:
- Around line 127-137: The enter() function (and the similar block around
clear()) activates raw mode and switches to the alternate screen but returns
early on errors from execute!, Terminal::new, or clear(), leaving the terminal
in a modified state; update enter() (and the 156-170 block) to perform rollback
on every error path by undoing what succeeded: if enable_raw_mode() succeeded
but execute!(EnterAlternateScreen, EnableMouseCapture) later fails, call
execute!(LeaveAlternateScreen, DisableMouseCapture) and disable_raw_mode()
before returning; likewise, if execute! succeeded but Terminal::new or clear()
fails, run execute!(LeaveAlternateScreen, DisableMouseCapture) and
disable_raw_mode() to restore the terminal; factor this into a small cleanup
helper or use a scope guard around the EnterAlternateScreen/EnableMouseCapture
sequence to ensure consistent rollback on all early returns.
- Around line 248-270: The match against editor names uses basename (derived
from program) but doesn't normalize Windows variants like Code.exe or code.cmd,
so update the code that computes basename to strip common executable extensions
and lowercase it before the match (e.g., derive file_name as before, then call
file_stem() or strip_suffix for ".exe", ".cmd", ".bat" and then to_lowercase()).
Modify the variable used in the match (the existing basename) so the branches
(e.g., the "code"/"nvim"/"vim" arms) receive the normalized, lowercased stem and
will correctly match Windows $EDITOR values.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: eeaa8b88-74d7-44e3-9f3e-b47766d27afd

📥 Commits

Reviewing files that changed from the base of the PR and between f028491 and a9e2f53.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (8)
  • Cargo.toml
  • src/tui.rs
  • src/tui/input.rs
  • src/tui/mod.rs
  • src/tui/state.rs
  • src/tui/tests.rs
  • src/tui/views.rs
  • src/tui/widgets.rs
✅ Files skipped from review due to trivial changes (2)
  • Cargo.toml
  • src/tui/state.rs
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/tui/widgets.rs
  • src/tui/views.rs
  • src/tui/input.rs

Comment thread src/tui/mod.rs
Comment thread src/tui/mod.rs
@Darkroom4364 Darkroom4364 force-pushed the 273-tui-submodules branch from a9e2f53 to 9c589b8 Compare May 4, 2026 18:43
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