Skip to content

Cursor#28

Merged
vimlinuz merged 5 commits into
mainfrom
cursor
Jan 2, 2026
Merged

Cursor#28
vimlinuz merged 5 commits into
mainfrom
cursor

Conversation

@vimlinuz

@vimlinuz vimlinuz commented Jan 2, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • Bug Fixes
    • Fixed cursor rerendering by centralizing cursor handling so it behaves consistently during popups.
  • New Features
    • Added "disconnect from current network" option to the help menu.
  • Refactor
    • Consolidated cursor visibility and blinking control into a single draw path, removing scattered cursor side effects.
  • Documentation
    • Updated changelog with the fixed cursor entry.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Jan 2, 2026

Copy link
Copy Markdown
Contributor

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

Centralizes terminal cursor control by removing cursor side-effects from widget render paths and adding cursor positioning and blinking management to App::draw; renames help constant and adds a disconnect help line; documents the fix in CHANGELOG.

Changes

Cohort / File(s) Summary
Changelog
CHANGELOG.md
Added a Fixed entry noting cursor rerendering issue fixed by moving cursor control from render to draw
App — centralized cursor handling
src/apps/core.rs
Added crossterm imports and execute! use; implemented App::draw side-effects to set terminal cursor position, show/hide cursor, and toggle blinking based on Wi‑Fi popup state; added exit flag setter
Widgets — removed direct cursor side-effects & help text
src/apps/core/widget.rs
Removed scattered terminal cursor commands (Show/Hide, MoveTo, DisableBlinking/EnableBlinking) from multiple render branches; renamed HELP_TESTHELP_TEXT and appended "(x) disconnect from current network" to help lines

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • Cursor #28 — Implements the same cursor-handling migration (move cursor logic from render to App::draw) and the HELP_TEXT update.

Poem

🐰 I hopped through code with careful paws,
I pulled the cursor from scattered laws,
Now draw holds the light where blinking stays,
Help gained a line to cut old ways,
A tidy hop — no more cursor strays ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Cursor' is vague and overly generic, providing minimal information about what was actually changed despite meaningful refactoring work. Use a more descriptive title such as 'Refactor cursor management to draw method' or 'Move cursor rendering from widget to draw method' to clearly convey the main architectural change.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c3050b0 and ecc9b9b.

📒 Files selected for processing (2)
  • src/apps/core.rs
  • src/apps/core/widget.rs

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

@coderabbitai

coderabbitai Bot commented Jan 2, 2026

Copy link
Copy Markdown
Contributor

Note

Docstrings generation - SUCCESS
Generated docstrings for this pull request at #29

Docstrings generation was requested by @santoshxshrestha.

* #28 (comment)

The following files were modified:

* `src/apps/core.rs`
* `src/apps/core/widget.rs`

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
CHANGELOG.md (1)

9-9: Minor grammar correction.

The phrase "placing it to the draw method" should be "placing it in the draw method" for proper grammar.

🔎 Suggested fix
-- Fixed the rerendering issue of the cursor by removing it from the render method and placing it to the draw method.
+- Fixed the rerendering issue of the cursor by removing it from the render method and placing it in the draw method.
src/apps/core.rs (1)

73-78: Simplify the overly verbose comment.

The comment explaining io::stdout() usage spans 6 lines and covers basic concepts. This level of detail is unnecessary for developers familiar with the codebase.

🔎 Suggested simplification
-            // The reason for using io::stdout() here is that the crossterm execute! macro needs a writable output target to send
-            // terminal commands to. io::stdout() provides a handle to the standard output (the terminal), so the commands (Show, MoveTo, EnableBlinking)
-            // are sent to the terminal for immediate effect.
-            //
-            // If you remove io::stdout(), execute! won't know where to send the commands, resulting in a compilation error.
-            // You must provide a valid output stream (like io::stdout()) for terminal control commands to work.
-            // EnableBlinking
+            // Use io::stdout() as the output target for crossterm terminal commands
             let _ = execute!(io::stdout(), cursor::Show, EnableBlinking);
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1d49e85 and c3050b0.

📒 Files selected for processing (3)
  • CHANGELOG.md
  • src/apps/core.rs
  • src/apps/core/widget.rs
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-29T17:44:05.883Z
Learnt from: santoshxshrestha
Repo: santoshxshrestha/nmtui PR: 0
File: :0-0
Timestamp: 2025-12-29T17:44:05.883Z
Learning: In the santoshxshrestha/nmtui project, input field handlers (SSID and password handlers in src/apps/handlers/ssid_handler.rs and src/apps/handlers/password_handler.rs) intentionally do not include Ctrl+C or global help handlers to avoid the performance overhead of sharing app state and additional polling that would make the program laggy.

Applied to files:

  • src/apps/core/widget.rs
  • src/apps/core.rs
🔇 Additional comments (3)
src/apps/core/widget.rs (2)

17-30: LGTM! Good refactoring.

The renaming from HELP_TEST to HELP_TEXT improves clarity, and the addition of the disconnect command to the help text provides better user guidance.


175-175: LGTM! Consistent with constant rename.

The usage has been correctly updated to reference the renamed HELP_TEXT constant.

src/apps/core.rs (1)

13-19: LGTM! Necessary imports for cursor control.

The new imports support the centralized cursor handling logic in the draw method.

Comment thread src/apps/core.rs
Comment on lines +65 to +83
// Set cursor position for SSID or Password popups
if self.wifi_credentials.flags.show_ssid_popup
|| self.wifi_credentials.flags.show_password_popup
{
frame.set_cursor_position(Position::new(
frame.area().x + frame.area().width / 4 + self.wifi_credentials.cursor_pos + 1,
frame.area().y + frame.area().height / 4 + 1,
));
// The reason for using io::stdout() here is that the crossterm execute! macro needs a writable output target to send
// terminal commands to. io::stdout() provides a handle to the standard output (the terminal), so the commands (Show, MoveTo, EnableBlinking)
// are sent to the terminal for immediate effect.
//
// If you remove io::stdout(), execute! won’t know where to send the commands, resulting in a compilation error.
// You must provide a valid output stream (like io::stdout()) for terminal control commands to work.
// EnableBlinking
let _ = execute!(io::stdout(), cursor::Show, EnableBlinking);
} else {
let _ = execute!(io::stdout(), cursor::Hide, DisableBlinking);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Silently ignoring terminal control errors could cause UX issues.

The let _ = execute!(...) pattern on lines 80 and 82 silently discards any errors from cursor visibility/blinking commands. If these operations fail, the cursor could be left in an inconsistent state, degrading the user experience.

Consider logging errors or handling them gracefully to ensure cursor state problems are detectable.

🔎 Proposed fix to handle errors
-            let _ = execute!(io::stdout(), cursor::Show, EnableBlinking);
+            if let Err(e) = execute!(io::stdout(), cursor::Show, EnableBlinking) {
+                eprintln!("Failed to show cursor: {}", e);
+            }
         } else {
-            let _ = execute!(io::stdout(), cursor::Hide, DisableBlinking);
+            if let Err(e) = execute!(io::stdout(), cursor::Hide, DisableBlinking) {
+                eprintln!("Failed to hide cursor: {}", e);
+            }
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Set cursor position for SSID or Password popups
if self.wifi_credentials.flags.show_ssid_popup
|| self.wifi_credentials.flags.show_password_popup
{
frame.set_cursor_position(Position::new(
frame.area().x + frame.area().width / 4 + self.wifi_credentials.cursor_pos + 1,
frame.area().y + frame.area().height / 4 + 1,
));
// The reason for using io::stdout() here is that the crossterm execute! macro needs a writable output target to send
// terminal commands to. io::stdout() provides a handle to the standard output (the terminal), so the commands (Show, MoveTo, EnableBlinking)
// are sent to the terminal for immediate effect.
//
// If you remove io::stdout(), execute! won’t know where to send the commands, resulting in a compilation error.
// You must provide a valid output stream (like io::stdout()) for terminal control commands to work.
// EnableBlinking
let _ = execute!(io::stdout(), cursor::Show, EnableBlinking);
} else {
let _ = execute!(io::stdout(), cursor::Hide, DisableBlinking);
}
// Set cursor position for SSID or Password popups
if self.wifi_credentials.flags.show_ssid_popup
|| self.wifi_credentials.flags.show_password_popup
{
frame.set_cursor_position(Position::new(
frame.area().x + frame.area().width / 4 + self.wifi_credentials.cursor_pos + 1,
frame.area().y + frame.area().height / 4 + 1,
));
// The reason for using io::stdout() here is that the crossterm execute! macro needs a writable output target to send
// terminal commands to. io::stdout() provides a handle to the standard output (the terminal), so the commands (Show, MoveTo, EnableBlinking)
// are sent to the terminal for immediate effect.
//
// If you remove io::stdout(), execute! won't know where to send the commands, resulting in a compilation error.
// You must provide a valid output stream (like io::stdout()) for terminal control commands to work.
// EnableBlinking
if let Err(e) = execute!(io::stdout(), cursor::Show, EnableBlinking) {
eprintln!("Failed to show cursor: {}", e);
}
} else {
if let Err(e) = execute!(io::stdout(), cursor::Hide, DisableBlinking) {
eprintln!("Failed to hide cursor: {}", e);
}
}
🤖 Prompt for AI Agents
In src/apps/core.rs around lines 65 to 83, the execute!(io::stdout(), ...) calls
currently use `let _ =` which discards errors; change these to handle the
Result: call execute! and match or use if let Err(e) = ... to log the error
(using the existing logger) and attempt a safe fallback to restore cursor state
(e.g., try the opposite command or ensure cursor is hidden/shown on error).
Ensure both the Show/EnableBlinking and Hide/DisableBlinking paths handle Err by
logging the error with context and performing a best-effort cleanup to keep
terminal cursor state consistent.

Comment thread src/apps/core.rs
Comment on lines +69 to +72
frame.set_cursor_position(Position::new(
frame.area().x + frame.area().width / 4 + self.wifi_credentials.cursor_pos + 1,
frame.area().y + frame.area().height / 4 + 1,
));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for cursor_pos assignments and modifications in the codebase
rg -nP --type=rust 'cursor_pos\s*[=+\-]' -B3 -A3

Repository: santoshxshrestha/nmtui

Length of output: 2774


🏁 Script executed:

#!/bin/bash
# Find the popup rendering code in core.rs
rg -nP --type=rust 'width\s*/\s*2' src/apps/core.rs -B5 -A5

Repository: santoshxshrestha/nmtui

Length of output: 48


🏁 Script executed:

#!/bin/bash
# Search for popup rendering code
rg -nP --type=rust 'Block|Paragraph|show_ssid_popup|show_password_popup' src/apps/core.rs -B2 -A2 | head -80

Repository: santoshxshrestha/nmtui

Length of output: 1267


🏁 Script executed:

#!/bin/bash
# Search for render functions related to SSID/password
rg -nP --type=rust 'render.*ssid|render.*password|fn.*ssid|fn.*password' src/apps/core.rs -B2 -A8 | head -100

Repository: santoshxshrestha/nmtui

Length of output: 48


🏁 Script executed:

#!/bin/bash
# Get the size of core.rs and read relevant sections
wc -l src/apps/core.rs
echo "---"
# Look for widget/block creation around the cursor position code
sed -n '50,150p' src/apps/core.rs | cat -n

Repository: santoshxshrestha/nmtui

Length of output: 5497


🏁 Script executed:

#!/bin/bash
# Read the entire core.rs file
cat -n src/apps/core.rs

Repository: santoshxshrestha/nmtui

Length of output: 7739


🏁 Script executed:

#!/bin/bash
# Find widget implementation
fd widget src/apps/ -type f
echo "---"
# If widget.rs exists, show its size
if [ -f src/apps/widget.rs ]; then
  wc -l src/apps/widget.rs
fi
if [ -d src/apps/widget ]; then
  ls -la src/apps/widget/
fi

Repository: santoshxshrestha/nmtui

Length of output: 257


🏁 Script executed:

#!/bin/bash
# Find widget implementation
find src/apps -name "widget*" -o -name "Widget*"
echo "---"
# Look for widget in imports or module declarations
rg -n "mod widget" src/apps/

Repository: santoshxshrestha/nmtui

Length of output: 124


🏁 Script executed:

#!/bin/bash
# Check size and read widget.rs
wc -l src/apps/core/widget.rs
echo "---"
cat -n src/apps/core/widget.rs

Repository: santoshxshrestha/nmtui

Length of output: 13033


Bound cursor position to popup width, not just input string length.

The cursor position calculation (frame.area().x + frame.area().width / 4 + self.wifi_credentials.cursor_pos + 1) has no constraint to keep it within the popup boundaries. While cursor_pos is bounded to the input string's character count in the handlers, it is not bounded to the popup width (area.width / 2). If an input string is very long (longer than the popup can display), the cursor would render outside the visible popup area.

Update the move_cursor_right function in src/apps/handlers/utils.rs to also cap cursor_pos to the popup width (accounting for borders and padding).

🤖 Prompt for AI Agents
In src/apps/core.rs around lines 69-72 the cursor is positioned using
self.wifi_credentials.cursor_pos without constraining it to the popup width;
update src/apps/handlers/utils.rs (move_cursor_right) to clamp cursor_pos to the
visible input area width of the popup: compute popup_width = frame.area().width
/ 2 (as used for the popup), subtract any borders/padding (e.g. 2 for borders
and any left padding) to get visible_input_width, then set cursor_pos =
min(cursor_pos, visible_input_width.saturating_sub(1)) when moving right so the
cursor can never be placed beyond the popup's drawable area; ensure the same
clamping logic is applied wherever cursor_pos is modified.

@vimlinuz vimlinuz merged commit e0d721b into main Jan 2, 2026
1 check passed
@vimlinuz vimlinuz deleted the cursor branch January 2, 2026 21:07
@coderabbitai coderabbitai Bot mentioned this pull request Jan 3, 2026
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