Properly Create a Virtual Buffer

Now that the maze is displayed in a buffer, but it is not properly configured. For example, if a user executes the :edit command on the buffer, the maze will disappear. This is because Vim does not know how to reload the buffer content, and we must inform Vim about the content of the buffer when it is reloaded.

In this section, we will use the buffer module of denops_std to create a proper virtual buffer that concretizes the buffer content. Let's modify the main.ts file as follows:

import type { Entrypoint } from "https://deno.land/x/denops_std@v6.5.0/mod.ts";
import * as buffer from "https://deno.land/x/denops_std@v6.5.0/buffer/mod.ts";
import * as fn from "https://deno.land/x/denops_std@v6.5.0/function/mod.ts";
import { Maze } from "https://deno.land/x/maze_generator@v0.4.0/mod.js";

export const main: Entrypoint = (denops) => {
  denops.dispatcher = {
    async maze() {
      const { bufnr, winnr } = await buffer.open(denops, "maze://");

      const winWidth = await fn.winwidth(denops, winnr);
      const winHeight = await fn.winheight(denops, winnr);
      const maze = new Maze({
        xSize: winWidth / 3,
        ySize: winHeight / 3,
      }).generate();
      const content = maze.getString();

      await buffer.replace(denops, bufnr, content.split(/\r?\n/g));
      await buffer.concrete(denops, bufnr);
    },
  };
};

In this code, we use buffer.open to open a maze:// buffer and get the buffer number (bufnr) and the window number (winnr). Because Denops works asynchronously, the current buffer or window may be changed from what we expected. That's why developers should use buffer.open to open a buffer and save the buffer number and the window number for further operations.

Then, we call fn.winwidth and fn.winheight with the obtained window number to get the window size. Again, the current window might be changed, so we should use winnr to specify the window.

note

Vim may execute some events between RPC calls, so the current buffer or window really may be changed from what we expected. Denops plugin developers should be careful about this. The best practice for avoiding this problem is to avoid using current and always specify the buffer number or window number.

After that, we use buffer.replace to replace the content of the buffer. Actually, replacing the buffer content is a bit tricky. Developers should care about modifiable options to avoid unmodifiable errors, foldmethod options to keep foldings, and should remove the buffer content that is not replaced by setline or setbufline, etc. The buffer.replace function will care about all of those, so developers should avoid using setline or setbufline directly.

At the end, we call buffer.concrete to concretize the buffer content. This function defines BufReadCmd autocmd to restore the content when the buffer is reloaded. Without this, the buffer content will be discarded when the user executes the :edit command.

Restart Vim, rerun the :Maze command, and then you can see:

Try the :edit command on the buffer, and you can see the maze is still there.