Metadata-Version: 2.4
Name: jvim
Version: 0.7.2
Summary: JSON editor with vim-style keybindings
Project-URL: Homepage, https://github.com/k2hyun/jvim
Project-URL: Repository, https://github.com/k2hyun/jvim
Project-URL: Issues, https://github.com/k2hyun/jvim/issues
Author-email: Kihyun Kim <k2hyun@gmail.com>
License-Expression: MIT
Keywords: cli,editor,json,jsonl,textual,tui,vim
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Text Editors
Classifier: Topic :: Utilities
Requires-Python: >=3.10
Requires-Dist: textual>=0.70.0
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: textual-dev>=1.0; extra == 'dev'
Description-Content-Type: text/markdown

# jvim

JSON editor with vim-style keybindings, built with [Textual](https://github.com/Textualize/textual).

[한국어](README.kr.md)

## Screenshots

### Editor
![jvim](docs/jvim.svg)

### Diff Viewer
![jvimdiff](docs/jvimdiff.svg)

## 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`)
- **Word search** - Search word under cursor with `*` (forward) and `#` (backward)
- **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 with `d`/`y`/`c` operators
- **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/g` with 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

```bash
pip install jvim
```

## Usage

```bash
# 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

1. Position your cursor on a line containing a JSON string value
2. Type `ej` in normal mode
3. A new editor panel opens with the parsed and formatted JSON
4. Edit the embedded JSON with full syntax highlighting and validation
5. Save with `:w` to update the parent document (minified) or `:q` to 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
- `:w` saves to the parent document and continues editing
- `:wq` saves and returns to the previous level
- `:q!` discards changes and returns to the previous level

### Example

Given this JSON:
```json
{
    "config": "{\"host\": \"localhost\", \"port\": 8080}"
}
```

Using `ej` on the config line opens:
```json
{
    "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:

```bash
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

```bash
# Register jvimdiff as git difftool
jvimdiff --install-difftool

# Remove registration
jvimdiff --uninstall-difftool
```

### Usage

```bash
# 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

```bash
# 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** - `]c` next hunk, `[c` previous hunk (wraps around)
- **Panel switch** - `Tab` to 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** - `ej` to diff embedded JSON strings within each panel

## Keybindings

Use `:help` inside jvim to see the full keybinding reference.

## Vim Plugin

A native Vim plugin with the same JSON editing features (folding, JSONPath, embedded JSON, JSONL) is available as a standalone repository:

[vim-jvim](https://github.com/k2hyun/vim-jvim) — install with your favorite plugin manager:

```vim
Plug 'k2hyun/vim-jvim'
```

## License

MIT
