Skip to content

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

Open
wants to merge 47 commits into
base: dev
Choose a base branch
from

Conversation

Jack251970
Copy link
Member

@Jack251970 Jack251970 commented Jul 21, 2025

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, the plugin section in setting window will just display other plugins and main window will query other plugins for results so that all things in main window will not affected by that bad plugin.

TEST

  • Add await Task.Delay(100000) in Plugin Manager plugin and main window toggle and query still work.
  • Change action keyword or uninstall initializing plugins can work.
  • Performance: Time period from application start to tray icon menu showing improves from 6.73s to 2.81s with about 30 plugins.
  • If users have home page plugin with long time to initialize, the main window will refresh when all plugins are initialized

This comment has been minimized.

Copy link

gitstream-cm bot commented Jul 21, 2025

Be a legend 🏆 by adding a before and after screenshot of the changes you made, especially if they are around UI/UX.

@coderabbitai coderabbitai bot added the enhancement New feature or request label Jul 21, 2025
Copy link
Contributor

coderabbitai bot commented Jul 21, 2025

📝 Walkthrough

Walkthrough

This change refactors plugin management and initialization to use thread-safe concurrent collections, introduces the IResultUpdateRegister interface for plugin result update event registration, and updates related classes and initialization flows accordingly. Several properties are replaced with methods, and plugin registration, querying, and event handling are updated for improved concurrency and modularity. Additionally, plugin metadata translation updates and dialog jump plugin registration are improved for thread safety and modularity, and startup sequencing is adjusted to separate plugin initialization.

Changes

File(s) Change Summary
Flow.Launcher.Core/Plugin/PluginManager.cs Refactored all plugin collections to use concurrent collections; replaced properties with methods; updated plugin loading, initialization, registration, querying, and lifecycle management for thread safety and asynchrony; added new helper methods for action keywords and plugin registration; improved error handling during initialization.
Flow.Launcher.Core/Plugin/IResultUpdateRegister.cs Introduced new interface IResultUpdateRegister with method RegisterResultsUpdatedEvent(PluginPair) for registering plugin result update events.
Flow.Launcher.ViewModel/MainViewModel.cs Implemented IResultUpdateRegister; refactored event registration for plugin result updates to register per plugin; updated to use new concurrent plugin retrieval methods; improved cancellation handling with async cancellation; updated query construction to use method calls instead of properties.
Flow.Launcher.Core/Resource/Internationalization.cs Added method UpdatePluginMetadataTranslation(PluginPair) to update a single plugin's metadata translation and invoke culture change callbacks with error logging.
Flow.Launcher.Infrastructure/DialogJump/DialogJump.cs Changed dialog jump collections to concurrent dictionaries; refactored initialization to remove external parameters and use internal concurrent collections; added method to initialize dialog jump plugins incrementally with thread-safe adds.
Flow.Launcher/App.xaml.cs Refactored startup sequence: moved plugin environment preparation, loading, initialization, and auto-update into a separate asynchronous task; reordered notification and dialog jump initialization; removed redundant plugin metadata translation update call from startup; adjusted log message formatting.
Flow.Launcher.PublicAPIInstance.cs Updated GetAllPlugins() method to return initialized plugins via PluginManager.GetAllLoadedPlugins() instead of using the deprecated AllPlugins property.
Flow.Launcher.SettingPages.ViewModels.SettingsPanePluginsViewModel.cs Changed plugin list property to use App.API.GetAllPlugins() for retrieving all loaded plugins instead of PluginManager.AllPlugins; changed backing field type from IList to List.
Flow.Launcher.MainWindow.xaml.cs Updated query construction in Backspace key handler to use PluginManager.GetNonGlobalPlugins() method instead of the NonGlobalPlugins property.
Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs Added XML documentation remarks to GetAllPlugins() method clarifying some plugins may not be initialized yet.
Flow.Launcher.ViewModel/PluginViewModel.cs Updated HasSettingControl property to return false if the plugin is initializing or initialization failed, preventing settings panel display for such plugins.
Flow.Launcher.Core/Plugin/PluginsLoader.cs Changed DotNetPlugins method return type from IEnumerable<PluginPair> to List<PluginPair>; minor formatting adjustments without logic changes.

Sequence Diagram(s)

sequenceDiagram
    participant App
    participant PluginManager
    participant MainViewModel
    participant IResultUpdateRegister

    App->>PluginManager: Prepare environment
    App->>PluginManager: LoadPlugins(settings)
    PluginManager-->>App: List<PluginPair>
    App->>PluginManager: InitializePluginsAsync(IResultUpdateRegister)
    PluginManager->>MainViewModel: RegisterResultsUpdatedEvent(plugin)
    MainViewModel->>PluginPair: Subscribe to ResultsUpdated event
Loading
sequenceDiagram
    participant PluginPair
    participant MainViewModel

    PluginPair->>MainViewModel: ResultsUpdated event
    MainViewModel->>MainViewModel: Validate query and cancellation
    MainViewModel->>MainViewModel: Clone results, set badge icons, update metadata
    MainViewModel->>MainViewModel: Enqueue results for UI update
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • taooceros
  • jjw24

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3221f93 and 97fb8d6.

📒 Files selected for processing (4)
  • Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs (1 hunks)
  • Flow.Launcher/MainWindow.xaml.cs (1 hunks)
  • Flow.Launcher/PublicAPIInstance.cs (1 hunks)
  • Flow.Launcher/ViewModel/MainViewModel.cs (7 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • Flow.Launcher/MainWindow.xaml.cs
  • Flow.Launcher/PublicAPIInstance.cs
  • Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs
  • Flow.Launcher/ViewModel/MainViewModel.cs
⏰ 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: build
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch plugin_initialization

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🔭 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 duplication

The 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 and TryAdd where another thread could add the same key. Consider using AddOrUpdate 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 of Remove for ConcurrentDictionary (line 892).

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c02ef0e and 50924e4.

📒 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 safety

The migration from Dictionary to ConcurrentDictionary is appropriate for the asynchronous plugin loading model. This ensures thread-safe access when plugins are initialized concurrently.


109-115: LGTM! Simplified initialization approach

The removal of parameters and use of TryAdd for preinstalled components aligns well with the new plugin initialization model.


130-151: Well-designed plugin registration method

The 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 method

The change from PluginManager.NonGlobalPlugins property to PluginManager.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 registration

The 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 to PluginManager.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:

  1. Main window starts immediately without waiting for plugins
  2. Plugin loading happens in parallel without blocking UI
  3. Proper logging tracks plugin initialization performance
  4. 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 update

Actually, 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 verified

A 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 a List<PluginPair> as expected.
  • PluginManager.InitializePluginsAsync(List<PluginPair>, IResultUpdateRegister) matches the call in App.xaml.cs.
  • MainViewModel implements IResultUpdateRegister, 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 corresponding RegisterResultsUpdatedEvent 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 to PluginManager.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 frameworks

All 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 lookups
  • ConcurrentBag for unordered plugin lists where iteration is the primary operation

This 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.

Copy link

gitstream-cm bot commented Jul 21, 2025

🥷 Code experts: taooceros

Jack251970, taooceros have most 👩‍💻 activity in the files.
Jack251970, taooceros have most 🧠 knowledge in the files.

See details

Flow.Launcher.Core/Plugin/PluginManager.cs

Activity based on git-commit:

Jack251970 taooceros
JUL 95 additions & 54 deletions 71 additions & 5 deletions
JUN 74 additions & 273 deletions
MAY 298 additions & 25 deletions
APR 73 additions & 68 deletions
MAR 42 additions & 37 deletions
FEB 276 additions & 198 deletions

Knowledge based on git-blame:
Jack251970: 37%
taooceros: 11%

Flow.Launcher.Core/Resource/Internationalization.cs

Activity based on git-commit:

Jack251970 taooceros
JUL 143 additions & 98 deletions
JUN
MAY 31 additions & 13 deletions
APR 34 additions & 30 deletions
MAR 67 additions & 40 deletions
FEB 5 additions & 4 deletions

Knowledge based on git-blame:
Jack251970: 67%

Flow.Launcher.Infrastructure/DialogJump/DialogJump.cs

Activity based on git-commit:

Jack251970 taooceros
JUL 1079 additions & 0 deletions
JUN
MAY
APR
MAR
FEB

Knowledge based on git-blame:
taooceros: 100%

Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs

Activity based on git-commit:

Jack251970 taooceros
JUL 23 additions & 5 deletions
JUN 45 additions & 2 deletions
MAY 4 additions & 1 deletions
APR 228 additions & 27 deletions
MAR
FEB 38 additions & 28 deletions

Knowledge based on git-blame:
Jack251970: 51%
taooceros: 3%

Flow.Launcher/App.xaml.cs

Activity based on git-commit:

Jack251970 taooceros
JUL 48 additions & 10 deletions 5 additions & 0 deletions
JUN 6 additions & 0 deletions
MAY 51 additions & 28 deletions
APR 73 additions & 40 deletions
MAR 168 additions & 94 deletions
FEB 79 additions & 40 deletions

Knowledge based on git-blame:
Jack251970: 71%
taooceros: 2%

Flow.Launcher/MainWindow.xaml.cs

Activity based on git-commit:

Jack251970 taooceros
JUL 26 additions & 11 deletions 83 additions & 7 deletions
JUN 91 additions & 71 deletions
MAY 145 additions & 43 deletions
APR 69 additions & 45 deletions
MAR 1141 additions & 1076 deletions
FEB 1 additions & 1 deletions

Knowledge based on git-blame:
Jack251970: 64%
taooceros: 6%

Flow.Launcher/PublicAPIInstance.cs

Activity based on git-commit:

Jack251970 taooceros
JUL 18 additions & 6 deletions
JUN 54 additions & 22 deletions
MAY 124 additions & 131 deletions
APR 165 additions & 61 deletions
MAR 21 additions & 19 deletions
FEB 28 additions & 11 deletions

Knowledge based on git-blame:
Jack251970: 54%
taooceros: 3%

Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginsViewModel.cs

Activity based on git-commit:

Jack251970 taooceros
JUL
JUN
MAY 58 additions & 13 deletions
APR 102 additions & 62 deletions
MAR 2 additions & 1 deletions
FEB

Knowledge based on git-blame:
Jack251970: 65%

Flow.Launcher/ViewModel/MainViewModel.cs

Activity based on git-commit:

Jack251970 taooceros
JUL 16 additions & 1 deletions 344 additions & 65 deletions
JUN 25 additions & 13 deletions
MAY 529 additions & 316 deletions
APR 35 additions & 28 deletions
MAR 695 additions & 628 deletions
FEB 63 additions & 21 deletions

Knowledge based on git-blame:
Jack251970: 34%
taooceros: 17%

✨ Comment /gs review for LinearB AI review. Learn how to automate it here.

This comment has been minimized.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 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 switch

Also 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 of Remove for consistency with ConcurrentDictionary API.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 50924e4 and 566572b.

📒 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.

This comment has been minimized.

@Jack251970
Copy link
Member Author

@coderabbitai full review

Copy link
Contributor

coderabbitai bot commented Jul 21, 2025

✅ Actions performed

Full review triggered.

@jjw24
Copy link
Member

jjw24 commented Jul 21, 2025

How do we indicate/notify that plugin/plugins are still loading and no results will be returned yet? We need to avoid the confusion like e.g. flow is broken because I don't get any bookmarks in the results.

@Jack251970
Copy link
Member Author

How do we indicate/notify that plugin/plugins are still loading and no results will be returned yet? We need to avoid the confusion like e.g. flow is broken because I don't get any bookmarks in the results.

I do not think we need to do that because it is unlikely that all plugins installed by users will take a long time to initialize. There should be some plugins which are loaded and initialized very fast

This comment has been minimized.

@jjw24
Copy link
Member

jjw24 commented Jul 21, 2025

Remind me again do we clearly log when plugin finished loading? If we don't notify then I think the log should make it easy to see which plugin finished and which is still loading. In case with issues like we experienced in the roll out of favicon loading in Bookmarks plugin.

@Jack251970
Copy link
Member Author

Remind me again do we clearly log when plugin finished loading? If we don't notify then I think the log should make it easy to see which plugin finished and which is still loading. In case with issues like we experienced in the roll out of favicon loading in Bookmarks plugin.

Let me check. Flow will log when one plugin is initialized in InitAsync (PluginManager.cs) and will also log when one plugin is loaded and Constructed (PluginLoader.cs).

This comment has been minimized.

@Jack251970
Copy link
Member Author

Jack251970 commented Jul 21, 2025

Remind me again do we clearly log when plugin finished loading? If we don't notify then I think the log should make it easy to see which plugin finished and which is still loading. In case with issues like we experienced in the roll out of favicon loading in Bookmarks plugin.

And I find plugin constructor log is only for Debug log level, so if users set log level to Info, nothing will be logged.

While plugin initialization has both debug and info log level, so it will always disappear in log files.

I will add info log message for constructor to resolve this. (Done in Add info log message for plugin constructors)

This comment has been minimized.

Copy link

@check-spelling-bot Report

🔴 Please review

See the 📂 files view, the 📜action log, or 📝 job summary for details.

❌ Errors Count
❌ forbidden-pattern 2

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)

\bwork[- ]arounds?\b
If the flagged items are 🤯 false positives

If items relate to a ...

  • binary file (or some other file you wouldn't want to check at all).

    Please add a file path to the excludes.txt file matching the containing file.

    File paths are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your files.

    ^ refers to the file's path from the root of the repository, so ^README\.md$ would exclude README.md (on whichever branch you're using).

  • well-formed pattern.

    If you can write a pattern that would match it,
    try adding it to the patterns.txt file.

    Patterns are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your lines.

    Note that patterns can't match multiline strings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants