Skip to content

Repository files navigation

Bad Juju

An LSP-powered, editor-agnostic front-end for Jujutsu.

Overview

Bad Juju exposes Jujutsu VCS operations through the Language Server Protocol, so any LSP-capable editor can show jj status, conflict markers, and change information inline.

Repository Structure

server/          Rust LSP server (tower-lsp)
clients/
  vscode/        VS Code extension
docs/            Design documents
samples/         Example jj repos used for testing

Example Output

When the user runs Bad Juju: Open status window, the server regenerates .jj/badjuju/status.jujutsu and opens it in the editor. The buffer combines jj status, the working-copy stack, and a one-screen command reference:

STATUS:

The working copy has no changes.
Working copy  (@) : kpkzwvqm 909679d0 (empty) (no description set)
Parent commit (@-): xorwskru 66bfbfdf feat(neovim): buffer-local keymaps on status.jj and log.jj (bad-juju-jb3)

STACK: ancestors(reachable(@, mutable()), 2)

@  kpkzwvqm 909679d0 1min stephen@example.com
│  (empty) (no description set)
○  xorwskru 66bfbfdf 2min stephen@example.com
│  feat(neovim): buffer-local keymaps on status.jj and log.jj (bad-juju-jb3)
○  mmqmovmy 0eca5029 3min stephen@example.com
│  feat(neovim): make status.jj/log.jj buffers read-only and reload in place on refresh (bad-juju-uga)
◆  spxlzwpr 18d66a82 20min stephen@example.com main
│  fix(ci): set DESTDIR when installing redo (bad-juju-d16)
~

COMMAND REFERENCE:
n     new change
l     open log
d     describe
s     squash file at cursor into parent
U     unsquash file at cursor from parent into child   (or Ctrl+K U when vim shadows U)
a     abandon commit at cursor (or working copy)
u     jj undo (revert last operation)
=     toggle --stat on the stack log
g     refresh
q     close

Bad Juju: Open log window writes .jj/badjuju/log.jujutsu. The first line is an editable REVSET: header — change it and save to re-run the query. The JJ:-prefixed lines are shortcut revsets you can apply by placing the cursor on the line and pressing Enter:

REVSET: @
JJ: Mutable:  ancestors(reachable(@, mutable()), 2)
JJ: Stack:    (immutable_heads()..@)::

OUTPUT:

@  kpkzwvqm 909679d0 1min stephen@example.com
│  (empty) (no description set)
~

COMMAND REFERENCE:
Edit REVSET above and save to re-run the query.
Place the cursor on a shortcut line and press Enter to apply it.
a     abandon commit at cursor

Editor Setup

VS Code

Install the extension from the marketplace or build it locally (see clients/vscode/README.md). Open a Jujutsu repo and run Bad Juju: Open status window from the command palette (Ctrl+Shift+P / Cmd+Shift+P).

Neovim

See clients/neovim/README.md for installation and configuration. Once the LSP is wired up, run:

:lua require('badjuju').execute('badjuju.status')

Or use the default keymap (<leader>js or whichever binding you configure).

Helix

See clients/helix/README.md for the languages.toml snippet. Once badjuju is on your PATH, open the status buffer with:

hx "$(badjuju status)"

Prerequisites

Note

If you don’t want to install redo, the repo ships a self-contained ./do shell script as a drop-in fallback. Every redo <target> in this document can be run as ./do <target> instead (e.g. ./do all, ./do test, ./do check).

Building

pnpm install
redo               # or: ./do all

Testing

redo test

Development

To work on Bad Juju locally:

  1. Install the prerequisites listed above, including redo (brew install redo on macOS).

  2. Install JS dependencies and build the workspace:

    pnpm install
    redo
  3. Install the badjuju server binary to your Cargo bin directory (~/.cargo/bin):

    redo server/install

    The build configuration (debug or release) is read from the configuration file at the repo root.

  4. Iterate on the VS Code extension:

    1. Open the clients/vscode directory in VS Code (open it as the workspace root, not the repo root, so the launch config and package.json scripts resolve correctly).

    2. Press kbd:[F5] to launch an Extension Development Host. The checked-in .vscode/launch.json runs the build task first (pnpm run build) and then loads the freshly built extension. Open a Jujutsu repo inside the host window and run a command such as Bad Juju: Open status window from the command palette to exercise the extension.

    3. After editing clients/vscode/src/, stop the Extension Development Host and press kbd:[F5] again (or run pnpm run watch for an incremental rebuild and reload via Developer: Reload Window in the host).

  5. Before committing, run the CI-equivalent check (formatting, clippy, tests, Biome):

    redo check

About

A Jujutsu client for all editors, inspired by Matklad's description of an LSP-powered VCS integration

Resources

Stars

9 stars

Watchers

1 watching

Forks

Releases

Contributors

Languages