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

👍 add plugin unload feature #385

Merged
merged 5 commits into from
Jul 7, 2024
Merged

👍 add plugin unload feature #385

merged 5 commits into from
Jul 7, 2024

Conversation

Milly
Copy link
Contributor

@Milly Milly commented Jul 5, 2024

Refs #349, vim-denops/deno-denops-core#8

Plugin API:

  • Entrypoint can now return AsyncDisposable.
    • It is called by denops#plugin#unload().
    • It is called when the server closing.
      • When denops#server#close() is called.
      • When denops#server#stop() is called.
      • When the channel is closed.
      • When the server process trapped SIGINT.

Vim API:

  • Add new denops-function:
    • denops#plugin#unload({plugin})
  • Add new events:
    • DenopsPluginUnloadPre:{plugin}
    • DenopsPluginUnloadPost:{plugin}
    • DenopsPluginUnloadFail:{plugin}

Additional

Added tests for script rewrite reload, note that this breaks deno test --watch.

Summary by CodeRabbit

  • New Features
    • Introduced plugin unloading functionality, enabling better plugin management.
    • Added events for pre and post plugin unloading, enhancing control over plugin lifecycle.
    • Introduced error handling events for plugin operations.
  • Bug Fixes
    • Improved handling of plugin loading and unloading errors.
  • Documentation
    • Updated documentation to reflect new plugin unloading and event handling features.
  • Tests
    • Added comprehensive tests for plugin unloading and error scenarios.

Plugin API:

- `Entrypoint` can now return `AsyncDisposable`.
  - It is called by `denops#plugin#unload()`.
  - It is called when the server closing.
    - When `denops#server#close()` is called.
    - When `denops#server#stop()` is called.
    - When the channel is closed.
    - When the server process trapped `SIGINT`.

Vim API:

- Add new `denops-function`:
  - `denops#plugin#unload({plugin})`
- Add new events:
  - `DenopsPluginUnloadPre:{plugin}`
  - `DenopsPluginUnloadPost:{plugin}`
  - `DenopsPluginUnloadFail:{plugin}`
Copy link

coderabbitai bot commented Jul 5, 2024

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

The changes introduce new functionality to unload Denops plugins, with appropriate events and error handling. The Service interface and various scripts now include methods and events to manage the plugin lifecycle more robustly. Updates were made to testing files and configurations to ensure this new functionality works correctly, providing a more comprehensive and error-resilient plugin management experience.

Changes

Files/Paths Change Summary
autoload/denops/_internal/plugin.vim Introduced functions for plugin unloading and state updates.
autoload/denops/plugin.vim Added public function denops#plugin#unload(name) for unloading plugins.
deno.jsonc Modified coverage script to exclude test files and added exclusion entry under the test section.
denops/@denops-private/host.ts Added unload(name: string): Promise<void> method to Service interface.
denops/.../host/nvim_test.ts, vim_test.ts Added unload function to Service interface in both Vim and Neovim test files.
denops/@denops-private/host_test.ts Added unload method to Service interface.
denops/@denops-private/plugin.ts Introduced Entrypoint type definition for plugin entrypoints.
denops/@denops-private/service.ts Enhanced Service class with new methods for plugin load and unload, and introduced PluginModule type.
denops/@denops-private/service_test.ts Added extensive test scenarios for plugin loading, unloading, and reloading.
doc/denops.txt Updated documentation for loading, unloading, and reloading plugins, with new event descriptions.
plugin/denops.vim Extended to include plugin unload events like DenopsPluginUnloadPre, DenopsPluginUnloadPost.
plugin/denops/debug.vim Added handlers for DenopsPluginFail and plugin unload events with debug messages.
tests/.../functions/plugin_test.ts Added new test cases for denops#plugin#unload() and extended reload scenarios.
tests/.../dummy_invalid_dispose_plugin.ts, dummy_valid_dispose_plugin.ts Added new test dummy plugins with valid and invalid dispose methods.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Vim
    participant Denops
    participant Plugin
    User->>Vim: Call denops#plugin#unload(name)
    Vim->>Denops: Invoke unload(name)
    Denops->>Plugin: Fire DenopsPluginUnloadPre
    Plugin-->>Denops: Acknowledge Pre-Unload
    Denops->>Plugin: Execute unload logic
    Plugin-->>Denops: Unload Success/Fail
    Denops->>Plugin: Fire DenopsPluginUnloadPost or DenopsPluginUnloadFail
    Plugin-->>Denops: Acknowledge Post-Unload or Handle Fail
    Denops->>Vim: Return Status
    Vim->>User: Unload Complete/Error
Loading

Poem

In the meadow of code, plugins do prepare,
Unloaded gracefully, handled with care.
Events now whisper, the lifecycle's tale,
With DeNops guiding, they will not fail.
A rabbit hops, proud of the feat,
With code as its meadow, life is complete. 🌸🛠️


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

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>.
    • 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 generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @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 as 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 resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

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

@Milly Milly marked this pull request as draft July 5, 2024 12:07
This breaks `--watch` option.
Copy link

codecov bot commented Jul 5, 2024

Codecov Report

Attention: Patch coverage is 97.77778% with 2 lines in your changes missing coverage. Please review.

Project coverage is 92.79%. Comparing base (880e30e) to head (a519c0f).

Files Patch % Lines
denops/@denops-private/host.ts 33.33% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           v7-pre     #385      +/-   ##
==========================================
+ Coverage   92.33%   92.79%   +0.46%     
==========================================
  Files          21       23       +2     
  Lines        1291     1361      +70     
  Branches      144      159      +15     
==========================================
+ Hits         1192     1263      +71     
+ Misses         96       95       -1     
  Partials        3        3              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@Milly Milly added the enhancement New feature or request label Jul 5, 2024
@Milly Milly requested review from lambdalisue and Shougo July 5, 2024 14:48
@Milly Milly marked this pull request as ready for review July 5, 2024 14:48
@Milly
Copy link
Contributor Author

Milly commented Jul 5, 2024

@coderabbitai review

Copy link

coderabbitai bot commented Jul 5, 2024

Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@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

Outside diff range and nitpick comments (4)
tests/denops/testdata/dummy_valid_dispose_plugin.ts (1)

1-3: Reminder: Update import statement.

The TODO comment indicates that the Entrypoint should be imported from denops-core once issue #349 is resolved.

// import type { Entrypoint } from "jsr:@denops/[email protected]";
+ // TODO: Update import statement once issue #349 is resolved.
tests/denops/testdata/dummy_invalid_dispose_plugin.ts (1)

1-3: Reminder: Update import statement.

The TODO comment indicates that the Entrypoint should be imported from denops-core once issue #349 is resolved.

// import type { Entrypoint } from "jsr:@denops/[email protected]";
+ // TODO: Update import statement once issue #349 is resolved.
denops/@denops-private/plugin.ts (1)

1-1: Address the TODO comment.

The TODO comment references a specific issue (#349). It would be helpful to provide more context or a link to the issue for better traceability.

-// TODO: #349 Update `Entrypoint` in denops-core, remove this module from `$.test.exclude` in `deno.jsonc`, and remove this module.
+// TODO: Update `Entrypoint` in denops-core (see issue #349), remove this module from `$.test.exclude` in `deno.jsonc`, and remove this module.
denops/@denops-private/service.ts (1)

1-2: Reminder: Import Entrypoint from denops-core.

The TODO comment indicates that the Entrypoint should be imported from denops-core in the future.

- // TODO: #349 Import `Entrypoint` from denops-core.
+ // TODO: #349 Import `Entrypoint` from denops-core.
Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 880e30e and 3759c61.

Files selected for processing (16)
  • autoload/denops/_internal/plugin.vim (3 hunks)
  • autoload/denops/plugin.vim (1 hunks)
  • deno.jsonc (1 hunks)
  • denops/@denops-private/host.ts (3 hunks)
  • denops/@denops-private/host/nvim_test.ts (1 hunks)
  • denops/@denops-private/host/vim_test.ts (1 hunks)
  • denops/@denops-private/host_test.ts (1 hunks)
  • denops/@denops-private/plugin.ts (1 hunks)
  • denops/@denops-private/service.ts (8 hunks)
  • denops/@denops-private/service_test.ts (10 hunks)
  • doc/denops.txt (2 hunks)
  • plugin/denops.vim (1 hunks)
  • plugin/denops/debug.vim (1 hunks)
  • tests/denops/runtime/functions/plugin_test.ts (6 hunks)
  • tests/denops/testdata/dummy_invalid_dispose_plugin.ts (1 hunks)
  • tests/denops/testdata/dummy_valid_dispose_plugin.ts (1 hunks)
Files skipped from review due to trivial changes (1)
  • plugin/denops.vim
Additional context used
Biome
denops/@denops-private/plugin.ts

[error] 35-35: void is confusing inside a union type.

Unsafe fix: Use undefined instead.

(lint/suspicious/noConfusingVoidType)

GitHub Check: codecov/patch
denops/@denops-private/host.ts

[warning] 77-77: denops/@denops-private/host.ts#L77
Added line #L77 was not covered by tests

denops/@denops-private/service.ts

[warning] 231-233: denops/@denops-private/service.ts#L231-L233
Added lines #L231 - L233 were not covered by tests

Additional comments not posted (44)
tests/denops/testdata/dummy_valid_dispose_plugin.ts (1)

5-10: LGTM!

The function main is correctly defined as an Entrypoint and includes an async dispose method that executes a Denops command.

tests/denops/testdata/dummy_invalid_dispose_plugin.ts (1)

5-10: LGTM!

The function main is correctly defined as an Entrypoint and includes an async dispose method that throws an error for testing purposes.

plugin/denops/debug.vim (1)

12-14: LGTM!

The new autocmds for DenopsPluginUnloadPre, DenopsPluginUnloadPost, and DenopsPluginUnloadFail events are correctly defined and follow the existing pattern.

deno.jsonc (2)

6-6: LGTM!

The new task for coverage with exclusions is correctly defined.


10-14: LGTM!

The new test exclusions are correctly defined and include a TODO comment for future updates.

denops/@denops-private/host.ts (2)

76-77: Ensure the invoke function handles the "unload" case correctly.

The invoke function has been updated to handle the "unload" case. Ensure that the arguments are correctly passed and handled.

Tools
GitHub Check: codecov/patch

[warning] 77-77: denops/@denops-private/host.ts#L77
Added line #L77 was not covered by tests


52-52: Ensure the unload method is implemented correctly.

The unload method in the Service interface should be reviewed to ensure it is correctly implemented in the corresponding class.

Verification successful

The unload method is implemented correctly.

The unload method with the signature async unload(name: string): Promise<void> is present in the Service class located in denops/@denops-private/service.ts. This confirms that the method is correctly implemented.

  • denops/@denops-private/service.ts: async unload(name: string): Promise<void>
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the implementation of the `unload` method in the `Service` class.

# Test: Search for the `unload` method implementation. Expect: Only occurances of the new method.
rg --type ts $'unload(name: string): Promise<void>'

Length of output: 52


Script:

#!/bin/bash
# Description: Locate the `Service` class and verify the implementation of the `unload` method within it.

# Step 1: Locate the `Service` class definition.
rg --type ts 'class Service'

# Step 2: Once the file containing the `Service` class is found, search for the `unload` method implementation within that file.
# Note: This command will be executed after identifying the file from the first command.
FILE_PATH=$(rg --type ts --files-with-matches 'class Service')
if [ -n "$FILE_PATH" ]; then
  rg --type ts 'unload(name: string): Promise<void>' $FILE_PATH
else
  echo "Service class not found."
fi

Length of output: 360


Script:

#!/bin/bash
# Description: Verify if the `unload` method is implemented with a different signature in the `Service` class.

# Search for any method named `unload` within the `denops/@denops-private/service.ts` file.
rg --type ts 'unload' denops/@denops-private/service.ts

Length of output: 437

denops/@denops-private/host_test.ts (1)

14-14: Ensure the test for the unload method is comprehensive.

The test for the unload method should cover all relevant scenarios, including valid and invalid arguments.

Verification successful

The unload method has comprehensive test coverage.

The search results indicate that the unload method is tested in various scenarios, including unloading a plugin, handling errors, and ensuring a plugin is not unloaded multiple times.

  • tests/denops/runtime/functions/plugin_test.ts
  • denops/@denops-private/service_test.ts
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the test coverage for the `unload` method.

# Test: Search for the `unload` method test cases. Expect: Only occurances of the new test cases.
rg --type ts $'t.step("calls \'unload\'",'

Length of output: 129


Script:

#!/bin/bash
# Description: Verify the test coverage for the `unload` method.

# Test: Search for the `unload` method test cases. Expect: Only occurrences of the new test cases.
rg --type ts 't.step("calls \'unload\'",'

Length of output: 93


Script:

#!/bin/bash
# Description: Verify the test coverage for the `unload` method.

# Test: Search for the `unload` method test cases. Expect: Only occurrences of the new test cases.
rg --type ts 't.step("calls '\''unload'\''",'

Length of output: 129


Script:

#!/bin/bash
# Description: Verify the test coverage for the `unload` method.

# Test: Search for the `unload` method occurrences in test files.
rg --type ts 'unload'

Length of output: 4310

denops/@denops-private/host/vim_test.ts (1)

21-21: Integration of unload method looks good.

The unload method has been correctly added to the service object.

autoload/denops/_internal/plugin.vim (6)

4-4: Addition of STATE_UNLOADING is appropriate.

The new state STATE_UNLOADING is consistent with the existing states.


31-37: Implementation of denops#_internal#plugin#unload looks good.

The function correctly changes the plugin state to unloading and notifies the server to invoke the unload action.


72-77: Implementation of s:DenopsSystemPluginUnloadPre looks good.

The function correctly identifies the plugin name, updates its state to unloading, and triggers the corresponding autocmd event.


79-85: Implementation of s:DenopsSystemPluginUnloadPost looks good.

The function correctly identifies the plugin name, resets its state to reserved, clears callbacks, and triggers the corresponding autocmd event.


87-93: Implementation of s:DenopsSystemPluginUnloadFail looks good.

The function correctly identifies the plugin name, updates its state to failed, clears callbacks, and triggers the corresponding autocmd event.


100-102: Autocmd events for plugin unloading are correctly added.

The new autocmd events for DenopsSystemPluginUnloadPre, DenopsSystemPluginUnloadPost, and DenopsSystemPluginUnloadFail are correctly defined and nested.

denops/@denops-private/host/nvim_test.ts (1)

26-26: Integration of unload method looks good.

The unload method has been correctly added to the service object.

denops/@denops-private/service.ts (9)

Line range hint 44-65:
Modification of load method looks good.

The load method has been updated to remove the suffix parameter and correctly handles plugin loading.


68-79: Implementation of #unload method looks good.

The private #unload method correctly handles the unloading of plugins and returns the plugin instance.


81-83: Implementation of unload method looks good.

The public unload method correctly invokes the private #unload method.


85-89: Implementation of reload method looks good.

The reload method correctly unloads and reloads the plugin.


149-159: Modification of close method looks good.

The close method correctly unloads all plugins and clears the internal state.


176-178: Addition of PluginModule type looks good.

The PluginModule type correctly defines the structure of a plugin module.


182-183: Addition of #loadedWaiter and #disposable looks good.

The new properties #loadedWaiter and #disposable correctly handle the plugin loading state and resource disposal.


Line range hint 199-224:
Modification of #load method looks good.

The #load method correctly handles plugin loading, including error handling and event emission.


258-266: Implementation of createScriptSuffix looks good.

The createScriptSuffix function correctly generates a suffix for script URLs to handle reloads.

doc/denops.txt (5)

412-419: Accurate and clear documentation of plugin loading events.

The documentation correctly outlines the sequence of events triggered during the loading of a plugin.


420-434: Accurate and clear documentation of the denops#plugin#unload function.

The documentation correctly describes the function's purpose, behavior, and the sequence of events triggered during plugin unloading.


437-442: Accurate and clear documentation of plugin reloading events.

The documentation correctly outlines the sequence of events triggered during the reloading of a plugin and references related functions.


509-526: Accurate and clear documentation of new plugin unloading events.

The documentation correctly describes the purpose and timing of the new DenopsPluginUnloadPre, DenopsPluginUnloadPost, and DenopsPluginUnloadFail events.


524-526: Accurate and clear documentation of the DenopsPluginUnloadFail event.

The documentation correctly describes the purpose and timing of the DenopsPluginUnloadFail event.

tests/denops/runtime/functions/plugin_test.ts (9)

17-18: Constants for valid and invalid dispose test scripts are correctly defined.

The constants scriptValidDispose and scriptInvalidDispose are correctly defined and will be used in the tests for plugin unloading.


150-184: Comprehensive tests for denops#plugin#unload function.

The tests cover scenarios where the plugin is successfully unloaded, including verifying that the appropriate events are fired and the dispose method is called.


186-223: Comprehensive tests for denops#plugin#unload function with dispose method failure.

The tests cover scenarios where the plugin's dispose method throws an error, including verifying that the appropriate events are fired and the error message is output.


225-248: Comprehensive tests for denops#plugin#unload function with non-existent plugin.

The tests cover scenarios where the plugin is not yet loaded, including verifying that no events are fired and no messages are output.


250-274: Comprehensive tests for denops#plugin#unload function with already unloaded plugin.

The tests cover scenarios where the plugin is already unloaded, including verifying that no events are fired and no messages are output.


Line range hint 295-336: Comprehensive tests for denops#plugin#reload function.

The tests cover scenarios where the plugin is successfully reloaded, including verifying that the appropriate events are fired and the entrypoint is called.


307-346: Comprehensive tests for denops#plugin#reload function with dispose method failure.

The tests cover scenarios where the plugin's dispose method throws an error during reload, including verifying that the appropriate events are fired and the error message is output.


357-371: Comprehensive tests for denops#plugin#reload function with non-existent plugin.

The tests cover scenarios where the plugin is not yet loaded, including verifying that no events are fired and no messages are output.


373-383: Comprehensive tests for denops#plugin#reload function with already unloaded plugin.

The tests cover scenarios where the plugin is already unloaded, including verifying that no events are fired and no messages are output.

denops/@denops-private/service_test.ts (5)

3-3: LGTM!

The added imports assertArrayIncludes and resolvesNext are appropriate for the new test cases.

Also applies to: 17-17


31-32: LGTM!

The new constants scriptValidDispose and scriptInvalidDispose are necessary for the new test cases.


309-353: LGTM!

The new test case for reloading a previously unloaded plugin is comprehensive and ensures correct event emissions.


356-527: LGTM!

The new test cases for the .unload() method cover a wide range of scenarios, ensuring robust handling of plugin unloading.


Line range hint 544-725:
LGTM!

The new test cases for the .reload() method are thorough and ensure that the service handles various reloading scenarios correctly.

denops/@denops-private/service.ts Outdated Show resolved Hide resolved
Comment on lines +33 to +35
export type Entrypoint = (
denops: Denops,
) => void | AsyncDisposable | Promise<void | AsyncDisposable>;
Copy link

Choose a reason for hiding this comment

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

Avoid using void in union types.

Using void in union types can be confusing. Replace void with undefined for clarity.

-export type Entrypoint = (
-  denops: Denops,
-) => void | AsyncDisposable | Promise<void | AsyncDisposable>;
+export type Entrypoint = (
+  denops: Denops,
+) => undefined | AsyncDisposable | Promise<undefined | AsyncDisposable>;
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export type Entrypoint = (
denops: Denops,
) => void | AsyncDisposable | Promise<void | AsyncDisposable>;
export type Entrypoint = (
denops: Denops,
) => undefined | AsyncDisposable | Promise<undefined | AsyncDisposable>;
Tools
Biome

[error] 35-35: void is confusing inside a union type.

Unsafe fix: Use undefined instead.

(lint/suspicious/noConfusingVoidType)

autoload/denops/plugin.vim Show resolved Hide resolved
@Milly
Copy link
Contributor Author

Milly commented Jul 5, 2024

When vim-denops/deno-denops-core#9 is merged, I would like to have it released as @denops/[email protected] and replace the import with it.

@Milly Milly mentioned this pull request Jul 6, 2024
4 tasks
Milly added 2 commits July 6, 2024 20:35
It is never resolved if it is called between `load()` and `unload()`.
denops/@denops-private/service.ts Outdated Show resolved Hide resolved
denops/@denops-private/service.ts Outdated Show resolved Hide resolved
Copy link
Member

@lambdalisue lambdalisue left a comment

Choose a reason for hiding this comment

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

LGTM

@lambdalisue lambdalisue merged commit 8adfe1f into v7-pre Jul 7, 2024
9 checks passed
@lambdalisue lambdalisue deleted the plugin-unload branch July 7, 2024 06:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants