JSON editor with vim-style keybindings
Project description
jvim
JSON editor with vim-style keybindings, built with Textual.
Screenshots
Editor
Diff Viewer
Features
- Vim-style modal editing - Normal, Insert, Command, and Search modes
- Syntax highlighting - JSON-aware colorization
- JSON validation - Real-time validation with error reporting
- JSONPath search - Search using JSONPath expressions (
$.foo.bar) - JSONL support - Edit JSON Lines files with smart formatting
- Embedded JSON editing - Edit JSON strings within JSON with nested level support
- Visual mode - Character-wise (
v) and line-wise (V) selection withd/y/coperators - Count prefix - Vim-style numeric prefixes (
5j,3dd,d3d) with fold-aware line operations - Folding - Collapse/expand JSON blocks and long string values
- Bracket matching - Jump to matching brackets with
% - Undo/Redo - Full undo history
- Substitute - Vim-style
:s/old/new/gwith regex, range, and flags support - Multi-file navigation - Open multiple files and switch with
:n,:N,:e# - Diff viewer - Side-by-side JSON comparison with scroll/fold sync
Installation
pip install jvim
Usage
# Open a file
jvim data.json
# Open multiple files
jvim a.json b.json c.json
# Open in read-only mode
jvim -R data.json
# Create new file
jvim newfile.json
Also available as jvi and jv shortcuts.
JSONL Support
jvim provides special handling for JSON Lines (.jsonl) files:
- Pretty-printed editing: Each JSONL record is automatically formatted with indentation for easy reading and editing
- Compact saving: When you save, each record is minified back to a single line, preserving the JSONL format
- Record numbers: A second column shows the record number (1, 2, 3...) for easy navigation
- Floating header: When scrolling through a multi-line record, the physical line number stays visible at the top
Example: A JSONL file with two records:
{"name": "Alice", "age": 30}
{"name": "Bob", "age": 25}
Opens in jvim as:
{
"name": "Alice",
"age": 30
}
{
"name": "Bob",
"age": 25
}
And saves back to the original compact format.
JSONPath Search
jvim supports powerful JSONPath searching with value filtering.
Basic JSONPath
Search patterns starting with $. or $[ are automatically recognized as JSONPath:
/$.name # Find the "name" field
/$..email # Find all "email" fields (recursive)
/$.users[0] # First user
/$.users[*].name # All user names
Value Filtering
You can filter search results by value using comparison operators:
| Operator | Description | Example |
|---|---|---|
= |
Equals | $.status="active" |
!= |
Not equals | $.status!=null |
> |
Greater than | $.age>18 |
< |
Less than | $.price<100 |
>= |
Greater or equal | $.count>=5 |
<= |
Less or equal | $.count<=10 |
~ |
Regex match | $.email~@gmail\.com$ |
Examples
/$.users[*].age>30 # Users older than 30
/$.items[*].status="active" # Items with active status
/$..name~^J # All names starting with J
/$.price<=1000 # Price 1000 or less
/$.config.enabled=true # Enabled configs
Search Modifiers
| Suffix | Description |
|---|---|
\j |
Force JSONPath mode for ambiguous patterns |
\c |
Case insensitive (for regex text search) |
\C |
Case sensitive (for regex text search) |
History
Search and command history is automatically saved to ~/.jvim/history.json and restored on next launch. Use arrow keys (↑/↓) to navigate history in search (/) and command (:) modes.
Embedded JSON Editing
JSON files often contain escaped JSON strings as values. jvim lets you edit these nested JSON structures naturally.
How it works
- Position your cursor on a line containing a JSON string value
- Type
ejin normal mode - A new editor panel opens with the parsed and formatted JSON
- Edit the embedded JSON with full syntax highlighting and validation
- Save with
:wto update the parent document (minified) or:qto cancel
Nested levels
You can edit embedded JSON within embedded JSON:
- The panel title shows the current nesting level:
Edit Embedded JSON (level 1) - A
[+]indicator appears when you have unsaved changes :wsaves to the parent document and continues editing:wqsaves and returns to the previous level:q!discards changes and returns to the previous level
Example
Given this JSON:
{
"config": "{\"host\": \"localhost\", \"port\": 8080}"
}
Using ej on the config line opens:
{
"host": "localhost",
"port": 8080
}
After editing and saving, the parent is updated with the minified result.
Substitute
jvim supports vim-style substitute commands for find-and-replace.
| Command | Description |
|---|---|
:s/old/new/ |
Replace first match on current line |
:s/old/new/g |
Replace all matches on current line |
:%s/old/new/g |
Replace all matches in entire file |
:N,Ms/old/new/g |
Replace all matches in lines N to M |
Features
- Custom delimiters - Use any character as delimiter:
:s#old#new#g,:s|old|new|g - Flags -
g(global/all matches),i(case insensitive) - Regex support - Full regular expressions with group capture (
\1,\2) - Undo - All substitutions can be undone with
u
Examples
:s/foo/bar/ # Replace first "foo" with "bar" on current line
:%s/TODO/DONE/g # Replace all "TODO" with "DONE" in file
:s/(\w+)/[\1]/g # Wrap each word in brackets
:%s/old/new/gi # Case-insensitive replace in entire file
:2,10s/from/to/g # Replace in lines 2 through 10
JSONPath Substitute
When the find pattern starts with $. or $[, substitute operates on JSON structure. The trailing = determines the mode:
| Pattern | Mode | Description |
|---|---|---|
:s/$.key/newkey/g |
Key rename | Rename JSON keys |
:s/$.key=/value/g |
Value replace | Replace all values at path |
:s/$.key="old"/new/g |
Filtered value | Replace values matching filter |
Key rename
:s/$.name/username/g # Rename "name" key to "username"
:s/$..name/label/g # Rename all "name" keys recursively
Value replace
:s/$.name=/Bob/g # Replace "name" value with "Bob"
:s/$..status=/active/g # Replace all "status" values recursively
:s/$.users[*].age=/0/g # Reset all user ages to 0
:s/$..enabled=/true/g # Set all "enabled" to true
:s/$..status="draft"/review/g # Replace only "draft" statuses (filter)
Replacement values are auto-detected: numbers (42), booleans (true/false), null stay as-is; everything else is JSON-encoded as a string.
Multi-file Navigation
Open multiple files and navigate between them using argument list commands:
jvim a.json b.json c.json
| Command | Description |
|---|---|
:n |
Go to next file |
:N |
Go to previous file |
:e# |
Switch to alternate (previously opened) file |
The title bar shows the current position in the file list: a.json [1/3].
Files opened with :e <file> are tracked as the alternate file, so you can switch back with :e#.
Git Difftool Integration
jvimdiff can be used as a git difftool to compare JSON changes in your repository.
Setup
# Register jvimdiff as git difftool
jvimdiff --install-difftool
# Remove registration
jvimdiff --uninstall-difftool
Usage
# Compare using jvimdiff
git difftool -t jvimdiff # All changed files
git difftool -t jvimdiff file.json # Specific file
git difftool -t jvimdiff HEAD~3 # Compare with specific commit
# Set as default difftool
git config --global diff.tool jvimdiff
git difftool file.json # Use without -t flag
Diff Viewer
jvim includes a side-by-side diff viewer for comparing two JSON files.
Usage
# Compare two JSON files
jvimdiff file1.json file2.json
# Skip JSON normalization (compare raw text)
jvimdiff --no-normalize file1.json file2.json
# Compare JSONL files (auto-detected for .jsonl extension)
jvimdiff --jsonl file1.json file2.json
Also available as jvd shortcut.
Features
- Color-coded diff - Deletions (red), insertions (green), and replacements (gray) are highlighted
- Scroll sync - Both panels scroll together
- Fold sync - Folding/unfolding in one panel is mirrored to the other
- Auto-fold - On load, all structure is folded, then only diff sections are unfolded
- Hunk navigation -
]cnext hunk,[cprevious hunk (wraps around) - Panel switch -
Tabto toggle focus between left and right panels - Active panel indicator - Title bar highlights the focused panel
- Cursor sync - Cursor position syncs between panels
- Line numbers - Logical line number (left) and JSONL record number (both panels)
- Embedded JSON diff -
ejto diff embedded JSON strings within each panel
Keybindings
Use :help inside jvim to see the full keybinding reference.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file jvim-0.7.0.tar.gz.
File metadata
- Download URL: jvim-0.7.0.tar.gz
- Upload date:
- Size: 296.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
05caed75772ed2fb3e81c2505412dec14e116817a6e3a6b1033adfeb04eacd3b
|
|
| MD5 |
f3e8aabf677c3b4b5d52de293002820f
|
|
| BLAKE2b-256 |
082f48b12b0fca568f4a7d39e0afbf0070ed84be57950dc464a88fea3490d19e
|
File details
Details for the file jvim-0.7.0-py3-none-any.whl.
File metadata
- Download URL: jvim-0.7.0-py3-none-any.whl
- Upload date:
- Size: 61.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a05d542cd1b3b89ad42c705f929967d9e19d2d59b6d4311dc428a7210aceb81d
|
|
| MD5 |
97f8f483a34c58b6c19c10f73f6955ea
|
|
| BLAKE2b-256 |
06a79455735f0356510f3e369e60854b7de7ca32c34f7c60ab4b9460351be6fb
|