Open-source project
chrisgrieser/nvim-spider avatar
chrisgrieser/nvim-spider

nvim-spider: subword motions that skip punctuation in Neovim

Use the w, e, b motions like a spider. Move by subwords and skip insignificant punctuation.

904 stars18 forksLuaMIT

At a glance

What is it?
nvim-spider replaces the w, e, b and ge motions in Neovim with ones that stop inside camelCase and snake_case names and glide over insignificant punctuation. It creates no keybindings by default, it ignores vim's iskeyword option, and it depends on an optional luarocks rock for UTF-8 support.
Who is it for?
nvim-spider suits a Neovim user who navigates source code and wants a word motion that understands the shape of an identifier rather than treating it as one blob, and who is willing to swap the built-in motions for plugin ones. It does not suit someone who wants vim's keyword rules to keep working, since the plugin ignores iskeyword, and it does not suit a configuration that cannot tolerate an extra Lua dependency for the motion layer.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 81 days ago.
What is it written in?
Mainly Lua, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The motion stops inside a camelCase name

The core change is what counts as a word. nvim-spider's motions are based on subwords, so they stop at the segments of a camelCase, SNAKE_CASE or kebab-case variable rather than at the whole identifier. The documentation shows the two behaviours side by side on the same line, with vim's w landing on the variable name as one stop and on each separated token, while spider's w lands on each segment. In a long line of code, that difference is the difference between a handful of stops and a lot of them. The other half of the change is punctuation handling. A sequence of one or more punctuation characters counts as significant if it is surrounded by whitespace and contains no non-punctuation characters, so the double equals in a comparison is a stop, while the colons and parentheses in a method call are not. The documentation counts the stops on one example line, 21 for vim and 14 for spider.

Installation is a plugin declaration, not a keybinding

The plugin is a Lua plugin for Neovim, and there is nothing to build. The three supported managers each get a one line declaration, and the README shows all three in a single block:

lua
-- packer
use { "chrisgrieser/nvim-spider" }

-- lazy.nvim
{ "chrisgrieser/nvim-spider", lazy = true },

-- vim-plug
Plug("chrisgrieser/nvim-spider")

The detail that catches people out is stated plainly right after: no keybindings are created by default. The plugin ships motions, not a mapping, so installing it changes nothing about how you edit until you replace the four motions yourself. The README then gives the replacement mappings, and the choice between them matters, because one form is lazy-loadable and the other is not:

lua
vim.keymap.set({ "n", "o", "x" }, "w", "<cmd>lua require('spider').motion('w')<CR>")
vim.keymap.set({ "n", "o", "x" }, "e", "<cmd>lua require('spider').motion('e')<CR>")
vim.keymap.set({ "n", "o", "x" }, "b", "<cmd>lua require('spider').motion('b')<CR>")
vim.keymap.set({ "n", "o", "x" }, "ge", "<cmd>lua require('spider').motion('ge')<CR>")

The modes covered are normal, operator-pending and visual, which is what makes the motions usable with operators and selections. A note in the documentation adds a constraint you should not skip: dot-repeat only works if the motions are called as Ex commands, so the alternative form where the third argument is a function will not repeat with the dot key.

setup is optional and motion options win over it

There are two ways to configure the plugin and the precedence between them is explicit. The global configuration goes in a setup call, which is documented as optional, and the defaults are these:

lua
-- default values
require("spider").setup {
	skipInsignificantPunctuation = true,
	subwordMovement = true,
	consistentOperatorPending = false, -- see the README for details
	customPatterns = {}, -- see the README for details
}

The two booleans are the two features described above, and either can be turned off if you want only one of them. The remaining two options point back at the documentation, which is a hint that the default values are the simple case and the interesting configuration lives elsewhere. The second route is to pass a table to the motion call itself:

lua
require("spider").motion("w", { skipInsignificantPunctuation = false })

Anything passed to the motion takes precedence over what setup set, so a single mapping can behave differently from the rest. That is the mechanism you would use to keep vim-style punctuation stops for one motion while the others skip them.

Custom patterns replace the default behaviour entirely

The customPatterns option is where the plugin stops being about subwords and becomes a general pattern-based motion. The rules are stated precisely. Patterns must be lua patterns, not regular expressions. When several patterns are given, the motion searches for all of them and stops at the closest one, and when there is nothing to match in a line the search continues into the next line. The option overrides the default behaviour, meaning no subword movement and no punctuation skipping, unless you pass a pattern table with overrideDefault set to false, which extends the default behaviour with an extra pattern. The documentation also notes that patterns must be symmetrical to work for both the backwards and forwards motions, and that an asymmetric pattern has to be defined separately for each direction. The first example is a motion that stops only at numbers:

lua
-- The motion stops only at numbers.
require("spider").motion("w", {
	customPatterns = { "%d+" },
})

And the extension form adds a stop without giving up the default behaviour:

lua
-- The motion stops at any occurrence of the letters "A" or "C", in addition 
-- to spider's default behavior.
require("spider").motion("w", {
	customPatterns = {
		patterns = { "A", "C" },
		overrideDefault = false,
	},
})

The plugin ignores iskeyword, on purpose

There is a note in the documentation that deserves to be read before you install: this plugin ignores vim's iskeyword option. iskeyword is the setting that tells vim which characters count as part of a word, and for C or C++ users it is where you list the characters that are allowed in an identifier. Since nvim-spider derives its own idea of a subword rather than consulting iskeyword, a configuration that has spent time tuning iskeyword will see different behaviour once the motions are swapped. The subword rules the plugin applies are based on case transitions and on the _ and hyphen separators, which covers the common naming conventions in most languages without any configuration. The other side of that choice is that the plugin needs no per-language setup, which is exactly what you want if you use one Neovim configuration across several languages. The trade is explicit: predictable across languages, but not what iskeyword told you.

Operator-pending mode is the case worth reading about

The README has a section devoted to the case of cw in operator-pending mode, and a separate option for consistent operator-pending mode that defaults to false. The reason this needs its own section is that a change to word motions changes what the c operator deletes, and a plugin that alters that silently is a bad neighbour. With the default subword behaviour, an operator applied to a motion can act on a fragment of an identifier rather than the whole identifier, and a change operator may leave you inside a word you expected to have been replaced entirely. The consistentOperatorPending option exists to control how the plugin behaves in that mode, and it is off by default, which tells you the default does not try to impose consistency. Whatever you decide, the safe procedure is to try c, d and y on a camelCase identifier and a snake_case identifier after installing, rather than assuming the behaviour matches what you had before.

UTF-8 support needs an optional luarocks rock

Support for special characters is not built in. It requires UTF-8 support via the luautf8 rock, and installing it means adding luarocks.nvim as another plugin. The configuration gives it a high priority, described as required so that luarocks.nvim runs as the first plugin in your config, and marks it not lazy, with the rock list set to luautf8:

lua
-- lazy.nvim
return {
	{ "chrisgrieser/nvim-spider", lazy = true },
	{
		"vhyrro/luarocks.nvim",
		priority = 1000, -- high priority required, luarocks.nvim should run as the first plugin in your config
		lazy = false,
		opts = {
			rocks = { "luautf8" } -- specifies a list of rocks to install
		},
	},
}

For packer there is a one line form with a rocks option. The documentation also points at two specific issues for troubleshooting UTF-8 problems, and adds a note that CJK characters still have some issues,. That is enough to know that non-Latin text is the weak spot of this plugin and worth testing in your own documents before you rely on it.

A small Lua project with no release tags

The repository is small and simple in the way a Neovim plugin tends to be. The tree holds a lua directory for the plugin code, a doc directory for the Vim help file, an editorconfig, a luarc configuration for the Lua language server, a stylua configuration for formatting, a rumdl configuration for the Markdown linter, a harper dictionary file, and an emmyrc configuration. The MIT licence field on the repository covers the code, and there are no GitHub releases, so there is no tagged version to pin and no changelog to read. The last push was on 2026-08-03. The one thing to keep in mind when adopting a plugin this small is that the maintenance signal is the commit log rather than a release process, and the same is true of the plugin's dependencies: you are taking on luarocks.nvim and a rock as well as the motion code. The plugin is not self-contained for non-ASCII text, and that is a dependency decision rather than a missing feature.

Editorial conclusion

nvim-spider suits a Neovim user who navigates source code and wants a word motion that understands the shape of an identifier rather than treating it as one blob, and who is willing to swap the built-in motions for plugin ones. It does not suit someone who wants vim's keyword rules to keep working, since the plugin ignores iskeyword, and it does not suit a configuration that cannot tolerate an extra Lua dependency for the motion layer. Before adopting it, read the operator-pending section, because the plugin changes what cw does, and if you work with CJK text, read the linked issues first, since the UTF-8 support depends on an optional rock and the project notes that CJK characters still have issues.

Frequently asked questions

How do I install nvim-spider and replace the w, e and b motions?

Add the plugin with your manager of choice, then map the motions yourself, because the plugin creates no keybindings by default. The mapping calls require('spider').motion('w') and the same for e, b and ge, in normal, operator-pending and visual mode.

Does nvim-spider respect the iskeyword option?

No. The documentation states that the plugin ignores vim's iskeyword option and derives its own subword rules from case transitions and from the _ and hyphen separators. That makes behaviour consistent across languages but different from a tuned iskeyword configuration.

How do I turn off the punctuation skipping in nvim-spider?

Set skipInsignificantPunctuation to false in the setup call, or pass it in the table given to the motion call, where it takes precedence over the setup value.

Does nvim-spider work with non-ASCII text?

Support for special characters requires the luautf8 rock, installed through luarocks.nvim with a high priority so it loads first. The documentation points to two specific issues for troubleshooting, and notes that CJK characters still have some issues.

Official sources

  1. chrisgrieser/nvim-spider on GitHub
  2. Issues
  3. License: MIT
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/chrisgrieser-nvim-spider.svg)](https://hysenlabs.com/projects/chrisgrieser-nvim-spider)

Was this useful?