Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
- [Creating a minimal Denops plugin](./tutorial/helloworld/creating-a-minimal-denops-plugin.md)
- [Adding Denops APIs](./tutorial/helloworld/adding-an-api.md)
- [Calling Vim features](./tutorial/helloworld/calling-vim-features.md)
- [Managing dependencies](./tutorial/helloworld/managing-dependencies.md)
- [Tutorial (Maze)](./tutorial/maze/README.md)
- [Utilizing third-party library](./tutorial/maze/utilizing-third-party-library.md)
- [Outputting content to buffer](./tutorial/maze/outputting-content-to-buffer.md)
Expand Down
8 changes: 7 additions & 1 deletion src/getting-started/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ $HOME
Next, write the following TypeScript code in `main.ts`:

```typescript,title=denops/denops-getting-started/main.ts
import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
import type { Entrypoint } from "jsr:@denops/std@^8.0.0";

export const main: Entrypoint = (denops) => {
denops.dispatcher = {
Expand All @@ -33,6 +33,12 @@ export const main: Entrypoint = (denops) => {
};
```

> [!NOTE]
>
> This example uses direct URL imports for simplicity. The recommended approach
> for managing dependencies is to use `deno.jsonc` with import maps, which
> you'll learn about in the [tutorials](../tutorial.md).

## Activate the Plugin

Add the following line to your Vim or Neovim configuration file (e.g.,
Expand Down
6 changes: 3 additions & 3 deletions src/getting-started/explanation.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ easily call.
In the Getting Started, we wrote the following code in the `main.ts` file:

```typescript
import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
import type { Entrypoint } from "jsr:@denops/std@^8.0.0";

export const main: Entrypoint = (denops) => {
denops.dispatcher = {
Expand All @@ -107,7 +107,7 @@ Let's break down this code step by step.
### About Imports

```typescript
import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
import type { Entrypoint } from "jsr:@denops/std@^8.0.0";
```

The first line imports the `Entrypoint` type from the [@denops/std] standard
Expand Down Expand Up @@ -215,7 +215,7 @@ For example, use
Vim's function instead of `denops.call` like:

```typescript
import * as fn from "jsr:@denops/std@^7.0.0/function";
import * as fn from "jsr:@denops/std@^8.0.0/function";

// Bad (result1 is `unknown`)
const result1 = await denops.call("expand", "%");
Expand Down
7 changes: 4 additions & 3 deletions src/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ features:
- **Unified codebase for Vim and Neovim**:<br>Denops provides a unified API for
both Vim and Neovim. You can write a plugin that functions on both Vim and
Neovim with a single codebase.
- **No worries about dependency management**:<br>Deno includes a built-in
dependency management system, allowing developers to write plugins with
third-party libraries without concerns about dependency management.
- **Modern dependency management**:<br>Deno's built-in dependency system with
import maps provides clean, maintainable dependency management. The workspace
configuration ensures each plugin's dependencies are isolated, preventing
conflicts when multiple Denops plugins are installed together.
- **Simple and efficient code**:<br>Deno utilizes the V8 engine, significantly
faster than Vim script. You can write a plugin with straightforward code,
without the need for complex optimizations solely for performance.
Expand Down
2 changes: 1 addition & 1 deletion src/tutorial/helloworld/adding-an-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Open `denops/denops-helloworld/main.ts` and rewrite the content with the
following code:

```typescript,title=denops/denops-helloworld/main.ts
import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
import type { Entrypoint } from "jsr:@denops/std@^8.0.0";
import { assert, is } from "jsr:@core/unknownutil@^4.3.0";

export const main: Entrypoint = (denops) => {
Expand Down
9 changes: 6 additions & 3 deletions src/tutorial/helloworld/calling-vim-features.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ the `denops` instance passed to the plugin's `main` function. You can rewrite
`main.ts` as follows to register the `DenopsHello` as a Vim command:

```typescript,title=denops/denops-helloworld/main.ts
import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
import type { Entrypoint } from "jsr:@denops/std@^8.0.0";
import { assert, is } from "jsr:@core/unknownutil@^4.3.0";

export const main: Entrypoint = (denops) => {
Expand Down Expand Up @@ -57,8 +57,11 @@ as a result.

## Next Steps

In the next step, follow the tutorial to learn how to develop a real Denops
plugin.
Learn about managing dependencies with import maps for cleaner code:

- [Managing dependencies](./managing-dependencies.md)

Or jump to the maze tutorial to learn more advanced concepts:

- [Tutorial (Maze)](../../tutorial/maze/index.html)
- [API reference](https://jsr.io/@denops/std)
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ denops-helloworld
Here is the content of the `denops/denops-helloworld/main.ts` file:

```typescript,title=denops/denops-helloworld/main.ts
import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
import type { Entrypoint } from "jsr:@denops/std@^8.0.0";

export const main: Entrypoint = (denops) => {
console.log("Hello, Denops from TypeScript!");
Expand Down
120 changes: 120 additions & 0 deletions src/tutorial/helloworld/managing-dependencies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Managing Dependencies with Import Maps

In the previous examples, we used direct URL imports like
`jsr:@denops/std@^8.0.0`. While this works, the recommended approach for Denops
plugins (v8.0.0+) is to use import maps with `deno.jsonc` for cleaner and more
maintainable dependency management.

## Why Use Import Maps?

The main reason to use import maps is to avoid conflicts between multiple Denops
plugins. Each Denops plugin must have a unique directory name under `denops/`,
but root-level configuration files could potentially conflict:

```
# Multiple plugins installed:
~/.vim/pack/plugins/start/plugin-a/
├── deno.jsonc # Could conflict
└── denops/plugin-a/ # Always unique

~/.vim/pack/plugins/start/plugin-b/
├── deno.jsonc # Could conflict
└── denops/plugin-b/ # Always unique
```

Some plugin managers have a "merge" feature that combines plugin directories,
but even without merging, placing configuration files in plugin-specific
directories (`denops/plugin-name/`) ensures no conflicts can occur regardless of
how plugins are installed or managed.

## Setting Up Your Plugin Structure

Update your `denops-helloworld` structure to include configuration files:

```
denops-helloworld/
├── deno.jsonc # Development configuration
├── denops/
│ └── denops-helloworld/
│ ├── deno.jsonc # Runtime dependencies
│ └── main.ts
└── plugin/
└── denops-helloworld.vim
```

### Root deno.jsonc (Development)

Create a `deno.jsonc` in your repository root for workspace configuration:

```json
{
"workspace": [
"./denops/denops-helloworld"
]
}
```

This enables Deno commands like `deno fmt`, `deno lint`, and `deno test` to work
from your project root and discover your plugin's configuration.

### Plugin deno.jsonc (Runtime)

Create `denops/denops-helloworld/deno.jsonc` for runtime dependencies:

```json
{
"imports": {
"@denops/std": "jsr:@denops/std@^8.0.0",
"@core/unknownutil": "jsr:@core/unknownutil@^4.3.0"
}
}
```

## Updating Your Code

With import maps configured, update your imports from:

```typescript
import type { Entrypoint } from "jsr:@denops/std@^8.0.0";
import { assert, is } from "jsr:@core/unknownutil@^4.3.0";
```

To cleaner versions:

```typescript
import type { Entrypoint } from "@denops/std";
import { assert, is } from "@core/unknownutil";
```

## Alternative: import_map.json

Denops also supports `import_map.json(c)` files, but they require more verbose
configuration due to the
[Import Maps Standard](https://github.com/WICG/import-maps):

```json
// denops/denops-helloworld/import_map.json
{
"imports": {
"@denops/std": "jsr:@denops/std@^8.0.0",
"@denops/std/": "jsr:/@denops/std@^8.0.0/" // Required for submodules
}
}
```

We recommend using `deno.jsonc` as it's less verbose and integrates better with
Deno tooling. For more details about the differences, see the
[Deno documentation](https://docs.deno.com/runtime/fundamentals/modules/#differentiating-between-imports-or-importmap-in-deno.json-and---import-map-option).

> [!IMPORTANT]
>
> Import map features require Denops v8.0.0 or later. For older versions,
> continue using direct URL imports.

## Benefits

1. **Cleaner imports**: No more long URLs in your code
2. **Version management**: Update dependencies in one place
3. **Better IDE support**: Auto-completion and type checking work seamlessly
4. **No conflicts**: Each plugin manages its own dependencies
5. **Development tools**: Format and lint your code from the project root
8 changes: 4 additions & 4 deletions src/tutorial/maze/adjusting-maze-size-to-fit-the-window.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ to have a maze that fits the current window size.
Let's modify the plugin to ensure the generated maze fits the current window
size.

```typescript,title=denops/denops-helloworld/main.ts
import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
import * as fn from "jsr:@denops/std@^7.0.0/function";
import { Maze } from "npm:@thewizardbear/maze_generator@^0.4.0";
```typescript,title=denops/denops-maze/main.ts
import type { Entrypoint } from "@denops/std";
import * as fn from "@denops/std/function";
import { Maze } from "maze_generator";

export const main: Entrypoint = (denops) => {
denops.dispatcher = {
Expand Down
27 changes: 20 additions & 7 deletions src/tutorial/maze/creating-applicative-plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,30 @@ augroup denops_maze
augroup END
```

Then, modify the `main.ts` file to accept the optional argument for a custom
Then, update your `denops/denops-maze/deno.jsonc` to include the unknownutil
dependency:

```json,title=denops/denops-maze/deno.jsonc
{
"imports": {
"@denops/std": "jsr:@denops/std@^8.0.0",
"@core/unknownutil": "jsr:@core/unknownutil@^4.3.0",
"maze_generator": "npm:@thewizardbear/maze_generator@^0.4.0"
}
}
```

Now modify the `main.ts` file to accept the optional argument for a custom
opener, generate a maze that fits the current window size, configure the buffer
options to make it non-file readonly buffer, etc.

```typescript,title=denops/denops-maze/main.ts
import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
import { batch, collect } from "jsr:@denops/std@^7.0.0/batch";
import * as fn from "jsr:@denops/std@^7.0.0/function";
import * as op from "jsr:@denops/std@^7.0.0/option";
import { Maze } from "npm:@thewizardbear/maze_generator@^0.4.0";
import { assert, is } from "jsr:@core/unknownutil@^4.3.0";
import type { Entrypoint } from "@denops/std";
import { batch, collect } from "@denops/std/batch";
import * as fn from "@denops/std/function";
import * as op from "@denops/std/option";
import { Maze } from "maze_generator";
import { assert, is } from "@core/unknownutil";

export const main: Entrypoint = (denops) => {
denops.dispatcher = {
Expand Down
4 changes: 2 additions & 2 deletions src/tutorial/maze/outputting-content-to-buffer.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ the maze to a buffer so that users can yank the maze with daily Vim operations!
Let's modify the code to make the generated maze output to a buffer.

```typescript,title=denops/denops-maze/main.ts
import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
import { Maze } from "npm:@thewizardbear/maze_generator@^0.4.0";
import type { Entrypoint } from "@denops/std";
import { Maze } from "maze_generator";

export const main: Entrypoint = (denops) => {
denops.dispatcher = {
Expand Down
10 changes: 5 additions & 5 deletions src/tutorial/maze/properly-configured-the-buffer.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ buffer after closure. Open the `main.ts` file and modify the `maze` method as
follows:

```typescript,title=denops/denops-maze/main.ts
import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
import * as buffer from "jsr:@denops/std@^7.0.0/buffer";
import * as fn from "jsr:@denops/std@^7.0.0/function";
import * as op from "jsr:@denops/std@^7.0.0/option";
import { Maze } from "npm:@thewizardbear/maze_generator@^0.4.0";
import type { Entrypoint } from "@denops/std";
import * as buffer from "@denops/std/buffer";
import * as fn from "@denops/std/function";
import * as op from "@denops/std/option";
import { Maze } from "maze_generator";

export const main: Entrypoint = (denops) => {
denops.dispatcher = {
Expand Down
8 changes: 4 additions & 4 deletions src/tutorial/maze/properly-create-a-virtual-buffer.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ proper virtual buffer that concretizes the buffer content. Let's modify the
`main.ts` file as follows:

```typescript,title=denops/denops-maze/main.ts
import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
import * as buffer from "jsr:@denops/std@^7.0.0/buffer";
import * as fn from "jsr:@denops/std@^7.0.0/function";
import { Maze } from "npm:@thewizardbear/maze_generator@^0.4.0";
import type { Entrypoint } from "@denops/std";
import * as buffer from "@denops/std/buffer";
import * as fn from "@denops/std/function";
import { Maze } from "maze_generator";

export const main: Entrypoint = (denops) => {
denops.dispatcher = {
Expand Down
12 changes: 6 additions & 6 deletions src/tutorial/maze/reduce-the-number-of-rpc-calls.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ enhance performance by reducing the number of RPC calls using the `batch` module
from `@denops/std`. Let's revise the `main.ts` file as follows:

```typescript,title=denops/denops-maze/main.ts
import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
import { batch, collect } from "jsr:@denops/std@^7.0.0/batch";
import * as buffer from "jsr:@denops/std@^7.0.0/buffer";
import * as fn from "jsr:@denops/std@^7.0.0/function";
import * as op from "jsr:@denops/std@^7.0.0/option";
import { Maze } from "npm:@thewizardbear/maze_generator@^0.4.0";
import type { Entrypoint } from "@denops/std";
import { batch, collect } from "@denops/std/batch";
import * as buffer from "@denops/std/buffer";
import * as fn from "@denops/std/function";
import * as op from "@denops/std/option";
import { Maze } from "maze_generator";

export const main: Entrypoint = (denops) => {
denops.dispatcher = {
Expand Down
27 changes: 25 additions & 2 deletions src/tutorial/maze/utilizing-third-party-library.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,41 @@ directory tree will look like this:

```
~/denops-maze
├── deno.jsonc
├── denops
│ └── denops-maze
│ ├── deno.jsonc
│ └── main.ts
└── plugin
└── denops-maze.vim
```

First, create the root `deno.jsonc` file for workspace configuration:

```json,title=deno.jsonc
{
"workspace": [
"./denops/denops-maze"
]
}
```

Then, create the `denops/denops-maze/deno.jsonc` file for runtime dependencies:

```json,title=denops/denops-maze/deno.jsonc
{
"imports": {
"@denops/std": "jsr:@denops/std@^8.0.0",
"maze_generator": "npm:@thewizardbear/maze_generator@^0.4.0"
}
}
```

The content of the `denops/denops-maze/main.ts` file will be:

```typescript,title=denops/denops-maze/main.ts
import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
import { Maze } from "npm:@thewizardbear/maze_generator@^0.4.0";
import type { Entrypoint } from "@denops/std";
import { Maze } from "maze_generator";

export const main: Entrypoint = (denops) => {
denops.dispatcher = {
Expand Down