-
-
Notifications
You must be signed in to change notification settings - Fork 442
Asynchronous Loading & Initialization Plugin Model to Improve Window Startup Speed #3854
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Conversation
This comment has been minimized.
This comment has been minimized.
Be a legend 🏆 by adding a before and after screenshot of the changes you made, especially if they are around UI/UX. |
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. 📝 WalkthroughWalkthroughAdds a per-plugin result-update registration interface, rewrites PluginManager to use thread-safe concurrent collections and refined lifecycle flows, defers plugin initialization off main startup, introduces single-plugin metadata translation updater, enables incremental DialogJump plugin registration, and updates callers and viewmodels to the new PluginManager accessors and APIs. Changes
Sequence Diagram(s)sequenceDiagram
participant App as App (startup)
participant PM as PluginManager
participant MV as MainViewModel (IResultUpdateRegister)
participant P as PluginPair
App->>PM: LoadPlugins(settings)
App->>PM: InitializePluginsAsync(register=MV)
PM->>MV: RegisterResultsUpdatedEvent(P) for each plugin
MV->>P: Subscribe if P implements IResultUpdated
sequenceDiagram
participant P as PluginPair
participant MV as MainViewModel
participant UI as UI
P->>MV: ResultsUpdated(results, token)
MV->>MV: Validate QueryText & token
alt valid
MV->>MV: Clone results, set badge icons, update metadata
MV->>UI: Enqueue results for display
else cancelled/irrelevant
Note right of MV: ignore update
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this 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
🔭 Outside diff range comments (2)
Flow.Launcher.Infrastructure/DialogJump/DialogJump.cs (1)
710-710
: Fix typo in log message- API.LogDebug(ClassName, $"Destory dialog: {hwnd}"); + API.LogDebug(ClassName, $"Destroy dialog: {hwnd}");Flow.Launcher/App.xaml.cs (1)
413-413
: Fix spelling error in comment.Pipeline failure indicates "acees" should be "access".
- // So here we need to check it and just return so that we will not acees _mainWindow?.Dispatcher + // So here we need to check it and just return so that we will not access _mainWindow?.Dispatcher
🧹 Nitpick comments (6)
Flow.Launcher.Core/Resource/Internationalization.cs (1)
370-384
: Consider refactoring to eliminate code duplicationThe implementation looks correct. However, this method duplicates the logic from
UpdatePluginMetadataTranslations
(lines 356-367). Consider refactoring the existing method to use this new one to maintain DRY principles.public static void UpdatePluginMetadataTranslations() { // Update plugin metadata name & description foreach (var p in PluginManager.GetTranslationPlugins()) { - if (p.Plugin is not IPluginI18n pluginI18N) return; - try - { - p.Metadata.Name = pluginI18N.GetTranslatedPluginTitle(); - p.Metadata.Description = pluginI18N.GetTranslatedPluginDescription(); - pluginI18N.OnCultureInfoChanged(CultureInfo.CurrentCulture); - } - catch (Exception e) - { - API.LogException(ClassName, $"Failed for <{p.Metadata.Name}>", e); - } + UpdatePluginMetadataTranslation(p); } }Flow.Launcher/App.xaml.cs (1)
184-185
: Minor improvement: Move log level setup comment.The comment positioning could be improved for better readability.
- // Setup log level before any logging is done - Log.SetLogLevel(_settings.LogLevel); + // Setup log level before any logging is done + Log.SetLogLevel(_settings.LogLevel);Flow.Launcher.Core/Plugin/PluginManager.cs (4)
609-617
: Consider using AddOrUpdate for atomic operations.While the current implementation is thread-safe, there's a small window between
TryGetValue
andTryAdd
where another thread could add the same key. Consider usingAddOrUpdate
for a more atomic operation:-if (_nonGlobalPlugins.TryGetValue(newActionKeyword, out var item)) -{ - _nonGlobalPlugins.TryUpdate(newActionKeyword, plugin, item); -} -else -{ - _nonGlobalPlugins.TryAdd(newActionKeyword, plugin); -} +_nonGlobalPlugins.AddOrUpdate(newActionKeyword, plugin, (key, oldValue) => plugin);
502-502
: Fix typo in comment.-// Plugins may have multi-actionkeywords eg. WebSearches. In this scenario it needs to be overriden on the plugin level +// Plugins may have multi-actionkeywords eg. WebSearches. In this scenario it needs to be overridden on the plugin level
361-361
: Consider using collection expressions consistently.For consistency with the rest of the file, consider replacing
Array.Empty<PluginPair>()
with collection expressions:-return Array.Empty<PluginPair>(); +return [];Also applies to: 372-372, 377-377
887-893
: Use discard for unused out parameters.The out parameters in TryRemove operations are not used. Consider using discards for clarity:
-_allPlugins.TryRemove(plugin.ID, out var item); -_globalPlugins.TryRemove(plugin.ID, out var item1); +_allPlugins.TryRemove(plugin.ID, out _); +_globalPlugins.TryRemove(plugin.ID, out _);-_nonGlobalPlugins.Remove(key, out var item2); +_nonGlobalPlugins.TryRemove(key, out _);Also note: Use
TryRemove
instead ofRemove
forConcurrentDictionary
(line 892).
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
Flow.Launcher.Core/Plugin/IResultUpdateRegister.cs
(1 hunks)Flow.Launcher.Core/Plugin/PluginManager.cs
(21 hunks)Flow.Launcher.Core/Resource/Internationalization.cs
(1 hunks)Flow.Launcher.Infrastructure/DialogJump/DialogJump.cs
(4 hunks)Flow.Launcher/App.xaml.cs
(3 hunks)Flow.Launcher/MainWindow.xaml.cs
(2 hunks)Flow.Launcher/PublicAPIInstance.cs
(1 hunks)Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginsViewModel.cs
(1 hunks)Flow.Launcher/ViewModel/MainViewModel.cs
(7 hunks)
🧰 Additional context used
🧠 Learnings (10)
📓 Common learnings
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3791
File: Flow.Launcher.Core/Plugin/PluginManager.cs:293-295
Timestamp: 2025-07-01T05:46:13.251Z
Learning: In Flow.Launcher.Core/Plugin/PluginManager.cs, when checking if a plugin is modified within the PluginManager class itself, prefer using the internal static PluginModified(string id) method directly rather than going through API.PluginModified() for better performance and architectural design.
Flow.Launcher.Core/Plugin/IResultUpdateRegister.cs (2)
Learnt from: Jack251970
PR: #3572
File: Flow.Launcher/App.xaml.cs:214-216
Timestamp: 2025-07-06T12:21:37.947Z
Learning: In Flow Launcher, the UpdatePluginManifestAsync method in PluginsManifest.cs already has comprehensive internal try-catch handling that logs exceptions and returns false on failure rather than throwing, making external try-catch wrappers unnecessary.
Learnt from: Jack251970
PR: #3791
File: Flow.Launcher.Core/Plugin/PluginManager.cs:293-295
Timestamp: 2025-07-01T05:46:13.251Z
Learning: In Flow.Launcher.Core/Plugin/PluginManager.cs, when checking if a plugin is modified within the PluginManager class itself, prefer using the internal static PluginModified(string id) method directly rather than going through API.PluginModified() for better performance and architectural design.
Flow.Launcher/MainWindow.xaml.cs (5)
Learnt from: Jack251970
PR: #3791
File: Flow.Launcher.Core/Plugin/PluginManager.cs:293-295
Timestamp: 2025-07-01T05:46:13.251Z
Learning: In Flow.Launcher.Core/Plugin/PluginManager.cs, when checking if a plugin is modified within the PluginManager class itself, prefer using the internal static PluginModified(string id) method directly rather than going through API.PluginModified() for better performance and architectural design.
Learnt from: Jack251970
PR: #3672
File: Flow.Launcher/MainWindow.xaml.cs:244-247
Timestamp: 2025-06-08T14:12:21.348Z
Learning: In Flow.Launcher, App.NotifyIcon is created before MainWindow creation, so null checks for App.NotifyIcon are not necessary when accessing it from MainWindow code.
Learnt from: Yusyuriv
PR: #3057
File: Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs:0-0
Timestamp: 2024-11-03T07:40:11.014Z
Learning: In Flow Launcher, when using Windows Forms dialogs (e.g., in JsonRPCPluginSettings.cs
), path validation is enabled by default in OpenFileDialog
and FolderBrowserDialog
, preventing users from selecting invalid paths, but it's possible to opt out of this validation on individual dialogs.
Learnt from: Jack251970
PR: #3572
File: Flow.Launcher/App.xaml.cs:214-216
Timestamp: 2025-07-06T12:21:37.947Z
Learning: In Flow Launcher, the UpdatePluginManifestAsync method in PluginsManifest.cs already has comprehensive internal try-catch handling that logs exceptions and returns false on failure rather than throwing, making external try-catch wrappers unnecessary.
Learnt from: onesounds
PR: #3394
File: Flow.Launcher/Themes/Darker Glass.xaml:134-141
Timestamp: 2025-03-28T21:12:13.386Z
Learning: In Flow.Launcher, hotkey styling is implemented with a two-component structure: a Border element with style ItemHotkeyBGStyle
that provides background and border styling, containing a TextBlock with style ItemHotkeyStyle
that handles the text styling.
Flow.Launcher.Core/Resource/Internationalization.cs (4)
Learnt from: Jack251970
PR: #3572
File: Flow.Launcher/App.xaml.cs:214-216
Timestamp: 2025-07-06T12:21:37.947Z
Learning: In Flow Launcher, the UpdatePluginManifestAsync method in PluginsManifest.cs already has comprehensive internal try-catch handling that logs exceptions and returns false on failure rather than throwing, making external try-catch wrappers unnecessary.
Learnt from: Jack251970
PR: #3791
File: Flow.Launcher.Core/Plugin/PluginManager.cs:293-295
Timestamp: 2025-07-01T05:46:13.251Z
Learning: In Flow.Launcher.Core/Plugin/PluginManager.cs, when checking if a plugin is modified within the PluginManager class itself, prefer using the internal static PluginModified(string id) method directly rather than going through API.PluginModified() for better performance and architectural design.
Learnt from: Jack251970
PR: #3850
File: Flow.Launcher.Core/Resource/Internationalization.cs:0-0
Timestamp: 2025-07-20T07:28:28.055Z
Learning: In Flow Launcher's Internationalization class, when the Flow Launcher language directory or default language file is missing, the only viable approach is to log an error and return early - there are no fallback mechanisms or alternative recovery strategies available due to architectural constraints.
Learnt from: taooceros
PR: #2616
File: Flow.Launcher/Flow.Launcher.csproj:7-7
Timestamp: 2024-10-08T15:52:58.573Z
Learning: In the Flow Launcher project, the version number in the Flow.Launcher.csproj
file is dynamically updated during the CI/CD process.
Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginsViewModel.cs (2)
Learnt from: Jack251970
PR: #3791
File: Flow.Launcher.Core/Plugin/PluginManager.cs:293-295
Timestamp: 2025-07-01T05:46:13.251Z
Learning: In Flow.Launcher.Core/Plugin/PluginManager.cs, when checking if a plugin is modified within the PluginManager class itself, prefer using the internal static PluginModified(string id) method directly rather than going through API.PluginModified() for better performance and architectural design.
Learnt from: Jack251970
PR: #3572
File: Flow.Launcher/App.xaml.cs:214-216
Timestamp: 2025-07-06T12:21:37.947Z
Learning: In Flow Launcher, the UpdatePluginManifestAsync method in PluginsManifest.cs already has comprehensive internal try-catch handling that logs exceptions and returns false on failure rather than throwing, making external try-catch wrappers unnecessary.
Flow.Launcher/App.xaml.cs (9)
Learnt from: Jack251970
PR: #3791
File: Flow.Launcher.Core/Plugin/PluginManager.cs:293-295
Timestamp: 2025-07-01T05:46:13.251Z
Learning: In Flow.Launcher.Core/Plugin/PluginManager.cs, when checking if a plugin is modified within the PluginManager class itself, prefer using the internal static PluginModified(string id) method directly rather than going through API.PluginModified() for better performance and architectural design.
Learnt from: Jack251970
PR: #3672
File: Flow.Launcher/MainWindow.xaml.cs:244-247
Timestamp: 2025-06-08T14:12:21.348Z
Learning: In Flow.Launcher, App.NotifyIcon is created before MainWindow creation, so null checks for App.NotifyIcon are not necessary when accessing it from MainWindow code.
Learnt from: Jack251970
PR: #3672
File: Flow.Launcher/MainWindow.xaml.cs:318-318
Timestamp: 2025-06-08T14:12:12.842Z
Learning: In Flow.Launcher, the App.NotifyIcon static property is initialized in the App class before MainWindow creation, so null checks are not needed when accessing App.NotifyIcon in MainWindow lifecycle methods.
Learnt from: Jack251970
PR: #3572
File: Flow.Launcher/App.xaml.cs:214-216
Timestamp: 2025-07-06T12:21:37.947Z
Learning: In Flow Launcher, the UpdatePluginManifestAsync method in PluginsManifest.cs already has comprehensive internal try-catch handling that logs exceptions and returns false on failure rather than throwing, making external try-catch wrappers unnecessary.
Learnt from: taooceros
PR: #2616
File: Flow.Launcher/Flow.Launcher.csproj:7-7
Timestamp: 2024-10-08T15:52:58.573Z
Learning: In the Flow Launcher project, the version number in the Flow.Launcher.csproj
file is dynamically updated during the CI/CD process.
Learnt from: jjw24
PR: #2448
File: Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs:16-20
Timestamp: 2025-01-18T10:10:18.414Z
Learning: In Flow Launcher's plugin system, the PluginInitContext parameter passed to plugin constructors is guaranteed to be non-null by the plugin initialization system, making null checks unnecessary.
Learnt from: Yusyuriv
PR: #3057
File: Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs:0-0
Timestamp: 2024-11-03T07:40:11.014Z
Learning: In Flow Launcher, when using Windows Forms dialogs (e.g., in JsonRPCPluginSettings.cs
), path validation is enabled by default in OpenFileDialog
and FolderBrowserDialog
, preventing users from selecting invalid paths, but it's possible to opt out of this validation on individual dialogs.
Learnt from: Jack251970
PR: #3850
File: Flow.Launcher.Core/Resource/Internationalization.cs:0-0
Timestamp: 2025-07-20T07:28:28.055Z
Learning: In Flow Launcher's Internationalization class, when the Flow Launcher language directory or default language file is missing, the only viable approach is to log an error and return early - there are no fallback mechanisms or alternative recovery strategies available due to architectural constraints.
Learnt from: Jack251970
PR: #3561
File: Flow.Launcher/ViewModel/SelectBrowserViewModel.cs:53-58
Timestamp: 2025-05-21T10:37:07.696Z
Learning: When implementing collection item removal operations in Flow Launcher, always handle index boundaries carefully. After removing an item from a collection, ensure the updated index remains within valid bounds (>= 0 and < collection.Count) to prevent IndexOutOfRangeExceptions, especially when decrementing indexes.
Flow.Launcher/ViewModel/MainViewModel.cs (4)
Learnt from: Jack251970
PR: #3791
File: Flow.Launcher.Core/Plugin/PluginManager.cs:293-295
Timestamp: 2025-07-01T05:46:13.251Z
Learning: In Flow.Launcher.Core/Plugin/PluginManager.cs, when checking if a plugin is modified within the PluginManager class itself, prefer using the internal static PluginModified(string id) method directly rather than going through API.PluginModified() for better performance and architectural design.
Learnt from: Jack251970
PR: #3572
File: Flow.Launcher/App.xaml.cs:214-216
Timestamp: 2025-07-06T12:21:37.947Z
Learning: In Flow Launcher, the UpdatePluginManifestAsync method in PluginsManifest.cs already has comprehensive internal try-catch handling that logs exceptions and returns false on failure rather than throwing, making external try-catch wrappers unnecessary.
Learnt from: Yusyuriv
PR: #3118
File: Flow.Launcher/ViewModel/MainViewModel.cs:1404-1413
Timestamp: 2024-12-08T21:12:12.060Z
Learning: In the MainViewModel
class, the _lastQuery
field is initialized in the constructor and is never null.
Learnt from: Jack251970
PR: #3672
File: Flow.Launcher/MainWindow.xaml.cs:244-247
Timestamp: 2025-06-08T14:12:21.348Z
Learning: In Flow.Launcher, App.NotifyIcon is created before MainWindow creation, so null checks for App.NotifyIcon are not necessary when accessing it from MainWindow code.
Flow.Launcher.Infrastructure/DialogJump/DialogJump.cs (9)
Learnt from: Jack251970
PR: #3791
File: Flow.Launcher.Core/Plugin/PluginManager.cs:293-295
Timestamp: 2025-07-01T05:46:13.251Z
Learning: In Flow.Launcher.Core/Plugin/PluginManager.cs, when checking if a plugin is modified within the PluginManager class itself, prefer using the internal static PluginModified(string id) method directly rather than going through API.PluginModified() for better performance and architectural design.
Learnt from: Yusyuriv
PR: #3057
File: Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs:0-0
Timestamp: 2024-11-03T07:40:11.014Z
Learning: In Flow Launcher, when using Windows Forms dialogs (e.g., in JsonRPCPluginSettings.cs
), path validation is enabled by default in OpenFileDialog
and FolderBrowserDialog
, preventing users from selecting invalid paths, but it's possible to opt out of this validation on individual dialogs.
Learnt from: Jack251970
PR: #3572
File: Flow.Launcher/App.xaml.cs:214-216
Timestamp: 2025-07-06T12:21:37.947Z
Learning: In Flow Launcher, the UpdatePluginManifestAsync method in PluginsManifest.cs already has comprehensive internal try-catch handling that logs exceptions and returns false on failure rather than throwing, making external try-catch wrappers unnecessary.
Learnt from: Jack251970
PR: #3500
File: Flow.Launcher/Storage/TopMostRecord.cs:145-149
Timestamp: 2025-05-01T05:38:25.673Z
Learning: For the MultipleTopMostRecord implementation in Flow.Launcher, sequence order of records in the ConcurrentBag does not need to be preserved, as confirmed by the developer. The unordered nature of ConcurrentBag is acceptable for this implementation.
Learnt from: jjw24
PR: #2448
File: Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs:16-20
Timestamp: 2025-01-18T10:10:18.414Z
Learning: In Flow Launcher's plugin system, the PluginInitContext parameter passed to plugin constructors is guaranteed to be non-null by the plugin initialization system, making null checks unnecessary.
Learnt from: Jack251970
PR: #3672
File: Flow.Launcher/MainWindow.xaml.cs:244-247
Timestamp: 2025-06-08T14:12:21.348Z
Learning: In Flow.Launcher, App.NotifyIcon is created before MainWindow creation, so null checks for App.NotifyIcon are not necessary when accessing it from MainWindow code.
Learnt from: Jack251970
PR: #3672
File: Flow.Launcher/MainWindow.xaml.cs:318-318
Timestamp: 2025-06-08T14:12:12.842Z
Learning: In Flow.Launcher, the App.NotifyIcon static property is initialized in the App class before MainWindow creation, so null checks are not needed when accessing App.NotifyIcon in MainWindow lifecycle methods.
Learnt from: onesounds
PR: #3394
File: Flow.Launcher/Themes/Darker Glass.xaml:134-141
Timestamp: 2025-03-28T21:12:13.386Z
Learning: In Flow.Launcher, hotkey styling is implemented with a two-component structure: a Border element with style ItemHotkeyBGStyle
that provides background and border styling, containing a TextBlock with style ItemHotkeyStyle
that handles the text styling.
Learnt from: Jack251970
PR: #3561
File: Flow.Launcher/ViewModel/SelectBrowserViewModel.cs:53-58
Timestamp: 2025-05-21T10:37:07.696Z
Learning: When implementing collection item removal operations in Flow Launcher, always handle index boundaries carefully. After removing an item from a collection, ensure the updated index remains within valid bounds (>= 0 and < collection.Count) to prevent IndexOutOfRangeExceptions, especially when decrementing indexes.
Flow.Launcher/PublicAPIInstance.cs (2)
Learnt from: Jack251970
PR: #3791
File: Flow.Launcher.Core/Plugin/PluginManager.cs:293-295
Timestamp: 2025-07-01T05:46:13.251Z
Learning: In Flow.Launcher.Core/Plugin/PluginManager.cs, when checking if a plugin is modified within the PluginManager class itself, prefer using the internal static PluginModified(string id) method directly rather than going through API.PluginModified() for better performance and architectural design.
Learnt from: Jack251970
PR: #3572
File: Flow.Launcher/App.xaml.cs:214-216
Timestamp: 2025-07-06T12:21:37.947Z
Learning: In Flow Launcher, the UpdatePluginManifestAsync method in PluginsManifest.cs already has comprehensive internal try-catch handling that logs exceptions and returns false on failure rather than throwing, making external try-catch wrappers unnecessary.
Flow.Launcher.Core/Plugin/PluginManager.cs (9)
Learnt from: Jack251970
PR: #3791
File: Flow.Launcher.Core/Plugin/PluginManager.cs:293-295
Timestamp: 2025-07-01T05:46:13.251Z
Learning: In Flow.Launcher.Core/Plugin/PluginManager.cs, when checking if a plugin is modified within the PluginManager class itself, prefer using the internal static PluginModified(string id) method directly rather than going through API.PluginModified() for better performance and architectural design.
Learnt from: Jack251970
PR: #3572
File: Flow.Launcher/App.xaml.cs:214-216
Timestamp: 2025-07-06T12:21:37.947Z
Learning: In Flow Launcher, the UpdatePluginManifestAsync method in PluginsManifest.cs already has comprehensive internal try-catch handling that logs exceptions and returns false on failure rather than throwing, making external try-catch wrappers unnecessary.
Learnt from: jjw24
PR: #2448
File: Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs:16-20
Timestamp: 2025-01-18T10:10:18.414Z
Learning: In Flow Launcher's plugin system, the PluginInitContext parameter passed to plugin constructors is guaranteed to be non-null by the plugin initialization system, making null checks unnecessary.
Learnt from: Yusyuriv
PR: #3057
File: Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs:0-0
Timestamp: 2024-11-03T07:40:11.014Z
Learning: In Flow Launcher, when using Windows Forms dialogs (e.g., in JsonRPCPluginSettings.cs
), path validation is enabled by default in OpenFileDialog
and FolderBrowserDialog
, preventing users from selecting invalid paths, but it's possible to opt out of this validation on individual dialogs.
Learnt from: Jack251970
PR: #3672
File: Flow.Launcher/MainWindow.xaml.cs:244-247
Timestamp: 2025-06-08T14:12:21.348Z
Learning: In Flow.Launcher, App.NotifyIcon is created before MainWindow creation, so null checks for App.NotifyIcon are not necessary when accessing it from MainWindow code.
Learnt from: Jack251970
PR: #3672
File: Flow.Launcher/MainWindow.xaml.cs:318-318
Timestamp: 2025-06-08T14:12:12.842Z
Learning: In Flow.Launcher, the App.NotifyIcon static property is initialized in the App class before MainWindow creation, so null checks are not needed when accessing App.NotifyIcon in MainWindow lifecycle methods.
Learnt from: onesounds
PR: Flow-Launcher/Flow.Launcher#0
File: :0-0
Timestamp: 2025-04-23T15:14:49.986Z
Learning: In WPF applications like Flow.Launcher, font styling should be applied using implicit styles instead of setting the FontFamily property on individual controls. Define implicit styles in a ResourceDictionary using <Style TargetType="{x:Type Button}"> format and merge it into App.xaml, which automatically applies the font to all instances of the control type while still allowing explicit overrides where needed.
Learnt from: taooceros
PR: #2616
File: Flow.Launcher/Flow.Launcher.csproj:7-7
Timestamp: 2024-10-08T15:52:58.573Z
Learning: In the Flow Launcher project, the version number in the Flow.Launcher.csproj
file is dynamically updated during the CI/CD process.
Learnt from: Jack251970
PR: #3279
File: Flow.Launcher/Helper/WallpaperPathRetrieval.cs:44-46
Timestamp: 2025-02-28T07:47:24.148Z
Learning: In Flow.Launcher's WallpaperPathRetrieval class, using a using
statement with MemoryStream when loading images with BitmapImage does not work properly, even when using BitmapCacheOption.OnLoad. The stream needs to remain open while the bitmap is in use.
🧬 Code Graph Analysis (1)
Flow.Launcher.Core/Plugin/IResultUpdateRegister.cs (1)
Flow.Launcher/ViewModel/MainViewModel.cs (1)
RegisterResultsUpdatedEvent
(277-321)
🪛 GitHub Actions: Check Spelling
Flow.Launcher/MainWindow.xaml.cs
[warning] 69-69: Spell check warning: Wnd
is not a recognized word. (unrecognized-spelling)
[warning] 118-118: Spell check warning: Wnd
is not a recognized word. (unrecognized-spelling)
[warning] 376-376: Spell check warning: Wnd
is not a recognized word. (unrecognized-spelling)
[warning] 778-778: Spell check warning: gamemode
is not a recognized word. (unrecognized-spelling)
[warning] 779-779: Spell check warning: gamemode
is not a recognized word. (unrecognized-spelling)
[warning] 782-782: Spell check warning: gamemode
is not a recognized word. (unrecognized-spelling)
[warning] 785-785: Spell check warning: positionreset
is not a recognized word. (unrecognized-spelling)
[warning] 788-788: Spell check warning: positionreset
is not a recognized word. (unrecognized-spelling)
[warning] 804-804: Spell check warning: gamemode
is not a recognized word. (unrecognized-spelling)
[warning] 805-805: Spell check warning: positionreset
is not a recognized word. (unrecognized-spelling)
[warning] 810-810: Spell check warning: positionreset
is not a recognized word. (unrecognized-spelling)
[warning] 928-928: Spell check warning: XRatio
is not a recognized word. (unrecognized-spelling)
[warning] 929-929: Spell check warning: YRatio
is not a recognized word. (unrecognized-spelling)
[warning] 1143-1143: Spell check warning: clocksb
is not a recognized word. (unrecognized-spelling)
[warning] 1144-1144: Spell check warning: clocksb
is not a recognized word. (unrecognized-spelling)
[warning] 1145-1145: Spell check warning: iconsb
is not a recognized word. (unrecognized-spelling)
[warning] 1146-1146: Spell check warning: iconsb
is not a recognized word. (unrecognized-spelling)
[warning] 1151-1151: Spell check warning: clocksb
is not a recognized word. (unrecognized-spelling)
[warning] 1152-1152: Spell check warning: iconsb
is not a recognized word. (unrecognized-spelling)
[warning] 234-234: Spell check warning: activing
is not a recognized word. (unrecognized-spelling)
[warning] 280-280: Spell check warning: gamemode
is not a recognized word. (unrecognized-spelling)
[warning] 418-418: Spell check warning: mainwindow
is not a recognized word. (unrecognized-spelling)
[warning] 506-506: Spell check warning: Arrowkeys
is not a recognized word. (unrecognized-spelling)
[warning] 784-784: Spell check warning: positionreset
is not a recognized word. (unrecognized-spelling)
[error] 825-825: Forbidden pattern error: work around
matches a forbidden pattern '\bwork[- ]arounds?\b'. (forbidden-pattern)
Flow.Launcher/App.xaml.cs
[warning] 217-217: Spell check warning: Loadertask
is not a recognized word. (unrecognized-spelling)
[warning] 210-210: Spell check warning: Loadertask
is not a recognized word. (unrecognized-spelling)
[warning] 413-413: Spell check warning: acees
is not a recognized word. (unrecognized-spelling)
Flow.Launcher.Infrastructure/DialogJump/DialogJump.cs
[warning] 180-180: Spell check warning: PInvoke
is not a recognized word. (unrecognized-spelling)
[warning] 185-185: Spell check warning: PInvoke
is not a recognized word. (unrecognized-spelling)
[warning] 190-190: Spell check warning: PInvoke
is not a recognized word. (unrecognized-spelling)
[warning] 195-195: Spell check warning: PInvoke
is not a recognized word. (unrecognized-spelling)
[warning] 336-336: Spell check warning: Wnd
is not a recognized word. (unrecognized-spelling)
[warning] 12-12: Spell check warning: NHotkey
is not a recognized word. (unrecognized-spelling)
[warning] 113-113: Spell check warning: preinstalled
is not a recognized word. (unrecognized-spelling)
[warning] 175-175: Spell check warning: PInvoke
is not a recognized word. (unrecognized-spelling)
[warning] 329-329: Spell check warning: Wnd
is not a recognized word. (unrecognized-spelling)
[warning] 710-710: Spell check warning: Destory
is not a recognized word. (unrecognized-spelling)
Flow.Launcher.Core/Plugin/PluginManager.cs
[warning] 502-502: Spell check warning: overriden
is not a recognized word. (unrecognized-spelling)
[warning] 798-798: Spell check warning: CETYU
is not a recognized word. (unrecognized-spelling)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: gitStream.cm
- GitHub Check: gitStream.cm
- GitHub Check: build
🔇 Additional comments (22)
Flow.Launcher.Infrastructure/DialogJump/DialogJump.cs (3)
68-73
: Good use of ConcurrentDictionary for thread safetyThe migration from
Dictionary
toConcurrentDictionary
is appropriate for the asynchronous plugin loading model. This ensures thread-safe access when plugins are initialized concurrently.
109-115
: LGTM! Simplified initialization approachThe removal of parameters and use of
TryAdd
for preinstalled components aligns well with the new plugin initialization model.
130-151
: Well-designed plugin registration methodThe new
InitializeDialogJumpPlugin
method properly supports individual plugin registration with appropriate type checking and thread-safe addition to the concurrent collections.Flow.Launcher/MainWindow.xaml.cs (1)
479-479
: Correct use of thread-safe plugin access methodThe change from
PluginManager.NonGlobalPlugins
property toPluginManager.GetNonGlobalPlugins()
method ensures thread-safe access to the plugin collection, which is essential with the new asynchronous plugin loading model.Flow.Launcher.Core/Plugin/IResultUpdateRegister.cs (1)
1-12
: Well-designed interface for plugin event registrationThe
IResultUpdateRegister
interface provides a clean abstraction for registering plugin result update events. This design properly separates concerns and enables dependency injection of the registration handler, which aligns perfectly with the asynchronous plugin loading architecture.Flow.Launcher/PublicAPIInstance.cs (1)
254-254
: LGTM! Thread-safe plugin access implemented correctly.The change from property access to method call aligns with the asynchronous plugin loading model and thread-safe concurrent collections refactor.
PluginManager.GetAllPlugins()
provides a safe snapshot of plugins without exposing the internal concurrent collection.Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginsViewModel.cs (1)
118-118
: LGTM! Consistent with thread-safe plugin management refactor.The change from
PluginManager.AllPlugins
property toPluginManager.GetAllPlugins()
method call maintains the lazy initialization pattern while adapting to the new thread-safe plugin collection infrastructure.Flow.Launcher/App.xaml.cs (5)
191-192
: LGTM! Notification system initialization moved appropriately.Moving notification system initialization earlier ensures it's available before any notification API calls, which prevents potential issues with the asynchronous plugin loading.
246-262
: LGTM! Asynchronous plugin initialization achieves PR objectives.This refactoring successfully implements the core objective of separating plugin initialization from main window startup. The async task ensures:
- Main window starts immediately without waiting for plugins
- Plugin loading happens in parallel without blocking UI
- Proper logging tracks plugin initialization performance
- Settings are saved after plugin environment updates
The fire-and-forget pattern (
_ = API.StopwatchLogInfoAsync(...)
) is appropriate here since the main startup flow shouldn't wait for plugins to complete.
200-201
: Fix spelling error in comment.Pipeline failure indicates a spelling issue that should be corrected.
- // Clean up after portability update + // Clean up after portability updateActually, let me check the pipeline failure more carefully - it seems to be about "Loadertask" and "acees" elsewhere. This line looks correct.
224-227
: DialogJump initialization verifiedA search through the codebase confirms:
- InitializeDialogJump now seeds the built-in explorers/dialogs into its concurrent dictionaries.
- PluginManager.cs still calls DialogJump.InitializeDialogJumpPlugin(pair) for each plugin.
- SetupDialogJump is invoked both at startup and on settings changes to (un)register the hotkey.
All plugin and built-in dialog jump paths remain registered via the concurrent dictionaries, so existing functionality is preserved. No further changes required.
252-254
: Integration Verified: Plugin loading and initialization are correctly wired up.
PluginManager.LoadPlugins(PluginsSettings)
returns aList<PluginPair>
as expected.PluginManager.InitializePluginsAsync(List<PluginPair>, IResultUpdateRegister)
matches the call in App.xaml.cs.MainViewModel
implementsIResultUpdateRegister
, so passing_mainVM
satisfies the interface requirement.No further changes needed.
Flow.Launcher/ViewModel/MainViewModel.cs (4)
30-30
: LGTM: Interface implementation aligns with the new plugin event registration pattern.The addition of
IResultUpdateRegister
interface is correctly implemented with the correspondingRegisterResultsUpdatedEvent
method.
277-321
: Well-structured refactoring of the event registration method.The changes improve the design by:
- Making plugin registration explicit with the
PluginPair
parameter- Adding proper type checking for
IResultUpdated
interface- Maintaining thread-safety with result cloning
The event handler correctly preserves all the original functionality including token cancellation checks and metadata updates.
440-440
: Correct usage of the new snapshot-returning methods.The migration from
PluginManager.NonGlobalPlugins
property toPluginManager.GetNonGlobalPlugins()
method aligns with the thread-safe design where methods return snapshots of the concurrent collections.Also applies to: 1576-1576, 1596-1596
1330-1330
: CancelAsync usage is safe with the current target frameworksAll projects target net9.0-(windows), which is ≥ .NET 8.0 and fully supports CancellationTokenSource.CancelAsync(). No further action is required.
Flow.Launcher.Core/Plugin/PluginManager.cs (6)
33-44
: Excellent migration to thread-safe concurrent collections.The choice of collection types is well-considered:
ConcurrentDictionary
for keyed plugin lookupsConcurrentBag
for unordered plugin lists where iteration is the primary operationThis ensures thread-safety for the new asynchronous plugin loading model.
196-209
: Clean separation of plugin loading from initialization.The refactored
LoadPlugins
method now has a single responsibility - loading plugins and returning them. This enables the new asynchronous initialization pattern while maintaining backwards compatibility.
238-313
: Well-designed asynchronous plugin initialization with comprehensive error handling.The initialization flow properly handles:
- Parallel plugin initialization for improved startup performance
- Graceful error handling that disables failed plugins while still tracking them
- Proper event registration through the
IResultUpdateRegister
interface- Translation updates after API instance is available
The decision to add failed plugins to
_allPlugins
(line 278) is correct as it allows users to manage/remove problematic plugins through the UI.
522-540
: Clean implementation of snapshot-returning methods.The methods correctly return immutable snapshots of the concurrent collections, preventing external modification. The use of collection expressions provides clean and efficient syntax.
798-798
: Plugin ID contains an unusual character sequence.The plugin ID
"5043CETYU6A748679OPA02D27D99677A"
contains "CETYU" which was flagged by spell check. If this is intentional (which it appears to be as part of a GUID-like identifier), this can be ignored. Otherwise, please verify the correct ID.
374-375
: Use internal PluginModified method for consistency.Based on previous learnings, prefer using the internal
PluginModified
method directly within PluginManager:-if (API.PluginModified(plugin.Metadata.ID)) +if (PluginModified(plugin.Metadata.ID))This aligns with the established pattern for better performance and architectural design.
Likely an incorrect or invalid review comment.
🥷 Code experts: taooceros Jack251970, taooceros have most 👩💻 activity in the files. See details
Activity based on git-commit:
Knowledge based on git-blame:
Activity based on git-commit:
Knowledge based on git-blame:
Activity based on git-commit:
Knowledge based on git-blame:
Activity based on git-commit:
Knowledge based on git-blame:
Activity based on git-commit:
Knowledge based on git-blame:
Activity based on git-commit:
Knowledge based on git-blame:
Activity based on git-commit:
Knowledge based on git-blame:
Activity based on git-commit:
Knowledge based on git-blame:
Activity based on git-commit:
Knowledge based on git-blame: ✨ Comment |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
♻️ Duplicate comments (1)
Flow.Launcher.Core/Plugin/PluginManager.cs (1)
646-655
: Race condition in RemoveActionKeyword persists.The race condition identified in previous reviews still exists. Between TryRemove and the conditional re-add, another thread could register a different plugin for the same keyword.
🧹 Nitpick comments (2)
Flow.Launcher.Core/Plugin/PluginManager.cs (2)
121-125
: Consider caching plugin lists for better performance.Each call to
GetAllInitializedPlugins()
creates a new list from the concurrent dictionary. For methods that might be called frequently (like external preview operations), consider caching the plugin list or using the concurrent collections directly with proper filtering.Example optimization for one method:
-await Task.WhenAll([.. GetAllInitializedPlugins().Select(plugin => plugin.Plugin switch +await Task.WhenAll([.. _allPlugins.Values.Select(plugin => plugin.Plugin switchAlso applies to: 130-134, 139-143
887-893
: Use consistent variable naming for removed items.The out variables have inconsistent names (item, item1, item2). While this doesn't affect functionality, consistent naming improves readability.
-_allPlugins.TryRemove(plugin.ID, out var item); -_globalPlugins.TryRemove(plugin.ID, out var item1); +_allPlugins.TryRemove(plugin.ID, out var _); +_globalPlugins.TryRemove(plugin.ID, out var _); var keysToRemove = _nonGlobalPlugins.Where(p => p.Value.Metadata.ID == plugin.ID).Select(p => p.Key).ToList(); foreach (var key in keysToRemove) { - _nonGlobalPlugins.Remove(key, out var item2); + _nonGlobalPlugins.TryRemove(key, out var _); }Also note: use
TryRemove
instead ofRemove
for consistency with ConcurrentDictionary API.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
Flow.Launcher.Core/Plugin/PluginManager.cs
(21 hunks)Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs
(1 hunks)Flow.Launcher/PublicAPIInstance.cs
(1 hunks)Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginsViewModel.cs
(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs
🚧 Files skipped from review as they are similar to previous changes (2)
- Flow.Launcher/PublicAPIInstance.cs
- Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginsViewModel.cs
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3791
File: Flow.Launcher.Core/Plugin/PluginManager.cs:293-295
Timestamp: 2025-07-01T05:46:13.251Z
Learning: In Flow.Launcher.Core/Plugin/PluginManager.cs, when checking if a plugin is modified within the PluginManager class itself, prefer using the internal static PluginModified(string id) method directly rather than going through API.PluginModified() for better performance and architectural design.
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3572
File: Flow.Launcher/App.xaml.cs:214-216
Timestamp: 2025-07-06T12:21:37.947Z
Learning: In Flow Launcher, the UpdatePluginManifestAsync method in PluginsManifest.cs already has comprehensive internal try-catch handling that logs exceptions and returns false on failure rather than throwing, making external try-catch wrappers unnecessary.
Flow.Launcher.Core/Plugin/PluginManager.cs (9)
Learnt from: Jack251970
PR: #3791
File: Flow.Launcher.Core/Plugin/PluginManager.cs:293-295
Timestamp: 2025-07-01T05:46:13.251Z
Learning: In Flow.Launcher.Core/Plugin/PluginManager.cs, when checking if a plugin is modified within the PluginManager class itself, prefer using the internal static PluginModified(string id) method directly rather than going through API.PluginModified() for better performance and architectural design.
Learnt from: Jack251970
PR: #3572
File: Flow.Launcher/App.xaml.cs:214-216
Timestamp: 2025-07-06T12:21:37.947Z
Learning: In Flow Launcher, the UpdatePluginManifestAsync method in PluginsManifest.cs already has comprehensive internal try-catch handling that logs exceptions and returns false on failure rather than throwing, making external try-catch wrappers unnecessary.
Learnt from: Yusyuriv
PR: #3057
File: Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs:0-0
Timestamp: 2024-11-03T07:40:11.014Z
Learning: In Flow Launcher, when using Windows Forms dialogs (e.g., in JsonRPCPluginSettings.cs
), path validation is enabled by default in OpenFileDialog
and FolderBrowserDialog
, preventing users from selecting invalid paths, but it's possible to opt out of this validation on individual dialogs.
Learnt from: Jack251970
PR: #3672
File: Flow.Launcher/MainWindow.xaml.cs:244-247
Timestamp: 2025-06-08T14:12:21.348Z
Learning: In Flow.Launcher, App.NotifyIcon is created before MainWindow creation, so null checks for App.NotifyIcon are not necessary when accessing it from MainWindow code.
Learnt from: Jack251970
PR: #3672
File: Flow.Launcher/MainWindow.xaml.cs:318-318
Timestamp: 2025-06-08T14:12:12.842Z
Learning: In Flow.Launcher, the App.NotifyIcon static property is initialized in the App class before MainWindow creation, so null checks are not needed when accessing App.NotifyIcon in MainWindow lifecycle methods.
Learnt from: onesounds
PR: Flow-Launcher/Flow.Launcher#0
File: :0-0
Timestamp: 2025-04-23T15:14:49.986Z
Learning: In WPF applications like Flow.Launcher, font styling should be applied using implicit styles instead of setting the FontFamily property on individual controls. Define implicit styles in a ResourceDictionary using <Style TargetType="{x:Type Button}"> format and merge it into App.xaml, which automatically applies the font to all instances of the control type while still allowing explicit overrides where needed.
Learnt from: jjw24
PR: #2448
File: Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs:16-20
Timestamp: 2025-01-18T10:10:18.414Z
Learning: In Flow Launcher's plugin system, the PluginInitContext parameter passed to plugin constructors is guaranteed to be non-null by the plugin initialization system, making null checks unnecessary.
Learnt from: taooceros
PR: #2616
File: Flow.Launcher/Flow.Launcher.csproj:7-7
Timestamp: 2024-10-08T15:52:58.573Z
Learning: In the Flow Launcher project, the version number in the Flow.Launcher.csproj
file is dynamically updated during the CI/CD process.
Learnt from: Jack251970
PR: #3279
File: Flow.Launcher/Helper/WallpaperPathRetrieval.cs:44-46
Timestamp: 2025-02-28T07:47:24.148Z
Learning: In Flow.Launcher's WallpaperPathRetrieval class, using a using
statement with MemoryStream when loading images with BitmapImage does not work properly, even when using BitmapCacheOption.OnLoad. The stream needs to remain open while the bitmap is in use.
🧬 Code Graph Analysis (1)
Flow.Launcher.Core/Plugin/PluginManager.cs (8)
Flow.Launcher.Infrastructure/UserSettings/PluginSettings.cs (5)
PluginsSettings
(7-106)Plugin
(92-99)Plugin
(101-105)Plugin
(108-134)UpdatePluginSettings
(41-90)Flow.Launcher.Core/Plugin/JsonRPCPluginBase.cs (3)
Save
(134-137)List
(33-33)List
(57-83)Flow.Launcher.Plugin/Interfaces/ISavable.cs (1)
Save
(19-19)Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs (3)
PluginModified
(539-539)List
(177-177)List
(445-445)Flow.Launcher.Core/Resource/Internationalization.cs (4)
List
(322-327)Internationalization
(17-387)Internationalization
(34-37)UpdatePluginMetadataTranslation
(370-384)Flow.Launcher.Core/Plugin/PluginsLoader.cs (2)
List
(25-56)PluginsLoader
(17-166)Flow.Launcher.Core/Plugin/PluginConfig.cs (1)
PluginConfig
(12-144)Flow.Launcher.Core/Plugin/QueryBuilder.cs (1)
Query
(9-60)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Report (PR)
- GitHub Check: build
This comment has been minimized.
This comment has been minimized.
@jjw24 Yeah, now I add UI for users so that they can know this plugin is still initializing. ![]() |
There was a problem hiding this 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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (10)
Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs (4)
68-71
: Fix typo in XML doc: “refeshes” → “refreshes”Apply:
- /// IReloadable implemented. It refeshes + /// IReloadable implemented. It refreshes
260-260
: Fix typo in XML doc: “cretain” → “certain”Apply:
- /// Download the specific url to a cretain file path + /// Download the specific url to a certain file path
321-321
: Fix typo in XML doc: “eror” → “error”Apply:
- /// otherwise logs the eror message. This is the primary logging method used for Flow + /// otherwise logs the error message. This is the primary logging method used for Flow
55-55
: XML doc tag has an extra ‘>’Apply:
- /// Turn this off to show your own notification after copy is done.</param>> + /// Turn this off to show your own notification after copy is done.</param>Flow.Launcher.Infrastructure/DialogJump/DialogJump.cs (4)
816-819
: Possible NRE/Key error when no explorer is cached_lock (_lastExplorerLock) { path = _dialogJumpExplorers[_lastExplorer]?.GetExplorerPath(); } will throw if _lastExplorer is null or not present. Use TryGetValue + null-check.
Apply:
- lock (_lastExplorerLock) - { - path = _dialogJumpExplorers[_lastExplorer]?.GetExplorerPath(); - } + IDialogJumpExplorerWindow explorerWindow = null; + lock (_lastExplorerLock) + { + if (_lastExplorer != null) + _dialogJumpExplorers.TryGetValue(_lastExplorer, out explorerWindow); + } + var path = explorerWindow?.GetExplorerPath();
249-259
: Dispose explorer windows before clearing to avoid leaksCurrent code assigns null without disposing previous IDialogJumpExplorerWindow instances.
Apply:
- foreach (var explorer in _dialogJumpExplorers.Keys) - { - _dialogJumpExplorers[explorer] = null; - } + foreach (var explorer in _dialogJumpExplorers.Keys) + { + _dialogJumpExplorers[explorer]?.Dispose(); + _dialogJumpExplorers[explorer] = null; + }
256-259
: Dispose dialog windows before clearing to avoid leaksSame as explorers; dispose existing IDialogJumpDialogWindow instances.
Apply:
- foreach (var dialog in _dialogJumpDialogs.Keys) - { - _dialogJumpDialogs[dialog] = null; - } + foreach (var dialog in _dialogJumpDialogs.Keys) + { + _dialogJumpDialogs[dialog]?.Dispose(); + _dialogJumpDialogs[dialog] = null; + }
704-708
: Fix log message spelling: “Destory” → “Destroy”Apply:
- Log.Debug(ClassName, $"Destory dialog: {hwnd}"); + Log.Debug(ClassName, $"Destroy dialog: {hwnd}");Flow.Launcher/App.xaml.cs (1)
423-425
: Fix comment typo: “acees” → “access”Apply:
- // So here we need to check it and just return so that we will not acees _mainWindow?.Dispatcher + // So here we need to check it and just return so that we will not access _mainWindow?.DispatcherFlow.Launcher.Core/Plugin/PluginManager.cs (1)
590-593
: Doc typo: “overriden” → “overridden”Apply:
- // Plugins may have multi-actionkeywords eg. WebSearches. In this scenario it needs to be overriden on the plugin level + // Plugins may have multi-actionkeywords eg. WebSearches. In this scenario it needs to be overridden on the plugin level
🧹 Nitpick comments (4)
Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs (2)
176-181
: Clarify “loaded vs initialized” in summary for discoverabilityConsider updating the summary of GetAllPlugins to explicitly say “Get all loaded plugins (may not be initialized yet)” to reduce confusion. Behavior is correct.
182-189
: New API looks good; add brief behavior noteLGTM. Consider documenting that includeFailed=true returns plugins whose initialization failed (for diagnostics/UI), but they should not be queried.
Flow.Launcher/App.xaml.cs (1)
248-252
: Disambiguate nested stopwatch log labelsBoth outer and inner use “Startup cost”. Rename the inner to “Plugin initialization cost” to make logs clearer.
Apply:
- _ = API.StopwatchLogInfoAsync(ClassName, "Startup cost", async () => + _ = API.StopwatchLogInfoAsync(ClassName, "Plugin initialization cost", async () =>Flow.Launcher.Core/Plugin/PluginManager.cs (1)
359-365
: Optionally filter disabled plugins earlier in ValidPluginsForQueryTo avoid showing plugin icon for a disabled/failed plugin, filter them here.
Apply:
- else - return [.. GetGlobalPlugins().Where(p => !PluginModified(p.Metadata.ID))]; + else + return [.. GetGlobalPlugins().Where(p => !PluginModified(p.Metadata.ID) && !p.Metadata.Disabled)]; @@ - return [plugin]; + return plugin.Metadata.Disabled ? Array.Empty<PluginPair>() : [plugin];Also applies to: 370-374
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
Flow.Launcher.Core/Plugin/PluginManager.cs
(22 hunks)Flow.Launcher.Core/Plugin/PluginsLoader.cs
(2 hunks)Flow.Launcher.Core/Resource/Internationalization.cs
(1 hunks)Flow.Launcher.Infrastructure/DialogJump/DialogJump.cs
(4 hunks)Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs
(2 hunks)Flow.Launcher/App.xaml.cs
(3 hunks)Flow.Launcher/Languages/en.xaml
(1 hunks)Flow.Launcher/MainWindow.xaml.cs
(1 hunks)Flow.Launcher/PublicAPIInstance.cs
(1 hunks)Flow.Launcher/ViewModel/MainViewModel.cs
(7 hunks)Flow.Launcher/ViewModel/PluginViewModel.cs
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
- Flow.Launcher.Core/Resource/Internationalization.cs
- Flow.Launcher/PublicAPIInstance.cs
- Flow.Launcher/MainWindow.xaml.cs
- Flow.Launcher.Core/Plugin/PluginsLoader.cs
🧰 Additional context used
🧠 Learnings (5)
📚 Learning: 2025-07-21T09:19:49.684Z
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3854
File: Flow.Launcher/App.xaml.cs:246-262
Timestamp: 2025-07-21T09:19:49.684Z
Learning: In Flow Launcher's App.xaml.cs, the asynchronous plugin initialization task (containing AbstractPluginEnvironment.PreStartPluginExecutablePathUpdate, PluginManager.LoadPlugins, PluginManager.InitializePluginsAsync, and AutoPluginUpdates) does not require additional try-catch error handling according to maintainer Jack251970, as these operations are designed to handle exceptions internally.
Applied to files:
Flow.Launcher/App.xaml.cs
Flow.Launcher.Core/Plugin/PluginManager.cs
📚 Learning: 2025-07-21T09:19:19.012Z
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3854
File: Flow.Launcher.Core/Plugin/PluginManager.cs:280-292
Timestamp: 2025-07-21T09:19:19.012Z
Learning: In Flow Launcher's PluginManager.cs, the post-initialization operations (RegisterResultsUpdatedEvent, UpdatePluginMetadataTranslation, RegisterPluginActionKeywords, DialogJump.InitializeDialogJumpPlugin, and AddPluginToLists) are designed to be exception-safe and do not require additional try-catch error handling according to the maintainer Jack251970.
Applied to files:
Flow.Launcher/App.xaml.cs
Flow.Launcher.Core/Plugin/PluginManager.cs
📚 Learning: 2025-07-06T12:21:37.947Z
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3572
File: Flow.Launcher/App.xaml.cs:214-216
Timestamp: 2025-07-06T12:21:37.947Z
Learning: In Flow Launcher, the UpdatePluginManifestAsync method in PluginsManifest.cs already has comprehensive internal try-catch handling that logs exceptions and returns false on failure rather than throwing, making external try-catch wrappers unnecessary.
Applied to files:
Flow.Launcher/App.xaml.cs
Flow.Launcher.Core/Plugin/PluginManager.cs
📚 Learning: 2025-08-13T06:12:43.382Z
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3897
File: Flow.Launcher/ViewModel/PluginViewModel.cs:46-51
Timestamp: 2025-08-13T06:12:43.382Z
Learning: In Flow Launcher's PluginViewModel.cs, the LoadIconAsync method does not require additional try-catch error handling according to maintainer Jack251970, as the existing error handling approach is considered sufficient for the image loading operations.
Applied to files:
Flow.Launcher/App.xaml.cs
Flow.Launcher.Core/Plugin/PluginManager.cs
📚 Learning: 2025-07-01T05:46:13.251Z
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3791
File: Flow.Launcher.Core/Plugin/PluginManager.cs:293-295
Timestamp: 2025-07-01T05:46:13.251Z
Learning: In Flow.Launcher.Core/Plugin/PluginManager.cs, when checking if a plugin is modified within the PluginManager class itself, prefer using the internal static PluginModified(string id) method directly rather than going through API.PluginModified() for better performance and architectural design.
Applied to files:
Flow.Launcher.Core/Plugin/PluginManager.cs
🧬 Code graph analysis (4)
Flow.Launcher/ViewModel/MainViewModel.cs (3)
Flow.Launcher.Core/Plugin/IResultUpdateRegister.cs (1)
RegisterResultsUpdatedEvent
(11-11)Flow.Launcher.Core/Plugin/PluginManager.cs (4)
PluginPair
(604-607)PluginManager
(24-997)PluginManager
(168-174)UpdatePluginMetadata
(581-594)Flow.Launcher.Core/Plugin/QueryBuilder.cs (2)
Query
(9-60)QueryBuilder
(7-61)
Flow.Launcher/App.xaml.cs (7)
Flow.Launcher.Infrastructure/Logger/Log.cs (1)
SetLogLevel
(66-84)Flow.Launcher.Infrastructure/Image/ImageLoader.cs (1)
ImageLoader
(17-411)Flow.Launcher.Infrastructure/DialogJump/DialogJump.cs (3)
DialogJump
(20-1086)InitializeDialogJump
(105-124)SetupDialogJump
(149-316)Flow.Launcher/Helper/HotKeyMapper.cs (2)
HotKeyMapper
(13-168)Initialize
(20-31)Flow.Launcher/PublicAPIInstance.cs (2)
SaveAppAllSettings
(107-116)LogInfo
(278-279)Flow.Launcher.Core/ExternalPlugins/Environments/AbstractPluginEnvironment.cs (1)
PreStartPluginExecutablePathUpdate
(171-217)Flow.Launcher.Core/Plugin/PluginManager.cs (3)
PluginManager
(24-997)PluginManager
(168-174)LoadPlugins
(200-211)
Flow.Launcher/ViewModel/PluginViewModel.cs (2)
Flow.Launcher.Core/Plugin/PluginManager.cs (3)
PluginManager
(24-997)PluginManager
(168-174)IsInitializingOrInitFailed
(655-671)Flow.Launcher.Core/Plugin/JsonRPCPluginBase.cs (1)
JsonRPCPluginBase
(20-148)
Flow.Launcher.Core/Plugin/PluginManager.cs (5)
Flow.Launcher/PublicAPIInstance.cs (9)
List
(250-250)List
(252-253)List
(532-532)Task
(118-118)Task
(223-242)PluginModified
(588-588)LogDebug
(275-276)ActionKeywordAssigned
(270-270)ReQuery
(520-520)Flow.Launcher.Core/Resource/Internationalization.cs (6)
List
(332-337)Task
(71-94)Task
(182-212)Internationalization
(16-407)Internationalization
(30-33)UpdatePluginMetadataTranslation
(380-394)Flow.Launcher/ViewModel/MainViewModel.cs (6)
List
(1308-1330)RegisterResultsUpdatedEvent
(278-322)Query
(1188-1216)Result
(1709-1750)Result
(1752-1780)ReQuery
(371-376)Flow.Launcher.Infrastructure/DialogJump/DialogJump.cs (2)
DialogJump
(20-1086)InitializeDialogJumpPlugin
(126-147)Flow.Launcher.Core/Plugin/QueryBuilder.cs (1)
Query
(9-60)
🪛 GitHub Actions: Check Spelling
Flow.Launcher.Infrastructure/DialogJump/DialogJump.cs
[warning] 176-176: unrecognized-spelling: 'PInvoke' is not a recognized word.
[warning] 181-181: unrecognized-spelling: 'PInvoke' is not a recognized word.
[warning] 186-186: unrecognized-spelling: 'PInvoke' is not a recognized word.
[warning] 191-191: unrecognized-spelling: 'PInvoke' is not a recognized word.
[warning] 332-332: unrecognized-spelling: 'Wnd' is not a recognized word.
[warning] 12-12: unrecognized-spelling: 'NHotkey' is not a recognized word.
[warning] 109-109: unrecognized-spelling: 'preinstalled' is not a recognized word.
[warning] 171-171: unrecognized-spelling: 'PInvoke' is not a recognized word.
[warning] 325-325: unrecognized-spelling: 'Wnd' is not a recognized word.
[warning] 706-706: unrecognized-spelling: 'Destory' is not a recognized word.
Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs
[warning] 69-69: unrecognized-spelling: 'refeshes' is not a recognized word.
[warning] 260-260: unrecognized-spelling: 'cretain' is not a recognized word.
[warning] 321-321: unrecognized-spelling: 'eror' is not a recognized word.
Flow.Launcher/App.xaml.cs
[warning] 423-423: unrecognized-spelling: 'acees' is not a recognized word.
Flow.Launcher/Languages/en.xaml
[warning] 25-25: unrecognized-spelling: 'uninstaller' is not a recognized word.
Flow.Launcher.Core/Plugin/PluginManager.cs
[warning] 590-590: unrecognized-spelling: 'overriden' is not a recognized word.
[warning] 875-875: unrecognized-spelling: 'CETYU' is not a recognized word.
[warning] 979-979: unrecognized-spelling: 'ite' is not a recognized word.
🔇 Additional comments (5)
Flow.Launcher/ViewModel/MainViewModel.cs (2)
278-321
: Results-updated registration is correct and safeGood filtering by QueryText/token and cloning; metadata and badge path handled.
1333-1337
: CancelAsync supported on .NET 9 targets All projects—including Flow.Launcher and its plugins—target net9.0-windows, soCancellationTokenSource.CancelAsync()
is available.Flow.Launcher.Core/Plugin/PluginManager.cs (1)
176-190
: Good hardening for Python binding cleanupWrapping File.Delete in try-catch avoids aborting the loop. LGTM.
Flow.Launcher/Languages/en.xaml (1)
69-72
: LGTM! Clear user-facing messages for plugin initialization states.The new localization strings effectively communicate plugin initialization and response states to users, aligning with the async plugin loading feature.
Flow.Launcher/ViewModel/PluginViewModel.cs (1)
134-138
: LGTM! Correctly guards settings panel access during initialization.The logic correctly prevents settings panel display for plugins that are still initializing or have failed initialization. The
!IsInitializingOrInitFailed
check ensures settings are only shown for successfully initialized plugins.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 13 out of 13 changed files in this pull request and generated no new comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
@coderabbitai full review |
✅ Actions performedFull review triggered. |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
Flow.Launcher.Core/Resource/Internationalization.cs (1)
366-366
: Critical bug: Early return skips remaining plugins.Line 366 uses
return
instead ofcontinue
, causing the method to exit entirely when encountering the first plugin that doesn't implementIPluginI18n
. This skips translation updates for all subsequent plugins in the iteration.Apply this diff to fix the issue:
- if (p.Plugin is not IPluginI18n pluginI18N) return; + if (p.Plugin is not IPluginI18n pluginI18N) continue;Flow.Launcher.Core/Plugin/PluginManager.cs (1)
262-295
: Rollback action keyword registration on init failure.We register action keywords before
InitAsync
, but if the plugin throws we leave those entries in_nonGlobalPlugins
/_globalPlugins
. The plugin is then disabled and never queried, yet its keywords keep hijacking lookups, leaving users with empty results and blocking other plugins that might share the same keyword until restart. Please remove the keywords when initialization fails.catch (Exception e) { PublicApi.Instance.LogException(ClassName, $"Fail to Init plugin: {pair.Metadata.Name}", e); @@ _allInitializedPlugins.TryAdd(pair.Metadata.ID, pair); _initFailedPlugins.TryAdd(pair.Metadata.ID, pair); + + foreach (var keyword in pair.Metadata.ActionKeywords.Distinct()) + { + if (keyword == Query.GlobalPluginWildcardSign) + { + _globalPlugins.TryRemove(pair.Metadata.ID, out _); + } + else + { + _nonGlobalPlugins.TryRemove(keyword, out _); + } + } return; }Flow.Launcher/MainWindow.xaml.cs (1)
860-895
: Fix wording to unblock spelling check.CI fails because the comment uses the banned phrase “work around” (see spelling check output). Rephrase it so the noun “workaround” is used instead.
- // Initialize call twice to work around multi-display alignment issue- https://github.com/Flow-Launcher/Flow.Launcher/issues/2910 + // Initialize twice as a workaround for the multi-display alignment issue - https://github.com/Flow-Launcher/Flow.Launcher/issues/2910 @@ - // Initialize call twice to work around multi-display alignment issue- https://github.com/Flow-Launcher/Flow.Launcher/issues/2910 + // Initialize twice as a workaround for the multi-display alignment issue - https://github.com/Flow-Launcher/Flow.Launcher/issues/2910
🧹 Nitpick comments (1)
Flow.Launcher.Core/Resource/Internationalization.cs (1)
361-394
: Consider eliminating duplication by calling the new helper.The bulk method
UpdatePluginMetadataTranslations()
and the new single-plugin methodUpdatePluginMetadataTranslation(PluginPair p)
contain identical per-plugin logic. Once the bug in line 366 is fixed, you could refactor the bulk method to call the new helper, reducing duplication and improving maintainability.Example refactor for the bulk method:
public static void UpdatePluginMetadataTranslations() { // Update plugin metadata name & description foreach (var p in PluginManager.GetTranslationPlugins()) { - if (p.Plugin is not IPluginI18n pluginI18N) continue; - try - { - p.Metadata.Name = pluginI18N.GetTranslatedPluginTitle(); - p.Metadata.Description = pluginI18N.GetTranslatedPluginDescription(); - pluginI18N.OnCultureInfoChanged(CultureInfo.CurrentCulture); - } - catch (Exception e) - { - PublicApi.Instance.LogException(ClassName, $"Failed for <{p.Metadata.Name}>", e); - } + UpdatePluginMetadataTranslation(p); } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
Flow.Launcher.Core/Plugin/IResultUpdateRegister.cs
(1 hunks)Flow.Launcher.Core/Plugin/PluginManager.cs
(22 hunks)Flow.Launcher.Core/Plugin/PluginsLoader.cs
(2 hunks)Flow.Launcher.Core/Resource/Internationalization.cs
(1 hunks)Flow.Launcher.Infrastructure/DialogJump/DialogJump.cs
(4 hunks)Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs
(2 hunks)Flow.Launcher/App.xaml.cs
(3 hunks)Flow.Launcher/Languages/en.xaml
(1 hunks)Flow.Launcher/MainWindow.xaml.cs
(1 hunks)Flow.Launcher/PublicAPIInstance.cs
(1 hunks)Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginsViewModel.cs
(1 hunks)Flow.Launcher/ViewModel/MainViewModel.cs
(7 hunks)Flow.Launcher/ViewModel/PluginViewModel.cs
(1 hunks)
🧰 Additional context used
🧠 Learnings (5)
📚 Learning: 2025-07-01T05:46:13.251Z
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3791
File: Flow.Launcher.Core/Plugin/PluginManager.cs:293-295
Timestamp: 2025-07-01T05:46:13.251Z
Learning: In Flow.Launcher.Core/Plugin/PluginManager.cs, when checking if a plugin is modified within the PluginManager class itself, prefer using the internal static PluginModified(string id) method directly rather than going through API.PluginModified() for better performance and architectural design.
Applied to files:
Flow.Launcher/PublicAPIInstance.cs
Flow.Launcher.Core/Plugin/PluginManager.cs
📚 Learning: 2025-07-21T09:19:19.012Z
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3854
File: Flow.Launcher.Core/Plugin/PluginManager.cs:280-292
Timestamp: 2025-07-21T09:19:19.012Z
Learning: In Flow Launcher's PluginManager.cs, the post-initialization operations (RegisterResultsUpdatedEvent, UpdatePluginMetadataTranslation, RegisterPluginActionKeywords, DialogJump.InitializeDialogJumpPlugin, and AddPluginToLists) are designed to be exception-safe and do not require additional try-catch error handling according to the maintainer Jack251970.
Applied to files:
Flow.Launcher.Core/Plugin/PluginManager.cs
Flow.Launcher/App.xaml.cs
📚 Learning: 2025-07-21T09:19:49.684Z
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3854
File: Flow.Launcher/App.xaml.cs:246-262
Timestamp: 2025-07-21T09:19:49.684Z
Learning: In Flow Launcher's App.xaml.cs, the asynchronous plugin initialization task (containing AbstractPluginEnvironment.PreStartPluginExecutablePathUpdate, PluginManager.LoadPlugins, PluginManager.InitializePluginsAsync, and AutoPluginUpdates) does not require additional try-catch error handling according to maintainer Jack251970, as these operations are designed to handle exceptions internally.
Applied to files:
Flow.Launcher.Core/Plugin/PluginManager.cs
Flow.Launcher/App.xaml.cs
📚 Learning: 2025-07-06T12:21:37.947Z
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3572
File: Flow.Launcher/App.xaml.cs:214-216
Timestamp: 2025-07-06T12:21:37.947Z
Learning: In Flow Launcher, the UpdatePluginManifestAsync method in PluginsManifest.cs already has comprehensive internal try-catch handling that logs exceptions and returns false on failure rather than throwing, making external try-catch wrappers unnecessary.
Applied to files:
Flow.Launcher.Core/Plugin/PluginManager.cs
Flow.Launcher/App.xaml.cs
📚 Learning: 2025-08-13T06:12:43.382Z
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3897
File: Flow.Launcher/ViewModel/PluginViewModel.cs:46-51
Timestamp: 2025-08-13T06:12:43.382Z
Learning: In Flow Launcher's PluginViewModel.cs, the LoadIconAsync method does not require additional try-catch error handling according to maintainer Jack251970, as the existing error handling approach is considered sufficient for the image loading operations.
Applied to files:
Flow.Launcher.Core/Plugin/PluginManager.cs
Flow.Launcher/App.xaml.cs
🪛 GitHub Actions: Check Spelling
Flow.Launcher/MainWindow.xaml.cs
[error] 861-861: Error - work around
matches a line_forbidden.patterns entry: \bwork[- ]arounds?\b
.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: gitStream.cm
🔇 Additional comments (9)
Flow.Launcher/Languages/en.xaml (1)
69-72
: LGTM! Clear user feedback for async plugin states.The four new localized strings provide clear, actionable feedback to users when plugins are still initializing or fail to respond. The naming follows existing conventions, the placeholder usage is correct, and the messages are grammatically sound. These additions directly support the PR's objective of improving the user experience during asynchronous plugin loading.
Flow.Launcher.Core/Resource/Internationalization.cs (1)
380-394
: LGTM! Per-plugin translation helper correctly implemented.The new method correctly extracts the per-plugin translation logic for individual plugin initialization. The implementation mirrors the bulk updater and handles errors appropriately.
Flow.Launcher.Core/Plugin/PluginsLoader.cs (4)
51-51
: LGTM: Return type change improves clarity.Changing from
IEnumerable<PluginPair>
toList<PluginPair>
is appropriate since the method materializes the collection immediately. The caller chains this with other sources and materializes to a list anyway, so this change eliminates deferred-execution complexity and improves clarity.
60-108
: Plugin construction and measurement logic is correct.Moving plugin construction, error handling, and list addition inside the stopwatch lambda ensures that constructor timing is accurately captured. The early return when
plugin == null
(line 104) correctly prevents adding failed plugins to the list.Note: Including the list addition (line 107) inside the stopwatch slightly inflates the reported constructor cost, but the impact is negligible since list addition is O(1).
110-111
: Good addition: Info-level logging improves observability.Adding Info-level logging for each plugin's constructor cost addresses the concern raised in PR comments about needing clear logging for plugin load/finish events. The message format is clear and includes the plugin name and timing.
77-98
: Error handling is appropriate.The error handling correctly distinguishes between DEBUG and non-DEBUG builds:
- DEBUG: Rethrows exceptions to surface issues during development.
- Non-DEBUG: Catches and logs exceptions with context-specific messages for different failure modes (assembly load, interface missing, type load, general errors).
The pattern-match filter
when (assembly == null)
on line 83 appropriately narrows the first catch block to assembly load failures.Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginsViewModel.cs (3)
117-121
: Type change from IList to List is appropriate.Changing from
IList<PluginViewModel>
toList<PluginViewModel>
makes the property signature match the actual returned type (the getter calls.ToList()
). Since this is a view model property exposed to the UI, using the concrete type is acceptable and improves clarity.
118-120
: Good documentation: Comments clarify design intent.The comments clearly explain why all plugin states (Initializing, Initialized, Init failed) are included in the settings view. This aligns with the PR's async initialization model and ensures users can manage plugins even when they're still loading or have failed to initialize.
121-121
: No action needed:GetAllPlugins()
covers all plugin states
App.API.GetAllPlugins()
delegates toPluginManager.GetAllLoadedPlugins()
, which returns_allLoadedPlugins.Values
. Since_allLoadedPlugins
is populated with every plugin before and during initialization—and never excludes failures—it includes initializing, initialized, and init-failed plugins as intended.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
This comment has been minimized.
This comment has been minimized.
@coderabbitai full review |
✅ Actions performedFull review triggered. |
@check-spelling-bot Report🔴 Please reviewSee the 📂 files view, the 📜action log, or 📝 job summary for details.
See ❌ Event descriptions for more information. Forbidden patterns 🙅 (1)In order to address this, you could change the content to not match the forbidden patterns (comments before forbidden patterns may help explain why they're forbidden), add patterns for acceptable instances, or adjust the forbidden patterns themselves. These forbidden patterns matched content: s.b. workaround(s)
If the flagged items are 🤯 false positivesIf items relate to a ...
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (2)
Flow.Launcher/App.xaml.cs (1)
216-216
: Variable naming corrected.The variable name has been updated to
imageLoaderTask
with proper camelCase, addressing the previous spelling warning.Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginsViewModel.cs (1)
11-11
: Spell checker false positive (duplicate).Same as in App.xaml.cs, 'iNKORE' is part of the package namespace and should be added to spell check exceptions.
🧹 Nitpick comments (1)
Flow.Launcher/App.xaml.cs (1)
25-25
: Consider adding 'iNKORE' to spell check exceptions.The pipeline reports 'NKORE' as unrecognized, but this is part of the
iNKORE.UI.WPF.Modern
package namespace. Consider adding this to the spell checker's exception list to suppress the false positive.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
Flow.Launcher/App.xaml.cs
(3 hunks)Flow.Launcher/MainWindow.xaml.cs
(1 hunks)Flow.Launcher/PublicAPIInstance.cs
(1 hunks)Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginsViewModel.cs
(1 hunks)Flow.Launcher/ViewModel/MainViewModel.cs
(5 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- Flow.Launcher/MainWindow.xaml.cs
- Flow.Launcher/PublicAPIInstance.cs
- Flow.Launcher/ViewModel/MainViewModel.cs
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-07-21T09:19:49.684Z
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3854
File: Flow.Launcher/App.xaml.cs:246-262
Timestamp: 2025-07-21T09:19:49.684Z
Learning: In Flow Launcher's App.xaml.cs, the asynchronous plugin initialization task (containing AbstractPluginEnvironment.PreStartPluginExecutablePathUpdate, PluginManager.LoadPlugins, PluginManager.InitializePluginsAsync, and AutoPluginUpdates) does not require additional try-catch error handling according to maintainer Jack251970, as these operations are designed to handle exceptions internally.
Applied to files:
Flow.Launcher/App.xaml.cs
📚 Learning: 2025-07-21T09:19:19.012Z
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3854
File: Flow.Launcher.Core/Plugin/PluginManager.cs:280-292
Timestamp: 2025-07-21T09:19:19.012Z
Learning: In Flow Launcher's PluginManager.cs, the post-initialization operations (RegisterResultsUpdatedEvent, UpdatePluginMetadataTranslation, RegisterPluginActionKeywords, DialogJump.InitializeDialogJumpPlugin, and AddPluginToLists) are designed to be exception-safe and do not require additional try-catch error handling according to the maintainer Jack251970.
Applied to files:
Flow.Launcher/App.xaml.cs
📚 Learning: 2025-07-06T12:21:37.947Z
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3572
File: Flow.Launcher/App.xaml.cs:214-216
Timestamp: 2025-07-06T12:21:37.947Z
Learning: In Flow Launcher, the UpdatePluginManifestAsync method in PluginsManifest.cs already has comprehensive internal try-catch handling that logs exceptions and returns false on failure rather than throwing, making external try-catch wrappers unnecessary.
Applied to files:
Flow.Launcher/App.xaml.cs
📚 Learning: 2025-08-13T06:12:43.382Z
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3897
File: Flow.Launcher/ViewModel/PluginViewModel.cs:46-51
Timestamp: 2025-08-13T06:12:43.382Z
Learning: In Flow Launcher's PluginViewModel.cs, the LoadIconAsync method does not require additional try-catch error handling according to maintainer Jack251970, as the existing error handling approach is considered sufficient for the image loading operations.
Applied to files:
Flow.Launcher/App.xaml.cs
🧬 Code graph analysis (2)
Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginsViewModel.cs (2)
Flow.Launcher/PublicAPIInstance.cs (3)
List
(250-250)List
(252-253)List
(532-532)Flow.Launcher.Core/Plugin/PluginManager.cs (5)
List
(559-562)List
(564-575)List
(577-580)List
(587-590)List
(628-655)
Flow.Launcher/App.xaml.cs (7)
Flow.Launcher.Infrastructure/Logger/Log.cs (1)
SetLogLevel
(66-84)Flow.Launcher.Infrastructure/Image/ImageLoader.cs (1)
ImageLoader
(17-411)Flow.Launcher/MainWindow.xaml.cs (3)
MainWindow
(37-1498)MainWindow
(86-102)InitializeDialogJump
(1432-1438)Flow.Launcher.Infrastructure/DialogJump/DialogJump.cs (3)
DialogJump
(20-1086)InitializeDialogJump
(105-124)SetupDialogJump
(149-316)Flow.Launcher/Helper/HotKeyMapper.cs (2)
HotKeyMapper
(13-168)Initialize
(20-31)Flow.Launcher/PublicAPIInstance.cs (2)
SaveAppAllSettings
(107-116)LogInfo
(278-279)Flow.Launcher.Core/Plugin/PluginManager.cs (2)
PluginManager
(24-1047)PluginManager
(168-174)
🪛 GitHub Actions: Check Spelling
Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginsViewModel.cs
[warning] 11-11: unrecognized-spelling: 'NKORE' is not a recognized word.
Flow.Launcher/App.xaml.cs
[warning] 25-25: unrecognized-spelling: 'NKORE' is not a recognized word.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: gitStream.cm
- GitHub Check: build
🔇 Additional comments (6)
Flow.Launcher/App.xaml.cs (5)
190-191
: LGTM! Early log level setup is correct.Setting the log level before any logging operations is the right approach and the comment clearly explains the requirement.
197-198
: LGTM! Notification system initialization is properly positioned.Installing the notification system before any notification API calls prevents potential initialization issues.
206-207
: LGTM! Portability cleanup is correctly positioned.Performing cleanup after language initialization is appropriate since cleanup operations may require localized messages.
230-234
: LGTM! DialogJump initialization sequencing is correct.The initialization is properly positioned after main window creation (to access window handle) and before hotkey mapper initialization. The comments clearly document the sequencing requirements.
252-275
: LGTM! Asynchronous plugin initialization correctly implements the PR objectives.The plugin initialization is now decoupled from main window startup, allowing the UI to show immediately while plugins load in the background. Key improvements:
- Fire-and-forget pattern allows main window to start without blocking
- Home page refresh logic (lines 264-267) handles users opening the window during initialization, ensuring complete results once all plugins finish loading
- Maintains proper sequencing: path updates → load plugins → initialize plugins → updates → save
This change successfully addresses the core issue where slow plugins blocked the main window from appearing.
Based on learnings
Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginsViewModel.cs (1)
117-130
: LGTM! Property changes correctly support asynchronous plugin initialization.The changes appropriately handle the new plugin lifecycle:
- Changing from
IList
toList
aligns with the underlying API return type- Using
App.API.GetAllPlugins()
now includes plugins in all states (Initializing, Initialized, Init failed)- The comments clearly explain why all plugin states are needed: to allow uninstalling failed plugins and changing settings for initializing plugins
This is essential for the async plugin loading feature, ensuring users can manage plugins even while initialization is in progress.
CHANGES
Since plugin initialization can cost plenty of time, let us start the main window first and then load and initialize the window to improve window startup speed.
If there is one plugin which consumes long time to load or initialize, main window will show UI to notify users and query other plugins for results so that all things in main window will not affected by that initializing plugin.
Fix #2854
TEST
await Task.Delay(30000)
inPlugin Manager
plugin. Main window toggle and query still work. If users query this plugin, it will tell users that this plugin is still initializing: