[codex] Keep followed files current while inactive - #112
Merged
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new “Follow Mode” for the macOS port so external file changes continue to update the underlying document state while the tab is inactive, and introduces an “age heatmap” UI strip plus menu/tab integrations to control and visualize follow state.
Changes:
- Add follow-mode core logic (per-file FSEvents watches, background DocumentData updates, and controlled mirroring into the visible Scintilla view).
- Add UI plumbing: View-menu and tab context menu actions, a tab “eye” indicator, and a right-edge age bar with configurable colors/thresholds.
- Persist follow-mode settings in app settings/preferences and wire them into app startup.
Reviewed changes
Copilot reviewed 21 out of 21 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| macos/platform/wndproc.mm | Adds View-menu command handler for toggling follow mode. |
| macos/platform/tab_context_menu.mm | Adds tab context-menu item to toggle follow mode per tab. |
| macos/platform/tab_bar_view.mm | Renders a “followed” indicator (eye icon) in tabs. |
| macos/platform/tab_bar_view.h | Exposes followed-state setters/getters for tab items. |
| macos/platform/split_view.mm | Uses editor container that can host the age bar; hooks scrolling/modified notifications for follow/age-bar refresh. |
| macos/platform/settings_manager.mm | Loads/saves follow-mode colors and age thresholds to JSON. |
| macos/platform/settings_manager.h | Adds follow-mode settings fields and defaults. |
| macos/platform/preferences_dialog.mm | Adds preferences UI for follow-mode colors/thresholds and triggers age-bar refresh on apply. |
| macos/platform/npp_constants.h | Defines new command IDs for follow mode and tab context follow action. |
| macos/platform/menu_builder.mm | Adds View-menu item and shortcut for follow mode. |
| macos/platform/follow_mode.mm | Implements follow-mode behavior (watching, background updates, Scintilla mirroring, line-age tracking). |
| macos/platform/follow_mode.h | Declares follow-mode toggle/update hooks for UI/Scintilla notifications. |
| macos/platform/file_monitor_mac.mm | Extends file monitor with per-file FSEvents streams and callbacks. |
| macos/platform/file_monitor_mac.h | Declares per-file watch APIs. |
| macos/platform/document_manager.mm | Integrates follow-mode UI refresh on tab activation and stops follow plumbing on close. |
| macos/platform/document_data.h | Adds follow-mode state to per-document data (flags, birth times, file size). |
| macos/platform/app_state.h | Adds global follow-mode settings and suppression flag for programmatic Scintilla restores. |
| macos/platform/app_delegate.mm | Installs editor container capable of hosting the age bar and wires follow/age-bar invalidation into notifications. |
| macos/platform/age_bar_view.mm | Implements the age heatmap view and editor container layout logic. |
| macos/platform/age_bar_view.h | Declares the age bar view, editor container, and invalidation helpers. |
| macos/CMakeLists.txt | Adds new follow-mode/age-bar sources to the macOS build. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+677
to
+689
| case IDM_VIEW_FOLLOW: | ||
| { | ||
| toggleFollowModeForActiveTab(ctx().activeView); | ||
| HMENU hMenu = GetMenu(hWnd); | ||
| if (hMenu) | ||
| { | ||
| int tab = (ctx().activeView == 0) ? ctx().activeTab : ctx().activeTab2; | ||
| auto& docs = (ctx().activeView == 0) ? ctx().documents : ctx().documents2; | ||
| bool on = (tab >= 0 && tab < (int)docs.size() && docs[tab].followMode); | ||
| CheckMenuItem(hMenu, IDM_VIEW_FOLLOW, | ||
| MF_BYCOMMAND | (on ? MF_CHECKED : MF_UNCHECKED)); | ||
| } | ||
| return 0; |
Comment on lines
+28
to
+35
| static NSMutableArray<NppAgeBarView*>* sLiveBars = nil; | ||
| static NSTimer* sTickTimer = nil; | ||
|
|
||
| static void ensureBarRegistry() | ||
| { | ||
| if (!sLiveBars) | ||
| sLiveBars = [NSMutableArray array]; | ||
| } |
| std::wstring widePath = UTF8ToWide([nsPath UTF8String]); | ||
|
|
||
| if (fwc && fwc->callback) | ||
| fwc->callback(action, widePath); |
Comment on lines
+215
to
+223
| // If already watching, replace the callback in-place. | ||
| for (size_t i = 0; i < m_impl->watchedFiles.size(); ++i) | ||
| { | ||
| if (m_impl->watchedFiles[i] == path) | ||
| { | ||
| m_impl->fileCallbacks[i] = std::move(callback); | ||
| return true; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Root Cause
Follow-mode file monitor callbacks previously treated Scintilla as the canonical buffer. When the followed tab was inactive, callbacks skipped the update path, so the stored DocumentData stayed stale until a later catch-up path ran.
Impact
A followed file now keeps advancing in the background without stealing focus or mutating an inactive Scintilla view. Switching back to the tab restores already-current content and reattaches the editor to the bottom.
Validation