Skip to content
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

Fix copy to clipboard STA thread issue & Add retry for copy #3314

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

Conversation

Jack251970
Copy link
Contributor

@Jack251970 Jack251970 commented Mar 6, 2025

Fix copy to clipboard STA thread issue

Fix CopyToClipboard function in JsonRPCAPI for JsonRPCV2 plugins: we should use STA thread to execute clipboard options.

Close #3071.

Add retry for clipboard copy

Sometimes clipboard is locked, we need to wait and retry.

Test

  • Copy to clipboard (text, file) on csharp plugins
  • Copy to clipboard (text, file) on JsonRPCV2 plugins
  • Get text from clipboard

@prlabeler prlabeler bot added the bug Something isn't working label Mar 6, 2025

This comment has been minimized.

Copy link

gitstream-cm bot commented Mar 6, 2025

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

Copy link
Contributor

coderabbitai bot commented Mar 6, 2025

📝 Walkthrough

Walkthrough

This pull request updates several components in the application. It adds two new Windows API entries (OleInitialize and OleUninitialize) in the native methods file. It introduces two new asynchronous STA task methods in the helper class and modifies existing clipboard functionality to use asynchronous calls with a retry mechanism. The changes also include an update to the language resources by adding a new error message for copy failures, and adjustments in the public API method signature to support asynchronous clipboard operations.

Changes

File(s) Change Summary
Flow.Launcher/…/NativeMethods.txt Added two new Windows API function entries: OleInitialize and OleUninitialize. Restored entry for WM_EXITSIZEMOVE.
Flow.Launcher/…/Win32Helper.cs Added two public static methods: StartSTATaskAsync(Action action) and StartSTATaskAsync<T>(Func<T> func) to facilitate asynchronous execution on STA threads with proper OLE initialization and uninitialization.
Flow.Launcher/…/UserSettings/Settings.cs and
Flow.Launcher/…/PublicAPIInstance.cs
Modified clipboard access: In Settings.cs, replaced direct synchronous clipboard invocation with an asynchronous lambda. In PublicAPIInstance.cs, updated CopyToClipboard to be asynchronous and introduced a retry mechanism via RetryActionOnSTAThreadAsync.
Flow.Launcher/…/Languages/en.xaml Added a new string resource <system:String x:Key="failedToCopy">Failed to copy</system:String> for indicating copy operation failures.

Sequence Diagram(s)

sequenceDiagram
    participant App as Application
    participant API as PublicAPIInstance
    participant RT as RetryActionOnSTAThreadAsync
    participant STA as Win32Helper (STA Task)
    participant Clip as Clipboard API

    App->>API: CopyToClipboard(data)
    API->>API: Validate input
    API->>RT: Invoke retry mechanism with clipboard action
    RT->>STA: Call StartSTATaskAsync(action)
    STA->>STA: OleInitialize & Execute clipboard action
    STA->>Clip: Call Clipboard.SetText / SetFileDropList
    Clip-->>STA: Return success/failure
    STA-->>RT: Return result
    RT-->>API: Propagate outcome
    API-->>App: Notify success or error
Loading
sequenceDiagram
    participant Caller as Calling Method
    participant STA as New STA Thread
    participant OLE as OLE Functions

    Caller->>STA: Invoke StartSTATaskAsync(Action/Func)
    STA->>OLE: OleInitialize()
    STA->>STA: Execute provided action/function
    STA->>OLE: OleUninitialize()
    STA-->>Caller: Return task result
Loading

Assessment against linked issues

Objective Addressed Explanation
Fix CopyToClipboard method to prevent STA-related errors (#3071)

Possibly related PRs

Suggested labels

1 min review

Poem

In my burrow, I hop with glee,
New functions and async flow set me free.
Clipboard tasks now race with time,
With OLE magic, everything’s sublime.
Code carrots crunch—oh what a spree! 🐇
Happy hops and fewer bugs for me!


📜 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 17ecebf and c98c419.

📒 Files selected for processing (1)
  • Flow.Launcher.Infrastructure/Win32Helper.cs (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: gitStream.cm
🔇 Additional comments (4)
Flow.Launcher.Infrastructure/Win32Helper.cs (4)

4-5: LGTM: Appropriate imports for thread and task functionality

The additional imports for System.Threading and System.Threading.Tasks are necessary for the new STA thread functionality.


323-328: Good attribution practice

Properly citing the source of inspiration for the implementation from the Files Community project. This follows good open-source practices for code attribution.


329-359: Well-implemented STA thread execution with proper exception handling

This implementation correctly:

  1. Creates and configures an STA thread
  2. Initializes OLE on that thread (needed for clipboard operations)
  3. Properly propagates exceptions to the caller
  4. Ensures OLE is uninitialized in all cases via the finally block

This addresses the core issue mentioned in the PR objectives of ensuring clipboard operations run on an STA thread.


361-391: Robust generic implementation for STA tasks that return values

The generic implementation follows the same pattern as the non-generic version, correctly handling return values and exceptions. Both methods follow the same structure which makes maintenance easier.

The previous review comments about exception handling have been properly addressed in this implementation.

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 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.
    • Generate unit testing code for this file.
    • 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 generate unit testing code for this file.
    • @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 generate unit testing code.
    • @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.

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

@Yusyuriv
Copy link
Member

Yusyuriv commented Mar 6, 2025

I am very against this. This is the core, most used, functionality, and it should be available to everyone. Plugins shouldn't need to reinvent the wheel every time. Especially considering Node and Python don't provide a way to do this. I remember seeing one plugin that packed another binary with itself just so it could copy text, which is absolutely ridiculous.

@Jack251970
Copy link
Contributor Author

Jack251970 commented Mar 6, 2025

I am very against this. This is the core, most used, functionality, and it should be available to everyone. Plugins shouldn't need to reinvent the wheel every time. Especially considering Node and Python don't provide a way to do this. I remember seeing one plugin that packed another binary with itself just so it could copy text, which is absolutely ridiculous.

Well, could you please give me the sample to test?

@Jack251970 Jack251970 changed the title Delete CopyToClipboard function in JsonRPC api [TODO] Fix CopyToClipboard function in JsonRPC api Mar 6, 2025
@Yusyuriv Yusyuriv marked this pull request as draft March 6, 2025 05:22
@Jack251970 Jack251970 changed the title [TODO] Fix CopyToClipboard function in JsonRPC api Fix CopyToClipboard function in JsonRPC api Mar 6, 2025
@Jack251970 Jack251970 changed the title Fix CopyToClipboard function in JsonRPC api Fix CopyToClipboard function in JsonRPCAPI for JsonRPCV2 plugins Mar 6, 2025
@Yusyuriv
Copy link
Member

Yusyuriv commented Mar 6, 2025

demo-plugin.zip

After installing this plugin, type rpc2. It will have one result. Select that result. You'll get a message box saying if the text was copied successfully or not.

@Jack251970
Copy link
Contributor Author

demo-plugin.zip

After installing this plugin, type rpc2. It will have one result. Select that result. You'll get a message box saying if the text was copied successfully or not.

Many thanks! Sorry, I don't see this as a bug unique to the V2 plugin. In that case, the bug could be fixed.

@Jack251970
Copy link
Contributor Author

Jack251970 commented Mar 6, 2025

demo-plugin.zip

After installing this plugin, type rpc2. It will have one result. Select that result. You'll get a message box saying if the text was copied successfully or not.

Sorry I cannot open your demo plugin. I have used 1.19.5 release version of FL (master branch) and downloaded embedded node.js environment from FL but I got this issue:

image

I want to check it by myself, but I really know little about JavaScript. Could you please fix it?

@Yusyuriv
Copy link
Member

Yusyuriv commented Mar 6, 2025

Could you please install a newer version of NodeJS (v22), specify it in settings (General — Node.js Path) and try again? Flow currently uses very old version that has reached end-of-life already.

This comment has been minimized.

@Jack251970 Jack251970 changed the title Fix CopyToClipboard function in JsonRPCAPI for JsonRPCV2 plugins Fix copy to clipboard STA thread issue & Add retry for text copy Mar 6, 2025
@Jack251970
Copy link
Contributor Author

Could you please install a newer version of NodeJS (v22), specify it in settings (General — Node.js Path) and try again? Flow currently uses very old version that has reached end-of-life already.

Thanks, I think I have fixed it. Now could you please help me check if copy to clipboard (directory) with JsonRPCV2 plugins can work?

@Jack251970
Copy link
Contributor Author

Could you please install a newer version of NodeJS (v22), specify it in settings (General — Node.js Path) and try again? Flow currently uses very old version that has reached end-of-life already.

Thanks, I think I have fixed it. Now could you please help me check if copy to clipboard (directory) with JsonRPCV2 plugins can work?

Nvm, I have checked it.

@Jack251970 Jack251970 marked this pull request as ready for review March 6, 2025 08:40
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: 1

🧹 Nitpick comments (5)
Flow.Launcher.Infrastructure/Win32Helper.cs (2)

122-125: Consider propagating exceptions rather than suppressing them.

The current implementation catches all exceptions but doesn't propagate them to the caller, making it difficult to diagnose issues when they occur.

-                catch (System.Exception)
-                {
-                    taskCompletionSource.SetResult();
-                }
+                catch (System.Exception ex)
+                {
+                    taskCompletionSource.SetException(ex);
+                }

154-157: Consider propagating exceptions rather than returning default values.

Similar to the non-generic method, this implementation catches all exceptions but doesn't propagate them to the caller. Instead, it returns a default value which could mask errors.

-                catch (System.Exception)
-                {
-                    taskCompletionSource.SetResult(default);
-                }
+                catch (System.Exception ex)
+                {
+                    taskCompletionSource.SetException(ex);
+                }
Flow.Launcher/PublicAPIInstance.cs (3)

131-156: Consolidate repetitive clipboard copy logic.

The logic for direct file/folder copying (lines 131–156) and text copying (lines 160–181) mostly duplicates the retry mechanism and message handling. Consider extracting common retry logic into a shared helper or unify this code block to improve maintainability and clarity.

Also applies to: 160-181


164-164: Fix minor typo in comment.

Change "shouold" to "should" for clarity.

- // We shouold use SetText instead of SetDataObject to avoid the clipboard being locked by other applications
+ // We should use SetText instead of SetDataObject to avoid the clipboard being locked by other applications

185-204: Reconsider returning the exception object from RetryActionOnSTAThreadAsync.

Returning an Exception object directly is functional, but throwing an exception or returning a status (e.g., bool) might simplify the calling code. The current design requires the caller to check for null vs. non-null to determine success/failure, which can be error-prone or less conventional.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 9f8e829 and e5ad777.

📒 Files selected for processing (5)
  • Flow.Launcher.Infrastructure/NativeMethods.txt (1 hunks)
  • Flow.Launcher.Infrastructure/UserSettings/Settings.cs (1 hunks)
  • Flow.Launcher.Infrastructure/Win32Helper.cs (2 hunks)
  • Flow.Launcher/Languages/en.xaml (1 hunks)
  • Flow.Launcher/PublicAPIInstance.cs (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: gitStream.cm
  • GitHub Check: gitStream.cm
  • GitHub Check: gitStream.cm
🔇 Additional comments (4)
Flow.Launcher.Infrastructure/NativeMethods.txt (1)

21-22: Good addition of required OLE function declarations.

These OLE function declarations are necessary for properly initializing and uninitializing the clipboard operations on STA threads, ensuring proper COM interop which is critical for clipboard functionality.

Flow.Launcher/Languages/en.xaml (1)

339-339: Good addition of error message for clipboard operations.

This new string resource will help provide better user feedback when clipboard operations fail, improving the overall user experience.

Flow.Launcher.Infrastructure/UserSettings/Settings.cs (1)

251-251:

✅ Verification successful

Ensure clipboard operations run on STA thread.

Good change to use the new StartSTATaskAsync method for clipboard text retrieval. This ensures proper threading model for COM operations.

Note that using .Result could potentially lead to deadlocks in certain scenarios, but since this is only creating a model with a function reference to be executed later, it should be fine in this context.


🏁 Script executed:

#!/bin/bash
# Check if this pattern is used elsewhere in the codebase where it might cause problems
rg "StartSTATaskAsync.*\.Result" --type cs

Length of output: 248


Verified STA Thread Usage for Clipboard Operations

After reviewing the code and verifying the pattern usage in the codebase, it’s clear that the call to Win32Helper.StartSTATaskAsync(Clipboard.GetText).Result is only present in Flow.Launcher.Infrastructure/UserSettings/Settings.cs. Since this function is used to defer clipboard text retrieval until later execution and is correctly encapsulated within a model creation, the use of .Result here is acceptable and does not pose a deadlock risk in this context.

  • Verified that the snippet is uniquely located in the intended file.
  • Confirmed that clipboard operations are safely executed on an STA thread.
Flow.Launcher.Infrastructure/Win32Helper.cs (1)

104-174: Good implementation of STA thread execution helpers.

The implementation of these helper methods provides a clean way to execute actions on an STA thread, which is necessary for clipboard and other COM operations. Properly initializing and uninitializing OLE ensures resources are managed correctly.

Copy link

gitstream-cm bot commented Mar 6, 2025

🥷 Code experts: onesounds

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

See details

Flow.Launcher.Infrastructure/NativeMethods.txt

Activity based on git-commit:

Jack251970 onesounds
MAR 30 additions & 3 deletions
FEB 4 additions & 1 deletions
JAN 1 additions & 4 deletions
DEC 24 additions & 2 deletions
NOV
OCT

Knowledge based on git-blame:
Jack251970: 100%

Flow.Launcher.Infrastructure/UserSettings/Settings.cs

Activity based on git-commit:

Jack251970 onesounds
MAR 3 additions & 2 deletions 10 additions & 0 deletions
FEB 10 additions & 4 deletions
JAN 17 additions & 4 deletions
DEC 1 additions & 1 deletions
NOV
OCT

Knowledge based on git-blame:
onesounds: 25%
Jack251970: 7%

Flow.Launcher.Infrastructure/Win32Helper.cs

Activity based on git-commit:

Jack251970 onesounds
MAR 360 additions & 159 deletions
FEB 13 additions & 16 deletions 22 additions & 0 deletions
JAN 0 additions & 138 deletions
DEC 243 additions & 4 deletions
NOV
OCT

Knowledge based on git-blame:
Jack251970: 100%

Flow.Launcher/Languages/en.xaml

Activity based on git-commit:

Jack251970 onesounds
MAR 6 additions & 3 deletions 7 additions & 3 deletions
FEB 10 additions & 7 deletions
JAN 1 additions & 0 deletions
DEC
NOV
OCT

Knowledge based on git-blame:
onesounds: 44%
Jack251970: 2%

Flow.Launcher/PublicAPIInstance.cs

Activity based on git-commit:

Jack251970 onesounds
MAR 21 additions & 19 deletions
FEB 24 additions & 3 deletions
JAN 45 additions & 47 deletions
DEC 25 additions & 32 deletions
NOV 16 additions & 0 deletions
OCT

Knowledge based on git-blame:
Jack251970: 22%
onesounds: 1%

To learn more about /:\ gitStream - Visit our Docs

@Jack251970 Jack251970 added the enhancement New feature or request label Mar 6, 2025
@Jack251970 Jack251970 changed the title Fix copy to clipboard STA thread issue & Add retry for text copy Fix copy to clipboard STA thread issue & Add retry for copy Mar 9, 2025
@Jack251970 Jack251970 requested a review from jjw24 March 10, 2025 04:11

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/PublicAPIInstance.cs (1)

123-123: 🛠️ Refactor suggestion

Use Task instead of async void to better handle exceptions and caller awareness.

Returning a Task rather than using async void is a standard best practice. Doing so allows the caller to await (or track) the completion and capture any unhandled exceptions within calling code.

- public async void CopyToClipboard(string stringToCopy, bool directCopy = false, bool showDefaultNotification = true)
+ public async Task CopyToClipboard(string stringToCopy, bool directCopy = false, bool showDefaultNotification = true)
🧹 Nitpick comments (4)
Flow.Launcher.Infrastructure/Win32Helper.cs (1)

325-328: Add comprehensive documentation for STA thread methods.

The comment only indicates the source of the code but doesn't explain the purpose of STA threads, when to use them, or why OLE initialization is necessary.

Consider enhancing the documentation:

/*
- Found on https://github.com/files-community/Files
+ Found on https://github.com/files-community/Files
+ 
+ These methods execute actions on Single Threaded Apartment (STA) threads.
+ STA is required for certain Windows operations, particularly those involving
+ the clipboard, COM objects, or drag-and-drop functionality. OLE initialization
+ is necessary for these operations to work correctly in the STA context.
*/
Flow.Launcher/PublicAPIInstance.cs (3)

166-166: Fix typo in comment.

There's a typo in the comment: "shouold" should be "should".

-    // We shouold use SetText instead of SetDataObject to avoid the clipboard being locked by other applications
+    // We should use SetText instead of SetDataObject to avoid the clipboard being locked by other applications

187-206: Extract magic numbers to named constants and improve error reporting.

The retry count and delay are hardcoded as magic numbers. Additionally, the method returns only the exception without additional context.

Consider improving the implementation:

+private const int DefaultClipboardRetryCount = 6;
+private const int DefaultClipboardRetryDelayMs = 150;

-private static async Task<Exception> RetryActionOnSTAThreadAsync(Action action, int retryCount = 6, int retryDelay = 150)
+private static async Task<Exception> RetryActionOnSTAThreadAsync(
+    Action action, 
+    int retryCount = DefaultClipboardRetryCount, 
+    int retryDelay = DefaultClipboardRetryDelayMs)
{
    for (var i = 0; i < retryCount; i++)
    {
        try
        {
            await Win32Helper.StartSTATaskAsync(action);
            break;
        }
        catch (Exception e)
        {
            if (i == retryCount - 1)
            {
+               Log.Debug(nameof(PublicAPIInstance), $"Clipboard operation failed after {retryCount} attempts");
                return e;
            }
            await Task.Delay(retryDelay);
        }
    }
    return null;
}

123-185: Consider adding cancellation support to the clipboard operations.

The clipboard operations are now asynchronous but don't support cancellation, which could be useful for long-running operations or when the user navigates away.

Consider adding an optional CancellationToken parameter:

- public async void CopyToClipboard(string stringToCopy, bool directCopy = false, bool showDefaultNotification = true)
+ public async Task CopyToClipboard(string stringToCopy, bool directCopy = false, bool showDefaultNotification = true, CancellationToken cancellationToken = default)
{
    if (string.IsNullOrEmpty(stringToCopy))
    {
        return;
    }

    var isFile = File.Exists(stringToCopy);
    if (directCopy && (isFile || Directory.Exists(stringToCopy)))
    {
        // Sometimes the clipboard is locked and cannot be accessed,
        // we need to retry a few times before giving up
-       var exception = await RetryActionOnSTAThreadAsync(() =>
+       var exception = await RetryActionOnSTAThreadAsync(() =>
        {
            var paths = new StringCollection
            {
                stringToCopy
            };

            Clipboard.SetFileDropList(paths);
-       });
+       }, cancellationToken: cancellationToken);
        
        // Rest of the method...
    }
}

- private static async Task<Exception> RetryActionOnSTAThreadAsync(Action action, int retryCount = 6, int retryDelay = 150)
+ private static async Task<Exception> RetryActionOnSTAThreadAsync(Action action, int retryCount = 6, int retryDelay = 150, CancellationToken cancellationToken = default)
{
    for (var i = 0; i < retryCount; i++)
    {
+       cancellationToken.ThrowIfCancellationRequested();
        try
        {
            await Win32Helper.StartSTATaskAsync(action);
            break;
        }
        catch (Exception e)
        {
            if (i == retryCount - 1)
            {
                return e;
            }
-           await Task.Delay(retryDelay);
+           await Task.Delay(retryDelay, cancellationToken);
        }
    }
    return null;
}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between e5ad777 and 04f6d14.

📒 Files selected for processing (5)
  • Flow.Launcher.Infrastructure/NativeMethods.txt (1 hunks)
  • Flow.Launcher.Infrastructure/UserSettings/Settings.cs (1 hunks)
  • Flow.Launcher.Infrastructure/Win32Helper.cs (2 hunks)
  • Flow.Launcher/Languages/en.xaml (1 hunks)
  • Flow.Launcher/PublicAPIInstance.cs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • Flow.Launcher/Languages/en.xaml
  • Flow.Launcher.Infrastructure/UserSettings/Settings.cs
  • Flow.Launcher.Infrastructure/NativeMethods.txt
🧰 Additional context used
🧬 Code Definitions (1)
Flow.Launcher/PublicAPIInstance.cs (3)
Flow.Launcher.Core/Plugin/JsonRPCV2Models/JsonRPCPublicAPI.cs (1) (1)
  • CopyToClipboard (37-40)
Flow.Launcher.Infrastructure/Win32Helper.cs (3) (3)
  • Task (329-359)
  • Task (361-391)
  • Win32Helper (17-394)
Flow.Launcher.Core/Plugin/PluginManager.cs (4) (4)
  • Task (87-95)
  • Task (97-104)
  • Task (106-113)
  • Task (115-122)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: gitStream.cm

@@ -253,7 +253,7 @@ public SearchPrecisionScore QuerySearchPrecision
[JsonIgnore]
public ObservableCollection<BuiltinShortcutModel> BuiltinShortcuts { get; set; } = new()
{
new BuiltinShortcutModel("{clipboard}", "shortcut_clipboard_description", Clipboard.GetText),
new BuiltinShortcutModel("{clipboard}", "shortcut_clipboard_description", () => Win32Helper.StartSTATaskAsync(Clipboard.GetText).Result),
Copy link
Member

Choose a reason for hiding this comment

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

I think it's better to use GetAwaiter().GetResult().

Copy link
Member

Choose a reason for hiding this comment

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

Maybe async void is better? I am not sure.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think either is ok?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it's better to use GetAwaiter().GetResult().

This cannot work here, so I choose to keep as it was

Copy link
Member

@taooceros taooceros Mar 21, 2025

Choose a reason for hiding this comment

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

what do you mean by not work here? It is almost semantically equal to Task.Result, except that the exception is handled in a different way?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changing () => Win32Helper.StartSTATaskAsync(Clipboard.GetText).Result to Win32Helper.StartSTATaskAsync(Clipboard.GetText).GetAwaiter().GetResult cannot work, the result is always empty

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: 0

🧹 Nitpick comments (2)
Flow.Launcher/PublicAPIInstance.cs (2)

166-166: Fix typo in comment.

There's a typo in the comment.

-    // We shouold use SetText instead of SetDataObject to avoid the clipboard being locked by other applications
+    // We should use SetText instead of SetDataObject to avoid the clipboard being locked by other applications

187-206: Well-implemented retry pattern.

The RetryActionOnSTAThreadAsync method provides a robust implementation of the retry pattern. Consider adding a comment explaining the reasoning behind the default values for retryCount and retryDelay.

-private static async Task<Exception> RetryActionOnSTAThreadAsync(Action action, int retryCount = 6, int retryDelay = 150)
+/// <summary>
+/// Executes an action on an STA thread with retry capability.
+/// </summary>
+/// <param name="action">The action to execute.</param>
+/// <param name="retryCount">Number of retry attempts (default: 6).</param>
+/// <param name="retryDelay">Delay between retries in milliseconds (default: 150).</param>
+/// <returns>The exception if all retries fail, or null if successful.</returns>
+private static async Task<Exception> RetryActionOnSTAThreadAsync(Action action, int retryCount = 6, int retryDelay = 150)
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 04f6d14 and 17ecebf.

📒 Files selected for processing (2)
  • Flow.Launcher/Languages/en.xaml (1 hunks)
  • Flow.Launcher/PublicAPIInstance.cs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • Flow.Launcher/Languages/en.xaml
🔇 Additional comments (5)
Flow.Launcher/PublicAPIInstance.cs (5)

123-123: Change async void to async Task to handle exceptions properly.

Using async void can lead to unhandled exceptions that crash the application. It's a best practice to use async Task instead, which allows callers to await the operation and handle exceptions properly.

-public async void CopyToClipboard(string stringToCopy, bool directCopy = false, bool showDefaultNotification = true)
+public async Task CopyToClipboard(string stringToCopy, bool directCopy = false, bool showDefaultNotification = true)

125-128: LGTM! Good defensive programming.

Adding a null/empty check as an early return is a good practice that prevents unnecessary processing.


162-183: Good improvement for text copying with retry mechanism.

Using Clipboard.SetText instead of SetDataObject is a good choice to prevent clipboard locking issues. The retry logic with proper error handling and user feedback enhances reliability.


133-158:

❓ Verification inconclusive

Improved file/folder copy with retry mechanism.

The retry mechanism for clipboard operations is a good addition that addresses potential clipboard locking issues.

Don't forget to update interface definitions in other files to maintain consistency with the new async signature.


🏁 Script executed:

#!/bin/bash
# Check if the IPublicAPI interface has been updated to match the new async signature

echo "Checking if interfaces need updating for async method:"
rg "interface IPublicAPI" -A 20 --include "*.cs"

Length of output: 611


Interface Async Update Verification:

The new retry mechanism implementation for clipboard operations looks robust. However, the automatic verification of the async signature update in the IPublicAPI interface was inconclusive due to the search command error. Please manually verify that all interface definitions (e.g., IPublicAPI) have been updated to use the new async signature to ensure consistency across the codebase.

  • Action Required:
    • Manually check the interface definitions (in files where IPublicAPI is declared) to confirm they now include the updated async method signature.
    • Ensure that any related interface changes are propagated throughout the codebase.

193-193:

❓ Verification inconclusive

Ensure Win32Helper.StartSTATaskAsync is properly implemented.

The code relies on Win32Helper.StartSTATaskAsync, which should ensure clipboard operations run on an STA thread as required by the Windows Clipboard API.


🏁 Script executed:

#!/bin/bash
# Check the implementation of Win32Helper.StartSTATaskAsync

echo "Showing implementation of Win32Helper.StartSTATaskAsync:"
rg "StartSTATaskAsync" -A 15 --include "*.cs"

Length of output: 610


Action Required: Manually Verify STA Implementation in Win32Helper.StartSTATaskAsync

The call to Win32Helper.StartSTATaskAsync on line 193 of Flow.Launcher/PublicAPIInstance.cs is critical to ensure that clipboard operations execute on an STA thread, as required by the Windows Clipboard API. Our initial attempt to auto-locate its implementation failed due to an argument error with the search command. Please verify manually—or re-run an updated search script—to confirm that the method indeed wraps clipboard calls within an STA context.

  • Location to check: Flow.Launcher/PublicAPIInstance.cs at line 193.
  • Action: Confirm that Win32Helper.StartSTATaskAsync is implemented to marshal clipboard operations onto an STA thread.

If needed, you can use the following revised shell script to try searching for the method implementation:

#!/bin/bash
echo "Searching for Win32Helper.StartSTATaskAsync implementation using corrected command:"
rg "StartSTATaskAsync" -A 30 .

Jack251970 and others added 2 commits March 21, 2025 07:20
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

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 22
⚠️ ignored-expect-variant 1
⚠️ non-alpha-in-dictionary 19

See ❌ Event descriptions for more information.

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
Labels
10 min review bug Something isn't working enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

BUG: CopyToClipboard method throws an error for JSON-RPC v2 plugins
3 participants