πͺ tobira.nvim
August 7, 2026 Β· View on GitHub
πͺ tobira.nvim
Learn the next Vim command from your own editing habits β not a cheat sheet.
tobira watches how you actually edit, and when it spots a pattern you could do better, it quietly shows you the one command that would have helped. No quizzes. No interruptions.
Features β’ Installation β’ Usage β’ Configuration β’ vs hardtime.nvim
β¨ Features
- π Fully passive β reads keystrokes via
vim.on_key(); no config required, zero impact on your existing mappings - π― 71 detected patterns across motion, edit, search, window, fold, mark, macro, diff, ex, and terminal β repeated
fsearches,dwβiinstead ofcw, retyping the same:s///substitution instead of&/g&, and more (see examples below) - β¨οΈ Ex commands, too β
:g,:norm,:s, and friends are tracked from the command line itself, not just normal-mode keys, so:g/:normcan be suggested to users who have never tried them (tobira's own:Tobira*commands are excluded, so checking your stats never counts as usage) - π¬ One suggestion at a time β shown after a natural pause, capped per session, with a cooldown between auto-suggestions β never a popup quiz
- π Mastery-aware β once you've used a command ~100 times, tobira stops suggesting it and moves on
- πͺ Level-aware β beginner commands surface first, advanced ones once you're ready
- πΊοΈ 186 commands in the learning graph, covering the full Neovim command surface
β‘οΈ Requirements
- Neovim 0.9+
- nvim-notify (optional β if installed, tobira's suggestion window matches its color scheme)
π¦ Installation
lazy.nvim
{
"kamegoro/tobira.nvim",
event = "VeryLazy",
opts = {},
}
packer.nvim
use {
"kamegoro/tobira.nvim",
config = function()
require("tobira").setup()
end,
}
π Usage
| Command | Description |
|---|---|
:Tobira | Show the next suggestion now (ignores cooldown). Press q / Esc to dismiss. |
:TobiraGuide | Toggle the cheatsheet panel |
:TobiraProgress | Show skill tree with mastery glyphs and a cursor-driven detail preview. x = suppress, p = pin, g/s = jump to guide/stats, q/Esc/<C-c> = close. |
:TobiraStats | Show usage stats: command distribution (never/tried/familiar/mastered) and efficiency gap suggestions |
:TobiraReset | Clear all usage data |
:checkhealth tobira | Diagnose your install β Neovim version, data directory, usage.json validity, lang config |
Full documentation is available in Neovim via :help tobira.
πΈ Screenshots β Guide, Stats & Progress panels
Guide panel
:TobiraGuide opens a cheatsheet on the right side of the screen. Commands you've already mastered are automatically hidden, so only your next targets are shown β and if one of them fades from use after you'd gotten comfortable with it, it reappears with a β³ (forgotten) marker instead of staying hidden forever. Pinned commands always appear at the top, marked β. Covers all 10 categories: motion, edit, search, window, fold, mark, macro, diff, ex, and terminal β each capped to 3 unmastered commands (preferring ones you've never tried) so the panel stays a compact reference to glance at while you keep coding, with a +N more line if a category has more to show. Opens automatically on first launch.
Usage stats
:TobiraStats leads with the one section that actually changes what you do next β Try these next, commands you're using heavily whose neighbors you've never tried β followed by a mastery bar and your top commands. Total keystrokes and how many commands you've discovered sit in a quiet line at the bottom: fun to see, but not the point. g / p jump straight to Guide / Progress.
Skill progress
:TobiraProgress shows your current level and the full command learning graph as a calm grid β mastery glyphs only, no clutter. Move the cursor onto any command and a preview strip below the grid fills in with its usage sparkline, count, status, and how far it is from the next star. The header shows your overall {n} / {total} mastered ratio, and each category shows its own {done} / {total}.
| Glyph | Meaning |
|---|---|
| (blank) | Not yet tried |
β | Tried (1+ uses) |
β
| Familiar (100+ uses) |
β
β
| Practiced (1000+ uses) |
β
β
β
| Mastered (5000+ uses) |
β³ | Forgotten β recent use has fallen off well below its earlier pace |
β | Suppressed β you don't want this suggested |
β | Pinned β always shown, in both :TobiraGuide and :TobiraProgress |
Keys inside :TobiraProgress: x toggles suppress on the command under the cursor, p toggles pin, g / s jump to Guide / Stats, q / Esc / <C-c> closes.
βοΈ Configuration
All options are optional β the defaults work out of the box.
require("tobira").setup({
lang = 'en', -- 'en' | 'ja' | 'zh' | 'es' | 'fr' | 'de'
idle_delay = 1500, -- ms of inactivity before showing an ambient suggestion
idle_suggestions = true, -- enable ambient idle suggestions
suggestion_cooldown = 300, -- s between automatic suggestions (default: 5 min)
max_shown = 2, -- max times to suggest the same command per session
integrations = true, -- boost suggestions when a known helper plugin is installed
})
tobira always respects your own :nmap/:nnoremap overrides β it never suggests a
command you've remapped away, and integrations above only gates the optional
plugin-detection boost, not that baseline behavior (see :help tobira-integrations).
tobira also tells apart a genuine remap from Neovim's own factory-default mappings β
gx, &, ]q/[q/]l/[l, and (Neovim 0.10+) even Y = y$ ship as built-in
defaults out of the box, so none of them count as "remapped" on a stock install; they're
suggested completely normally.
Two narrow exceptions cover a mapping that genuinely was set by something but still
does what tobira teaches: if you personally add nnoremap Y y$ yourself (redundant with
the modern default above, but a real personal binding), it's recognized as equivalent,
so the reactive y$ β Y suggestion still fires instead of being suppressed outright β
a Y remapped to anything else still suppresses it. Likewise, Neovim auto-loads
matchit.vim by default, which remaps % to <Plug>(MatchitNormalForward) β a strict,
compatible superset of the built-in % tobira teaches, so :TobiraGuide's cheat sheet
still lists % (with a "mapped to ..." note) on a stock install instead of hiding it
outright; a % remapped to anything else still hides it like any other override. Both
exceptions are still excluded from the proactive idle/:Tobira picks and
:TobiraStats's "Try these next" list either way β see :help tobira-integrations for
why those two surfaces don't read this distinction.
π― Detected patterns (examples)
| You do this | tobira suggests |
|---|---|
fa β fa on the same line | ; β repeat the last f/t |
dw β i | cw β change word in one command |
| `j$ \times 10 \text{in} \text{a} \text{row} | $}` β jump by paragraph |
j$ \times 10 \text{in} \text{a} \text{row} \text{while} $&diff is set | ]c β jump to the next diff hunk |
| `dd$ \times 3 \text{in} \text{a} \text{row} | ${n}dd` β delete N lines at once |
<C-w>q / ` | $ |
G then gg (or gg then G) | '' β jump straight back to your previous position |
| `cwFooBar | $qq...q/@q` β record and replay a macro |
| Same `:s/pat/repl/$ \text{retyped} 3 \times \text{across} \text{lines} | $g&` β repeat it across the whole file |
| ` | $<C-> |
<C-w>+ / <C-w>- / <C-w>< / ` | $ |
<C-e> / ` | $zz` β center the cursor line on screen |
Same one-line edit (e.g. A;<Esc>) on 3 consecutive lines | <C-v> β block-visual edit them all at once |
Insert-mode edit right after a ]c/[c diff-hunk jump | do / `dp$ β \text{diff} \text{obtain}/\text{put} \text{the} \text{whole} \text{hunk} |
| \text{Cursor} \text{returns} \text{to} \text{the} \text{same} \text{line} 3 \times \text{with} \text{real} \text{edits} \text{in} \text{between} | $ma` β set a named mark to jump back to |
| `~$ \times 6 (\text{spans} \text{a} \text{word}) / \times 12 (\text{spans} \text{a} \text{line}) | ` β toggle case in one motion |
71 patterns total β see :help tobira-patterns for the full list.
π Similar plugins
| Plugin | What it does | vs tobira |
|---|---|---|
| hardtime.nvim | Blocks repeated keys, hints better motions | Punishes bad habits β tobira teaches without ever blocking input |
| precognition.nvim | Shows available motions as virtual text | Always-on overlay β tobira appears only when you would have benefited |
| spamguard.nvim | Detects key spamming | Spam detection only β tobira covers the full command graph and tracks mastery |
| pathfinder.vim | Suggests more efficient cursor movement | Cursor movement only β tobira covers motion, edit, and search |
| vim-be-good | Game-based practice | Generic drills β tobira personalizes to your actual usage |
tobira is the only plugin that learns from your actual usage and shows you the specific commands you are missing.
β FAQ
| Question | Answer |
|---|---|
| Will tobira slow down my Neovim? | No β vim.on_key() stays minimal, no I/O per keystroke; usage data flushes only on exit. |
| Does it send my keystrokes anywhere? | No. Everything stays local in tobira/usage.json. |
| Can I use it alongside hardtime.nvim? | Yes β hardtime blocks bad habits, tobira teaches better ones. They complement each other. |
| A suggestion keeps appearing for something I already know | Open :TobiraProgress, move to it, press x to suppress. |
| How do I reset my data? | Run :TobiraReset. |
π¦Ύ Contributing
See CONTRIBUTING.md. This project follows strict TDD β tests before implementation, always.
License
MIT