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

vim-sim

v1.0.10

Published

A complete Vim editor simulation engine for Node.js. Implements motions, operators, visual mode, text objects, macros, marks, undo/redo tree, spell checking, and more. Check out my demo here: https://vim.colefoster.ca/demo

Downloads

973

Readme

vim-sim

Demo npm version License: MIT TypeScript Test Coverage

A complete, production-ready Vim editor simulation engine for Node.js. Implements the full Vim editing experience with 85%+ test coverage, including motions, operators, visual mode, text objects, macros, marks, undo/redo tree, spell checking, and more.

Core Editing

  • All Basic Motions: h, j, k, l, w, b, e, W, B, E, 0, $, ^, gg, G, {, }, (, ), %
  • Find & Till: f, F, t, T, ;, ,
  • Operators: d, c, y, >, <, =, g~, gu, gU
  • Visual Mode: Character (v), Line (V), and Block (<C-v>) with all operators
  • Text Objects: iw, aw, i", a", i', a', i(, a(, i{, a{, i[, a[, it, at, ip, ap, is, as
  • Insert Mode: i, I, a, A, o, O, s, S, c commands
  • Replace & Change: r, R, ~, J, gJ

Advanced Features

  • Undo/Redo Tree: Full vim-style undo tree with branches (u, <C-r>, g-, g+)
  • Macros: Record (q) and playback (@) with count support
  • Marks: Local and global marks (m, ', `)
  • Jump List: <C-o>, <C-i> navigation
  • Registers: Named, numbered, and special registers
  • Spell Checking: Real-time with custom dictionaries
  • Completion: Keyword, line, file, and omni completion
  • Folds: Code folding support
  • Multiple Windows: Split, navigate, and resize
  • Multiple Buffers: File management and buffer navigation

Text Formatting

  • Auto-indentation: Smart indentation based on braces
  • Text Wrapping: Format text with gq, gw
  • Alignment: Column alignment support
  • Comment Toggling: Smart comment handling
  • Digraphs: 150+ special characters

Installation

npm install vim-sim
import { Session } from 'vim-sim';

// Create a new vim session
const session = new Session();

// Load some text
session.handleKey(':');
session.handleKey('e');
session.handleKey(' ');
session.handleKey('f');
session.handleKey('i');
session.handleKey('l');
session.handleKey('e');
session.handleKey('.');
session.handleKey('t');
session.handleKey('x');
session.handleKey('t');
session.handleKey('Enter');

// Or set buffer content directly
import { State, Buffer, Cursor, Mode } from 'vim-sim';

const state = new State(
  new Buffer('Hello, World!\nVim simulation is awesome!'),
  new Cursor(0, 0),
  null,
  Mode.NORMAL
);
session.setState(state);

// Execute vim commands
session.handleKey('w');        // Move to next word
session.handleKey('d');        // Start delete operator
session.handleKey('w');        // Delete word

// Get the current state
const currentState = session.getState();
console.log(currentState.buffer.content);  // "Hello, is awesome!"
console.log(currentState.cursor.line);     // 0
console.log(currentState.cursor.column);   // 7

Session

The main entry point for vim simulation. Manages state and command execution.

class Session {
  constructor(config?: Partial<VimConfig>)

  // Handle a single keypress
  handleKey(key: string): void

  // Get current editor state
  getState(): State

  // Set editor state
  setState(state: State): void

  // Get command history
  getHistory(): CommandHistoryEntry[]
}

Example:

const session = new Session({
  tabSize: 4,
  expandTab: true,
  autoIndent: true
});

session.handleKey('i');           // Enter insert mode
session.handleKey('H');
session.handleKey('e');
session.handleKey('l');
session.handleKey('l');
session.handleKey('o');
session.handleKey('Escape');      // Back to normal mode
session.handleKey('0');           // Go to start of line

State

Represents the complete editor state at a point in time.

class State {
  constructor(
    buffer: Buffer,
    cursor: Cursor,
    selection: Range | null,
    mode: Mode,
    // ... other optional parameters
  )

  readonly buffer: Buffer
  readonly cursor: Cursor
  readonly selection: Range | null
  readonly mode: Mode
  readonly desiredColumn: number | null
  // ... many more properties
}

Buffer

Represents the text content being edited.

class Buffer {
  constructor(content: string = '')

  readonly content: string

  getLineCount(): number
  getLine(index: number): string
  getLines(): string[]
}

Example:

const buffer = new Buffer('Line 1\nLine 2\nLine 3');
console.log(buffer.getLineCount());  // 3
console.log(buffer.getLine(1));      // "Line 2"

Cursor

Represents cursor position (0-indexed).

class Cursor {
  constructor(line: number, column: number)

  readonly line: number
  readonly column: number
}

Mode

Vim editing modes.

enum Mode {
  NORMAL = 'normal',
  INSERT = 'insert',
  VISUAL = 'visual',
  VISUAL_LINE = 'visual_line',
  VISUAL_BLOCK = 'visual_block',
  COMMAND_LINE = 'command_line',
  REPLACE = 'replace'
}

Basic Text Editing

import { Session, Buffer, State, Cursor, Mode } from 'vim-sim';

const session = new Session();

// Start with some text
session.setState(new State(
  new Buffer('The quick brown fox\njumps over\nthe lazy dog'),
  new Cursor(0, 0),
  null,
  Mode.NORMAL
));

// Delete a word: dw
session.handleKey('d');
session.handleKey('w');

console.log(session.getState().buffer.content);
// "quick brown fox\njumps over\nthe lazy dog"

Visual Mode Selection

const session = new Session();
session.setState(new State(
  new Buffer('Hello World'),
  new Cursor(0, 0),
  null,
  Mode.NORMAL
));

// Visual select and delete: vlllld
session.handleKey('v');     // Enter visual mode
session.handleKey('l');     // Extend selection
session.handleKey('l');
session.handleKey('l');
session.handleKey('l');
session.handleKey('d');     // Delete selection

console.log(session.getState().buffer.content);  // " World"

Using Text Objects

const session = new Session();
session.setState(new State(
  new Buffer('function test(arg) { return arg; }'),
  new Cursor(0, 20),  // Inside the parentheses
  null,
  Mode.NORMAL
));

// Delete inside parentheses: di(
session.handleKey('d');
session.handleKey('i');
session.handleKey('(');

console.log(session.getState().buffer.content);
// "function test() { return arg; }"

Macros

const session = new Session();
session.setState(new State(
  new Buffer('line1\nline2\nline3'),
  new Cursor(0, 0),
  null,
  Mode.NORMAL
));

// Record macro: qaIHello <Esc>jq
session.handleKey('q');
session.handleKey('a');
session.handleKey('I');
session.handleKey('H');
session.handleKey('e');
session.handleKey('l');
session.handleKey('l');
session.handleKey('o');
session.handleKey(' ');
session.handleKey('Escape');
session.handleKey('j');
session.handleKey('q');

// Replay macro twice: 2@a
session.handleKey('2');
session.handleKey('@');
session.handleKey('a');

console.log(session.getState().buffer.content);
// "Hello line1\nHello line2\nHello line3"

Undo/Redo Tree

const session = new Session();
const state = new State(
  new Buffer('original text'),
  new Cursor(0, 0),
  null,
  Mode.NORMAL
);
session.setState(state);

// Make some changes
session.handleKey('c');
session.handleKey('w');
session.handleKey('n');
session.handleKey('e');
session.handleKey('w');
session.handleKey('Escape');

// Undo: u
session.handleKey('u');
console.log(session.getState().buffer.content);  // "original text"

// Redo: <C-r>
session.handleKey('<C-r>');
console.log(session.getState().buffer.content);  // "new text"

Working with Registers

const session = new Session();
session.setState(new State(
  new Buffer('Copy this text\nPaste here'),
  new Cursor(0, 0),
  null,
  Mode.NORMAL
));

// Yank to register 'a': "ayy
session.handleKey('"');
session.handleKey('a');
session.handleKey('y');
session.handleKey('y');

// Move and paste: jp
session.handleKey('j');
session.handleKey('"');
session.handleKey('a');
session.handleKey('p');

console.log(session.getState().buffer.content);
// "Copy this text\nPaste here\nCopy this text"

Custom Configuration

import { Session, ConfigManager } from 'vim-sim';

const session = new Session({
  tabSize: 2,
  expandTab: true,
  autoIndent: true,
  smartIndent: true,
  textWidth: 80,
  wrap: true,
  spell: true
});

// Or update config after creation
const config = session.getState().configManager;
// Access config values as needed

Spell Checking

const session = new Session();
const state = session.getState();

// Enable spell checking
state.spellChecker.enable();

// Add custom words
state.spellChecker.addGoodWord('vim-sim');

// Check a word
const isCorrect = state.spellChecker.isCorrect('hello');

// Get suggestions
const suggestions = state.spellChecker.suggest('wrold');
console.log(suggestions);  // ['world']

Window Management

const session = new Session();
const state = session.getState();

// Split window horizontally: <C-w>s
// Split window vertically: <C-w>v
// Navigate windows: <C-w>h/j/k/l
// Close window: <C-w>c

// Access window manager directly
const windowManager = state.windowManager;
const activeWindow = windowManager.getActiveWindow();

This package is written in TypeScript and provides full type definitions.

import type { State, Buffer, Cursor, Mode, Range, Command } from 'vim-sim';

function processVimState(state: State): void {
  const { buffer, cursor, mode, selection } = state;

  if (mode === Mode.VISUAL && selection) {
    console.log(`Selected from ${selection.start} to ${selection.end}`);
  }
}