kamegoro/tobira.nvim

github github
keybinding
stars 55
issues 13
subscribers 0
forks 4
CREATED

UPDATED


🚪 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
  • 🎯 77 detected patterns across motion, edit, search, window, fold, mark, macro, diff, ex, and terminal — repeated f searches, dw→i instead of cw, 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 / :norm can 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
  • 🗺️ 195 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.

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
diw → i ciw — change inner word in one command
j × 5 in a row on a genuinely wrapped line (with 'wrap' set) gj — move by display line instead
j × 10 in a row } — jump by paragraph
j × 10 in a row while &diff is set ]c — jump to the next diff hunk
dd × 3 in a row {n}dd — delete N lines at once
<C-w>q / <C-w>c × 2 in a row <C-w>o — close all other windows
zo × 2 in a row (different folds) zR — open all folds at once
zc × 2 in a row (different folds) zM — close all folds at once
G then gg (or gg then G) '' — jump straight back to your previous position
cwFooBar<Esc> repeated 3× (navigation allowed between) qq...q / @q — record and replay a macro
Same :s/pat/repl/ retyped 3× across lines g& — repeat it across the whole file
<Esc> × 2 in terminal mode, no effect <C-\><C-n> — exit terminal mode
<C-w>+ / <C-w>- / <C-w>< / <C-w>> × 2 in a row <C-w>= — equalize all window sizes
<C-e> / <C-y> × 5 in a row 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 — diff obtain/put the whole hunk
Cursor returns to the same line 3× with real edits in between ma — set a named mark to jump back to
~ × 6 (spans a word) / × 12 (spans a line) g~iw / g~$ — toggle case in one motion

77 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