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 getbufinfo() helper function #279

Merged
merged 1 commit into from
Feb 21, 2025

Conversation

mityu
Copy link
Contributor

@mityu mityu commented Dec 24, 2024

getbufnr() function have dictionaries of buffer local variables in its return value. Therefore, when there's a funcref in buffer local variables, denops will fail to send the return value back to the deno world.
This behavior is inconvenient, this PR makes denops-std's getbufnr() omit the "variables" entries from the return value.

Reproduce Steps

  • Prepare this /tmp/repro/denops/repro/main.ts
import type { Entrypoint } from "jsr:@denops/[email protected]";
import { getbufinfo } from "jsr:@denops/std@~7.4.0/function";

export const main: Entrypoint = (denops) => {
  denops.dispatcher = {
    async invoke() {
      await denops.cmd("let b:repro = {-> 0}");
      await getbufinfo(denops);
    },
  };
};
  • Prepare this vimrc.vim
set nocompatible

set runtimepath^=/tmp/repro
set runtimepath^=~/.cache/vim/pack/minpac/opt/denops.vim  " Please change this path

command! Repro call denops#notify('repro', 'invoke', [])
  • Launch vim with vim -u vimrc.vim
  • Run command :Repro
  • Get this error
[denops] Error: Failed to call 'invoke' API in 'repro': Error: Vim just returns "ERROR" for 'denops#api#vim#call()'. Check if 'denops.vim' exist in 'runtimepath' properly
[denops]     at Vim.call (file:///Users/mityu/.cache/vim/pack/minpac/opt/denops.vim/denops/@denops-private/host/vim.ts:55:13)
[denops]     at eventLoopTick (ext:core/01_core.js:175:7)
[denops]     at async getbufinfo (https://jsr.io/@denops/std/7.4.0/function/buffer.ts:453:20)
[denops]     at async Object.invoke (file:///tmp/repro/denops/repro/main.ts:12:7)
[denops]     at async Plugin.call (file:///Users/mityu/.cache/vim/pack/minpac/opt/denops.vim/denops/@denops-private/service.ts:276:14)
[denops]     at async Service.#dispatch (file:///Users/mityu/.cache/vim/pack/minpac/opt/denops.vim/denops/@denops-private/service.ts:117:12)
[denops]     at async Service.dispatch (file:///Users/mityu/.cache/vim/pack/minpac/opt/denops.vim/denops/@denops-private/service.ts:123:14)
[denops]     at async Vim.#dispatch (file:///Users/mityu/.cache/vim/pack/minpac/opt/denops.vim/denops/@denops-private/host/vim.ts:120:14)
[denops]     at Plugin.call (file:///Users/mityu/.cache/vim/pack/minpac/opt/denops.vim/denops/@denops-private/service.ts:281:13)
[denops]     at eventLoopTick (ext:core/01_core.js:175:7)
[denops]     at async Service.#dispatch (file:///Users/mityu/.cache/vim/pack/minpac/opt/denops.vim/denops/@denops-private/service.ts:117:12)
[denops]     at async Service.dispatch (file:///Users/mityu/.cache/vim/pack/minpac/opt/denops.vim/denops/@denops-private/service.ts:123:14)
[denops]     at async Vim.#dispatch (file:///Users/mityu/.cache/vim/pack/minpac/opt/denops.vim/denops/@denops-private/host/vim.ts:120:14)

Environment

  • macOS Sequoia 15.2 (Apple Silicon)
  • Deno
deno 2.1.4 (stable, release, aarch64-apple-darwin)
v8 13.0.245.12-rusty
typescript 5.6.2
  • Vim: 9.1.954

Summary by CodeRabbit

  • New Features

    • Introduced a new function to retrieve buffer information with various input options.
    • Expanded module exports to include new functionality.
  • Bug Fixes

    • Implemented filtering to exclude unwanted buffer-local variables in the output.
  • Tests

    • Added a test suite to validate the functionality and correctness of the new buffer information retrieval function.

Copy link

coderabbitai bot commented Dec 24, 2024

Warning

Rate limit exceeded

@mityu has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 19 minutes and 38 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 57ead86 and c105415.

📒 Files selected for processing (4)
  • deno.jsonc (1 hunks)
  • helper/getbufinfo.ts (1 hunks)
  • helper/getbufinfo_test.ts (1 hunks)
  • helper/mod.ts (1 hunks)

Walkthrough

The pull request introduces a new getbufinfo function in the Denops helper module, designed to retrieve buffer information asynchronously. The function is implemented with overloaded signatures to accept either a buffer name or a dictionary argument. It uses denops.eval to fetch buffer details, filters out variable properties, and converts specific properties to boolean values. Accompanying the implementation is a comprehensive test suite that validates the function's behavior across different buffer scenarios.

Changes

File Change Summary
helper/getbufinfo.ts Added new overloaded getbufinfo function with type-safe implementations for retrieving buffer information.
helper/getbufinfo_test.ts Created test suite to validate getbufinfo function behavior, including buffer creation, manipulation, and variable filtering.
helper/mod.ts Added export statement to include getbufinfo module exports.

Suggested reviewers

  • lambdalisue

Poem

🐰 Buffers dancing, info so bright,
A rabbit's code takes playful flight!
Filtering variables with glee,
Denops magic, can't you see?
Buffer secrets now unfurled! 🔍


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>, 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. (Beta)
  • @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

codecov bot commented Dec 24, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 85.80%. Comparing base (c3719e6) to head (c105415).
Report is 2 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #279      +/-   ##
==========================================
+ Coverage   85.73%   85.80%   +0.06%     
==========================================
  Files          64       65       +1     
  Lines        3442     3458      +16     
  Branches      301      301              
==========================================
+ Hits         2951     2967      +16     
  Misses        489      489              
  Partials        2        2              

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

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

🧹 Nitpick comments (1)
function/buffer.ts (1)

417-419: Review the in-code docs referencing the builtin function names.

Here, the documentation states:

“CAUTION: Different from the builtin getbufnr() function...”

However, the surrounding context is about getbufinfo(). It's potentially confusing for future maintainers to see getbufnr() referenced here. Confirm whether you intended to reference the builtin getbufinfo() function instead of getbufnr(), then adjust the documentation accordingly for clarity.

-CAUTION: Different from the builtin getbufnr() function...
+CAUTION: Different from the builtin getbufinfo() function...

Also applies to: 443-446

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between c3719e6 and f2995f7.

📒 Files selected for processing (2)
  • function/buffer.ts (3 hunks)
  • function/buffer_test.ts (2 hunks)
🔇 Additional comments (3)
function/buffer_test.ts (2)

64-65: Good test coverage addition.

This test sequence (await denops.cmd("1,$bwipeout!");) ensures that previously created buffers are removed before verifying the new filtering behavior. No issues found here.


66-75: Test logic aligns well with the new filtering requirement.

The test successfully verifies that the getbufinfo() function excludes the "variables" key by asserting the key's absence in the returned object. This addresses the PR’s objective of preventing serialization problems caused by buffer-local variables. Good use of assertFalse.

function/buffer.ts (1)

460-465: Filtering out the variables property is implemented correctly.

The usage of denops.eval along with the map and filter logic accurately omits variables from the returned buffer info. This resolves the issue of funcrefs in buffer-local variables causing JSON serialization errors. No further changes needed.

@mityu
Copy link
Contributor Author

mityu commented Dec 24, 2024

Hmm..., test fails due to the changes to the doc...

@lambdalisue
Copy link
Member

lambdalisue commented Dec 25, 2024

@mityu Could you move the implementation into helper/getbufinfo.ts so that we can avoid jsdoc mis-matched issue and we can keep backward compatibility?

@mityu
Copy link
Contributor Author

mityu commented Dec 25, 2024

I'm sleepy today. I'll do remaining work tomorrow.

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

🧹 Nitpick comments (2)
helper/getbufinfo.ts (2)

5-7: Add JSDoc comments for clarity.

The TODO: write placeholder can be updated with a concise description explaining what the getbufinfo function does, its parameters, and return types. This makes the code more maintainable and user-friendly.

 /**
- * TODO: write
+ * Retrieve information about the specified buffer(s) in a Denops environment.
+ * If a buffer is specified by name or index, returns information for that buffer.
+ * If called with no arguments or dictionary arguments, returns information for all buffers.
  */

17-36: Validate potential null or undefined arguments.

Although args is typed unknown[], in practice it should align with the overload signatures. You may consider an early check to avoid unexpected runtime errors if the call pattern changes.

 export async function getbufinfo(
   denops: Denops,
   ...args: unknown[]
 ): Promise<BufInfo[]> {
+  // Example safeguard if usage might vary in the future
+  if (!args) {
+    return [];
+  }
   const bufinfos = await denops.eval(
     "map(call('getbufinfo', l:args), {_, v -> filter(v, {k -> k !=# 'variables'})})",
     {
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between f2995f7 and 0100ab6.

📒 Files selected for processing (3)
  • helper/getbufinfo.ts (1 hunks)
  • helper/getbufinfo_test.ts (1 hunks)
  • helper/mod.ts (1 hunks)
🔇 Additional comments (6)
helper/mod.ts (1)

12-12: Exporting new module is good to have!

This export line cleanly exposes the newly created getbufinfo.ts module to external consumers. This is consistent with the approach used for other helper modules and doesn't appear to break any existing interfaces.

helper/getbufinfo.ts (2)

1-3: Imports are correct and cohesive.

All imported types correlate well with the usage in the file. This ensures type safety for Denops, BufInfo, and the dictionary arguments.


8-16: Method overloading is consistent with typical usage patterns.

The overload definitions for different argument types are a great approach to provide flexible call signatures. However, ensure to maintain consistent naming or comments for each overload signature, so developers understand how they differ.

helper/getbufinfo_test.ts (3)

1-10: Solid test structure and usage of @denops/test.

The test scaffolding is well set up to confirm getbufinfo behavior in both normal and multi-buffer contexts.


11-60: Good coverage of various buffer states.

By creating multiple buffers, modifying lines, and toggling visibility and loading states, you’re effectively testing a variety of scenarios. This ensures getbufinfo reliably returns the correct boolean flags (changed, hidden, listed, loaded).


65-75: Buffer-local variable filtering works well.

The test confirms that variables key is removed as intended. The assertion assertFalse("variables" in actual[0]) is an effective check, preventing future regressions if the logic changes.

@mityu mityu changed the title 💥 Remove "variables" entry from dict getbufnr() returns 👍 Add getbufinfo() helper function Feb 19, 2025
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: 1

🧹 Nitpick comments (3)
helper/getbufinfo.ts (3)

5-23: Consider enhancing the example code.

While the documentation is clear and well-written, the example could be more comprehensive by:

  1. Showing both overload usages (with buf and dict arguments)
  2. Including error handling

Here's a suggested enhancement:

import type { Entrypoint } from "jsr:@denops/std";
import { getbufinfo } from "jsr:@denops/std/helper/getbufinfo";

export const main: Entrypoint = async (denops) => {
  try {
    // Using buffer number
    const currentBufInfo = await getbufinfo(denops, await denops.call("bufnr") as number);
    console.log("Current buffer info:", currentBufInfo);

    // Using dict argument
    const allBufInfo = await getbufinfo(denops, { buflisted: 1 });
    console.log("All listed buffers:", allBufInfo);
  } catch (error) {
    console.error("Failed to get buffer info:", error);
  }
};

32-44: Consider using a more explicit type assertion.

The type assertion could be simplified by directly asserting the expected type:

-  ) as Record<
-    keyof BufInfo,
-    unknown
-  >[];
+  ) as Partial<BufInfo>[];

45-52: Consider using explicit boolean conversion.

While double negation (!!) is a common pattern, consider using Boolean() for more explicit type conversion:

   return bufinfos.map((bufinfo) => ({
     ...bufinfo,
-    changed: !!bufinfo.changed,
-    hidden: !!bufinfo.hidden,
-    listed: !!bufinfo.listed,
-    loaded: !!bufinfo.loaded,
+    changed: Boolean(bufinfo.changed),
+    hidden: Boolean(bufinfo.hidden),
+    listed: Boolean(bufinfo.listed),
+    loaded: Boolean(bufinfo.loaded),
   } as unknown as BufInfo));
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 0100ab6 and 57ead86.

📒 Files selected for processing (3)
  • helper/getbufinfo.ts (1 hunks)
  • helper/getbufinfo_test.ts (1 hunks)
  • helper/mod.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • helper/mod.ts
  • helper/getbufinfo_test.ts
🧰 Additional context used
🪛 GitHub Actions: Test
helper/getbufinfo.ts

[error] 2-2: Unknown export './helper/getbufinfo' for '@denops/std'.

🔇 Additional comments (2)
helper/getbufinfo.ts (2)

1-3: LGTM! Imports are well-organized.

The type imports are properly structured and include all necessary dependencies.

🧰 Tools
🪛 GitHub Actions: Test

[error] 2-2: Unknown export './helper/getbufinfo' for '@denops/std'.


24-31: LGTM! Function overloads are well-defined.

The overload signatures clearly define the supported argument types and return type.

@mityu mityu force-pushed the fix-getbufinfo branch 2 times, most recently from 5aa568f to dd66c7b Compare February 19, 2025 13:45
@mityu
Copy link
Contributor Author

mityu commented Feb 19, 2025

I'm really sorry for the super late. I've updated the patch. Could you review again? @lambdalisue

When a funcref appears in buffer-local variables, calling getbufinfo()
from denops world will fail due to the error on serializing its return
value using json_encode().
To avoid this, we add a wrapper function of getbufinfo() to filter-out
buffer-local variables from its return value.
@mityu
Copy link
Contributor Author

mityu commented Feb 19, 2025

(Dropped the first commit and the next reverting commit.)

@lambdalisue lambdalisue merged commit 5f8e7f4 into vim-denops:main Feb 21, 2025
10 checks passed
@mityu mityu deleted the fix-getbufinfo branch February 21, 2025 12:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants