npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

pi-vim

v0.1.8

Published

Vim-style modal editing for Pi's TUI editor

Downloads

711

Readme

vim-bindings — Pi REPL Vim Mode

A modal vim-like editing extension for Pi's REPL prompt, covering the high-frequency ("90%") command surface without trying to clone full Vim.

Loading

pi --extension /path/to/vim-bindings/index.ts

Or add to .pi/settings.json:

{
  "extensions": ["./pi-extensions/vim-bindings/index.ts"]
}

The mode indicator (INSERT / NORMAL) is shown in the bottom-right corner of the prompt.


Supported command surface

Mode switching

| Key | Action | |----------|----------------------------------------| | Esc | Insert → Normal mode | | Esc | Normal mode → pass to Pi (abort agent) | | i | Normal → Insert at cursor | | a | Normal → Insert after cursor | | I | Normal → Insert at line start | | A | Normal → Insert at line end | | o | Normal → open line below + Insert | | O | Normal → open line above + Insert |

Insert-mode shortcuts (stay in Insert mode):

| Key | Action | |-----------------|------------------------| | Shift+Alt+A | Go to end of line | | Shift+Alt+I | Go to start of line | | Alt+o | Open line below | | Alt+Shift+O | Open line above |


Navigation (Normal mode)

A {count} prefix can be prepended to any navigation key (max: 9999).

| Key | Action | |---------------|-------------------------------| | h | Left | | l | Right | | j | Down | | k | Up | | {count}h/l | Move left/right {count} cols | | {count}j/k | Move down/up {count} lines (clamped to buffer size) | | 0 | Line start | | $ | Line end | | gg | Buffer start (line 1) | | {count}gg | Go to line {count} (1-indexed, clamped) | | G | Buffer end (last line) | | {count}G | Go to line {count} (1-indexed, clamped) | | w | Next word start (keyword/punctuation aware) | | b | Previous word start | | e | word end (inclusive) | | W | Next WORD start (whitespace-delimited token) | | B | Previous WORD start | | E | WORD end (inclusive) | | {count}w/b/e| Move {count} word motions | | {count}W/B/E| Move {count} WORD motions | | } | Move to next paragraph start (line start col 0) | | { | Move to previous paragraph start (line start col 0) | | {count}} | Repeat } {count} times | | {count}{ | Repeat { {count} times |

word (w/b/e) splits punctuation from keyword chars. WORD (W/B/E) treats any non-whitespace run as one token (foo-bar, path/to, x.y).

Paragraph boundary definition (this extension wave):

  • blank line: matches ^\s*$
  • paragraph start: non-blank line at BOF, or non-blank line immediately after a blank line

Standalone { / } motions are navigation-only (no text/register mutation). Counted forms ({count}{, {count}}) step paragraph-by-paragraph. If no further paragraph boundary exists, motions clamp at BOF/EOF. Operator forms with braces (d{, d}, c{, c}, y{, y}) are out of scope for this wave.


Character-find motions (Normal mode)

A {count} prefix finds the Nth occurrence of {char} on the line.

| Key | Action | |------------------|------------------------------------------------| | f{char} | Jump forward to char (inclusive) | | F{char} | Jump backward to char (inclusive) | | t{char} | Jump forward to one before char (exclusive) | | T{char} | Jump backward to one after char (exclusive) | | {count}f{char} | Jump to Nth occurrence of char forward | | ; | Repeat last f/F/t/T motion | | , | Repeat last motion in reverse direction |

Char-find motions compose with operators: df{char}, ct{char}, d{count}t{char}, etc.


Edit operators (Normal mode)

All operators write to the unnamed register and mirror to the system clipboard (best-effort; clipboard failure never breaks editing).

Delete d{motion} / dd

A {count} or dual-count prefix ({pfx}d{op}{motion}) is supported for word, char-find, and linewise motions. Maximum total count: 9999.

| Command | Deletes | |-------------------|-----------------------------------------------------------| | dw | Forward to next word start (exclusive, can cross lines) | | de | Forward to word end (inclusive, can cross lines) | | db | Backward to word start (exclusive, can cross lines) | | dW | Forward to next WORD start (exclusive, can cross lines) | | dE | Forward to WORD end (inclusive, can cross lines) | | dB | Backward to WORD start (exclusive, can cross lines) | | d{count}w/e/b | Forward/backward {count} word motions | | d{count}W/E/B | Forward/backward {count} WORD motions | | d$ | To end of line | | d0 | To start of line | | dd | Current line (linewise) | | {count}dd | {count} lines (linewise) | | d{count}j | Current line + {count} lines below (linewise) | | d{count}k | Current line + {count} lines above (linewise) | | dG | Current line to end of buffer (linewise) | | df{char} | To and including char | | d{count}f{char} | To and including Nth char | | dt{char} | Up to (not including) char | | dF{char} | Backward to and including char | | dT{char} | Backward to one after char | | diw | Inner word | | daw | Around word (includes surrounding spaces) | | d{count}aw | Around {count} words |

Change c{motion} / cc

Same motion and count set as d. Deletes text then enters Insert mode.

| Command | Action | |-----------------|------------------------------------| | cw | Change word + Insert | | ce / cb | Change to word end / previous word start | | cW | Change WORD + Insert (cW on non-space behaves like cE) | | cE / cB | Change to WORD end / previous WORD start | | c{count}w/e/b | Change {count} word motions + Insert | | c{count}W/E/B | Change {count} WORD motions + Insert | | ciw | Change inner word | | caw | Change around word | | cc | Delete line content + Insert | | c$ | Delete to EOL + Insert | | … | All d motions apply |

Single-key edits

A {count} prefix is supported for x, p, P. Maximum: 9999.

| Key | Action | |--------------|---------------------------------------------------------------| | x | Delete char under cursor (no-op at/past EOL) | | {count}x | Delete {count} chars | | s | Delete char under cursor + Insert mode | | S | Delete line content + Insert mode | | D | Delete cursor to EOL (captures \n if at EOL with next line) | | C | Delete cursor to EOL + Insert mode |


Yank y{motion} / yy

Same motion set as d. Writes to register, no text mutation.

| Command | Yanks | |---------|---------------------------------| | yy | Whole line + trailing \n | | {count}yy | {count} whole lines + trailing \n | | y{count}j | Current line + {count} lines below (linewise) | | y{count}k | Current line + {count} lines above (linewise) | | yG | Current line to end of buffer (linewise) | | yw | Forward to next word start | | ye | To word end (inclusive) | | yb | Backward to word start | | yW | Forward to next WORD start | | yE | To WORD end (inclusive) | | yB | Backward to WORD start | | y$ | To end of line | | y0 | To start of line | | yf{c} | To and including char | | yiw | Inner word | | yaw | Around word (includes spaces) |

Counted yank caveat: counted word/WORD yank motions are intentionally not implemented (y2w, 2yw, y2W, 2yW, etc. cancel the pending operator). Linewise counted yank ({count}yy, y{count}j/k) remains supported.


Put / Paste

| Key | Action | |--------------|-------------------------------------------------------------| | p | Put after cursor (char-wise) / new line below (line-wise) | | P | Put before cursor (char-wise) / new line above (line-wise) | | {count}p | Put {count} times after cursor | | {count}P | Put {count} times before cursor |

Put reads from the unnamed register (not OS clipboard).
Line-wise detection: register content ending in \n is treated as line-wise.


Undo

| Key | Action | |-----|-------------------------------------------------| | u | Undo — sends ctrl+_ (\x1f) to the underlying readline editor |

Redo (<C-r>) is not implemented — see Out of scope.


Register and clipboard policy

  • One unnamed register (like Vim's "" register).
  • Every d, c, x, s, S, D, C, y operator form (including dd, {count}dd, d{count}j/k, dG, yy, {count}yy, y{count}j/k, yG) writes to the register and mirrors to the OS clipboard (via copyToClipboard, best-effort).
  • p / P read from the unnamed register only (not the OS clipboard).
  • This gives stable behaviour across local terminals and SSH / OSC52 setups.

Known differences from full Vim

| Area | This extension | Full Vim | |-----------------------|----------------------------------------|-------------------------------| | $ motion | Moves past last char (readline CTRL+E) | Moves to last char | | w / e / b + W / E / B | Cross-line for word + WORD motions | Cross-line | | 0 / $ operators | Exclusive of anchor col | 0 inclusive of col 0 | | Undo depth | Delegates to underlying readline undo | Full per-change undo tree | | Redo | Not implemented | <C-r> | | Visual mode | Not implemented | v, V, <C-v> | | Text objects | Supports iw/aw only | Full text-object set | | Count prefix | Supported for operators, word/char motions, navigation, and edits (x, p/P); capped at MAX_COUNT=9999 to prevent abuse | Full support | | Named registers | Not implemented ("a, etc.) | Supported | | Macros | Not implemented (q, @) | Supported | | Search | Not implemented (/, ?, n, N) | Supported | | Ex commands | Not implemented (:s, :g, etc.) | Supported | | Multi-line operators | Supports d/c/y with w/e/b and W/E/B, plus j/k counts and G; not full Vim motion matrix | Rich cross-line semantics |


Out of scope

These are explicitly deferred and not planned for this feature:

  • Visual modes (v, V, block visual)
  • Extended text objects beyond word (ip, i", i(, etc.)
  • Named registers ("a, "b, …)
  • Macros (q{char}, @{char})
  • Ex command surface (:s, :g, :r, …)
  • Search mode (/, ?, n, N)
  • Repeat (.)
  • Extended count prefix beyond currently supported motions (e.g. :, global operator counts)
  • Redo (<C-r>) — no native redo primitive in the underlying readline editor; deferred until a suitable hook is available.
  • Window / tab / buffer management
  • Plugin / runtime ecosystem compatibility

Architecture notes

  • index.tsModalEditor subclass of CustomEditor; all key handling.
  • motions.ts — pure motion calculation helpers (findWordMotionTarget, findCharMotionTarget); no side effects.
  • types.ts — shared types and escape-sequence constants.
  • test/ — Node test runner suite; no browser / full runtime required.

Run tests:

cd vim-bindings
npm test