# jarq

An interactive jq-like JSON query tool with a TUI.

Should you use this instead of `jq`? Definitely not, this was just an experiment using a TUI and live filtering.

## Usage

```bash
# Interactive TUI mode
echo '{"name": "Alice", "age": 30}' | jarq
cat data.json | jarq
jarq data.json

# Non-interactive mode (like jq)
echo '{"name": "Alice"}' | jarq '.name'
jarq '.items[]' data.json
```

In interactive mode, type filter expressions and see results in real-time.

## Keyboard Controls

### Navigation Mode

| Key | Action |
|-----|--------|
| `i`, `/` | Enter filter edit mode |
| `j`, `↓` | Scroll down |
| `k`, `↑` | Scroll up |
| `g` | Go to top |
| `G` | Go to bottom |
| `Ctrl-D` | Page down |
| `Ctrl-U` | Page up |
| `s` | Toggle slurp mode |
| `r` | Toggle raw output |
| `o` | Toggle compact output |
| `y` | Copy filter as jq command |
| `q`, `Esc` | Quit |
| `Ctrl-H` | Show help |

### Filter Edit Mode

| Key | Action |
|-----|--------|
| `Esc` | Exit filter edit mode |
| `Ctrl-P` | Toggle pause/resume evaluation |
| `Ctrl-C` | Cancel running evaluation |
| `Enter` | Evaluate now (when paused) |
| `Ctrl-S` | Toggle slurp mode |
| `Ctrl-R` | Toggle raw output |
| `Ctrl-O` | Toggle compact output |
| `Ctrl-Y` | Copy filter as jq command |
| `Ctrl-H` | Show help |

### Background Evaluation

jarq evaluates filters in the background as you type. For large files, you can:

- **Pause evaluation** (`Ctrl-P`): Stop auto-evaluation while you compose a complex filter
- **Cancel evaluation** (`Ctrl-C`): Stop a long-running evaluation and enter pause mode
- **Evaluate on demand** (`Enter`): When paused, manually trigger evaluation

When paused, the filter is still validated for syntax errors in real-time.

## Filter Syntax

```
.               # identity
.foo            # field access
.foo?           # optional (suppress errors)
.[0]            # array index
.[-1]           # negative index (from end)
.[2:5]          # array slice
.[:-1]          # slice (all but last)
.[]             # iterate all elements
.[]?            # optional iterate
.foo.bar        # chaining
.foo | length   # pipes

# Literals
42, 3.14        # numbers
"hello"         # strings
true, false     # booleans
null            # null

# Comparisons
.x == 5         # equal
.x != "foo"     # not equal
.x < 10         # less than
.x <= 10        # less or equal
.x > 0          # greater than
.x >= 0         # greater or equal

# Boolean operators
.a and .b       # logical and
.a or .b        # logical or
.x > 0 and .x < 10  # compound conditions

# Conditionals
if .x > 0 then "pos" else "neg" end
.name // "default"   # alternative (if null/false)

# Construction
[.a, .b]        # array
{name: .foo}    # object
{(.key): .val}  # dynamic key
```

## Builtins

| Builtin | Description |
|---------|-------------|
| `length` | Length of string, array, or object |
| `keys` | Object keys or array indices |
| `values` | Object or array values |
| `type` | Type name as string |
| `first` | First element of array |
| `last` | Last element of array |
| `reverse` | Reverse array |
| `sort` | Sort array |
| `min` | Minimum value in array |
| `max` | Maximum value in array |
| `unique` | Remove duplicates from array |
| `flatten` | Flatten nested arrays |
| `add` | Sum numbers, concat strings/arrays, merge objects |
| `empty` | Produce no output |
| `not` | Boolean negation |
| `to_entries` | Object to `[{key, value}, ...]` |
| `from_entries` | `[{key, value}, ...]` to object |

## Functions

| Function | Description |
|----------|-------------|
| `map(f)` | Apply filter to each array element |
| `select(f)` | Keep values where `f` is truthy |
| `sort_by(f)` | Sort array by extracted key |
| `group_by(f)` | Group array elements by key |
| `unique_by(f)` | Remove duplicates by key |
| `min_by(f)` | Element with minimum key |
| `max_by(f)` | Element with maximum key |
| `has("key")` | Check if object has key |
| `split("delim")` | Split string into array |
| `join("sep")` | Join array into string |
| `startswith("s")` | Check if string starts with prefix |
| `endswith("s")` | Check if string ends with suffix |
| `contains(value)` | Check if value contains another |
| `with_entries(f)` | Transform object entries |

## Building

```bash
cargo build --release
```

## License

MIT
