Skip to content

Conversation

@fcoury
Copy link
Contributor

@fcoury fcoury commented Jun 16, 2025

Summary

  • Implemented a plugin overlay system to eliminate visual flashing in the fidget plugin
  • Improved message formatting to match fidget.nvim's clean style
  • Added spinner animation that appears on the right side of active tasks

Problem

The fidget plugin was experiencing severe visual flashing issues where LSP progress messages would flicker constantly during rust-analyzer operations. Messages were also poorly formatted with redundant information.

Solution

  1. Created a Plugin Overlay System

    • New PluginOverlay structure with separate render buffers
    • Dirty region tracking to avoid unnecessary redraws
    • Support for different alignment options (top, bottom, avoid_cursor)
    • Messages now appear in bottom-right corner like fidget.nvim
  2. New Plugin API

    • red.createOverlay(id, config) - Create positioned overlays
    • red.updateOverlay(id, lines) - Update overlay content
    • red.removeOverlay(id) - Remove overlays
  3. Improved Message Formatting

    • Cleaner title extraction (e.g., "rustAnalyzer/Indexing" → "Indexing")
    • Better progress display (e.g., "Indexing: 17/21 (unicode_width)")
    • Animated spinner on the right side of active tasks
    • Checkmark icon for completed tasks

Test plan

  • Build the project with cargo build
  • Test with a Rust project to trigger rust-analyzer progress messages
  • Verify no visual flashing occurs
  • Confirm messages appear in bottom-right with proper formatting
  • Check that spinner animates on active tasks
  • Ensure completed tasks show checkmark

🤖 Generated with Claude Code

fcoury and others added 13 commits June 15, 2025 12:24
- Use Red's timer API instead of global setTimeout/clearTimeout
- Add proper debouncing to prevent creating multiple render timers
- Track removal timers separately to ensure proper cleanup
- Add error handling for async timer operations
- Increase poll rate from 10ms to 100ms to reduce timer pressure
- Add renderScheduled flag to prevent race conditions
- Increase poll rate to 500ms to avoid hitting timer limit
- Add documentation about current timer implementation limitations
- The root cause is that Red's timer implementation doesn't properly execute callbacks
- This is a temporary workaround until the timer system is improved
- Add TimeoutCallback variant to PluginRequest enum
- Modify op_set_timeout to send callback requests via ACTION_DISPATCHER
- Update JavaScript setTimeout to store callbacks and return timer IDs
- Add event listener for timeout:callback events
- Fix clearTimeout to properly clean up callbacks
- Add timer test plugin to validate functionality
- Update fidget plugin to use 100ms poll rate now that timers work

The timer system now properly executes callbacks when timers fire,
fixing the 'Too many timers' error and enabling plugins to use
timers effectively.
- Add timer_stats module to track timer usage per plugin
- Implement 'dt' debug command to dump timer statistics
- Add DumpTimers action to the debug command set
- Export timer_stats module for use in editor
- This helps identify plugins that are using excessive timers

The 'dt' command can be used in command mode to see which plugins
are creating timers and how many are active vs cleared.
Document the timer system improvements including:
- Problem description and root causes
- Implementation details of the fix
- Usage examples for plugin developers
- Debugging instructions
- Future improvement ideas
The previous timer implementation relied on tokio tasks that weren't
being polled properly due to the plugin runtime architecture. This
caused timers to never fire, preventing the fidget plugin from
displaying progress notifications.

Changes:
- Replace tokio-based timers with timestamp-based approach
- Poll for expired timers in main editor event loop every 10ms
- Add debug logging to track timer lifecycle
- Update fidget plugin with additional logging and refresh trigger

The timer callbacks now work reliably, allowing plugins like fidget
to update the display on a regular schedule.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
- Add new PluginOverlay system with separate render buffers
- Implement dirty region tracking to avoid unnecessary redraws
- Add overlay positioning with bottom-right alignment (fidget.nvim style)
- Create new plugin API methods: createOverlay, updateOverlay, removeOverlay
- Refactor fidget plugin to use overlay system instead of direct buffer rendering
- Messages now appear in bottom-right corner and stack upwards
- Eliminate visual flashing by rendering to overlay buffers

This provides a much smoother visual experience for LSP progress notifications,
similar to how fidget.nvim works in Neovim.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
The renderTimer variable was removed during the overlay system refactor
but a reference to it remained in the LSP progress handler, causing a
runtime error.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
- Add cleaner message formatting similar to fidget.nvim
- Extract titles from LSP tokens (e.g., "rustAnalyzer/Indexing" → "Indexing")
- Add spinner animation for in-progress tasks
- Add done checkmark icon for completed tasks
- Format rust-analyzer messages more cleanly (e.g., "Indexing: 17/21 (unicode_width)")
- Remove redundant information from progress displays

The messages now appear much cleaner and more readable, matching the
style of fidget.nvim's progress notifications.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
- Spinner now appears only on the last in-progress message
- Positioned on the right side of the text instead of left
- Completed tasks still show checkmark on the left
- Provides cleaner visual hierarchy with active task indicator

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
- Fix double spaces in progress messages
- Maintain proper capitalization for common terms (Fetching, Building, Loading)
- Handle special cases like 'buildArtifacts' → 'build-artifacts'
- Improve right-alignment rendering in overlay system
- Use proper Unicode character counting for text positioning

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
- Add width calculation based on editor size
- Truncate messages from the left side when they exceed available width
- Add ellipsis (...) at the beginning of truncated messages
- Ensures messages stay within editor bounds and remain right-aligned

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
- Add Default derive for OverlayManager instead of manual implementation
- Add Default derive for TimerUsage instead of manual implementation
- Follows clippy's recommendations for cleaner, more idiomatic code

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
@fcoury fcoury requested a review from Copilot June 16, 2025 15:49
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This pull request fixes the fidget plugin’s visual flashing issues and improves message formatting by introducing a plugin overlay system and integrating a refined timer management mechanism. Key changes include:

  • A new overlay API with create, update, and remove operations for flicker‐free overlay rendering
  • A reworked timer system that replaces the old timeout tracking with a polling-based callback mechanism and adds timer statistics
  • Updates to the fidget plugin and editor integration to use the new overlay and timer APIs

Reviewed Changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/plugin/timer_stats.rs Adds timer usage tracking with creation and clearing statistics
src/plugin/runtime.rs Reworks timeout handling with a polling mechanism and adds overlay ops
src/plugin/runtime.js Updates JS timer functions and overlay API integration
src/plugin/overlay.rs Implements overlay rendering and positioning logic
src/plugin/mod.rs Exports new overlay and timer modules
src/editor/rendering.rs / src/editor.rs Incorporates overlay updates and timer callback processing into the editor
plugins/fidget.js Enhances the fidget plugin with clean message formatting and spinner animation
examples/timer-test.js Provides tests validating timer callback functionality
docs/TIMER_IMPROVEMENTS.md Documents updated timer and overlay implementations
.hookman/hooks/pre-push.toml & ci.yml Minor CI and pre-push hook updates
Comments suppressed due to low confidence (1)

src/plugin/runtime.js:187

  • [nitpick] Consider adding additional error handling or a retry mechanism in the animation loop to avoid the spinner animation stopping unexpectedly if red.setTimeout fails. This can help maintain a smoother user interface experience.
animationTimer = await red.setTimeout(() => animate(), 100);

@fcoury fcoury merged commit c3820a8 into master Jun 16, 2025
32 checks passed
@fcoury fcoury deleted the fix-fidget branch June 16, 2025 15:53
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.

2 participants