profiq / docgen

IntelliJ plugin to generate Python documentation using OpenAI's GPT model
2 stars 4 forks source link

Fix the IDE freezing when an error is shown. #14

Closed msvana closed 1 year ago

msvana commented 1 year ago

I also noticed that the Cancel button didn't work because the OpenAI API request was synchronous. When the request was running it wasn't possible to to check if the user clicked the Cancel button. To fix this I made the request asynchronous.

petrvecera commented 1 year ago

Preferably we should not do a long task in the UI thread. https://plugins.jetbrains.com/docs/intellij/general-threading-rules.html

We should spawn a new thread and do a request in it. However I don't think it's worth investing our time right now. We can log this as an ticket for improvement 👍

FYI ChatGPT: When developing plugins for IntelliJ or any other JetBrains IDE, it's essential to ensure that long-running operations, especially IO-bound tasks like network requests, don't run on the Event Dispatch Thread (EDT). Running such tasks on the EDT would freeze the UI, leading to a poor user experience.

To avoid this, you can use IntelliJ's built-in concurrency utilities. Here are the steps to perform a network request without freezing the UI:

  1. Background Task: Use ProgressManager to run the task in the background.
ProgressManager.getInstance().run(new Task.Backgroundable(project, "Title of your task", false) {
    @Override
    public void run(@NotNull ProgressIndicator indicator) {
        // Your network request code goes here
    }
});
  1. Updating UI After Task Completion: If you want to update the UI after your background task completes, ensure you do so on the EDT using ApplicationManager.getApplication().invokeLater():
ProgressManager.getInstance().run(new Task.Backgroundable(project, "Title of your task", false) {
    @Override
    public void run(@NotNull ProgressIndicator indicator) {
        // Your network request code

        String result = ...; // Let's assume you got some result from the request

        ApplicationManager.getApplication().invokeLater(() -> {
            // Update UI with the result
        });
    }
});
  1. Show Progress: If you want to show the progress to the user, you can utilize the ProgressIndicator:
@Override
public void run(@NotNull ProgressIndicator indicator) {
    indicator.setIndeterminate(false);
    indicator.setText("Fetching data...");

    for (int i = 0; i <= 100; i++) {
        if (indicator.isCanceled()) {
            // Handle cancellation
            return;
        }

        // Simulate network task or some processing
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        indicator.setFraction(i / 100.0);
    }
}
  1. Handle Cancellations: It's also a good idea to periodically check if the task was cancelled by the user, using the ProgressIndicator.isCanceled() method, and handle it accordingly.

  2. Network Request Libraries: Remember to use a good networking library that supports cancellation, timeouts, etc. Libraries like OkHttp are great choices for this purpose.

By following these steps, you can ensure that your IntelliJ plugin performs network operations without blocking the UI, offering a responsive and user-friendly experience.

msvana commented 1 year ago

Well I am essentially doing the same thing. But instead of Task.Backgroundable I use Task.Modal so there is a progress bar in the middle of the screen. TaskBackgroundable would most likely just show a progress indicator in the status bar at the bottom (just like when WebStorm is indexing your project or something like that).

I was essentially interested in replacing the while loop with something else. But ChatGPT suggested a for loop instead. So basically the same solution.