Skip to content

FR: jj fix --no-index to format stdin in a text editor #8077

@cormacrelf

Description

@cormacrelf

Is your feature request related to a problem? Please describe.

I configure my formatters in jj config. Then I go and configure formatters in my editor, trying to make them match. These things never quite match. For example, say you have a jj fix script to add a header to every source file. You may have rustfmt configured, but it is much more complicated to get a script like that into your editor's format button. Plus, some of your rust projects might use rustfmt +nightly, some may not, etc.

JJ is good at configuring and running formatters, better (at what it handles, filesets) than almost any formatter in existence. But we can't use it as a formatter itself! It would be nice to just configure Vim to run a file through jj fix no matter the filetype. Then I could define formatting in one place, and get all the jj fix magic in the editor itself.

There is also an issue with testing jj fix configuration that this could solve. It's hard to do, you have to do a complicated dance with jj fix -s @, and a lot of jj undo and squashing. I've experienced writing a formatting wrapper script that matched itself, failed with exit code 0, and truncated itself.

Describe the solution you'd like

# for an editor configuration:
# format stdin as if it were a file at a given path in the repo, onto stdout
... | jj fix --no-index --stdin-filepath src/main.rs | ...

# test out your jj fix configuration, emits on stdout
jj fix --no-index src/main.rs | rg 'Copyright (C) 2025 The JJ Authors'

# or directly rewrite a list of paths in-place without updating @ commit
# should use filesets i think, because jj fix config has to match against
# filesets to determine tools to run
jj fix --no-index --in-place src/main.rs

--no-index would always imply --ignore-working-copy.

The command would be following the vein of git diff --no-index fileA fileB, which uses git config for diff tools but does not read the git index. That's exactly what this is, so I think it should have the same flag name.

For a text editor, you would configure it like this:

-- none-ls configuration for neovim

local h = require("null-ls.helpers")
local methods = require("null-ls.methods")

local FORMATTING = methods.internal.FORMATTING

return h.make_builtin({
   name = "jj_fix",
   meta = {
      url = "https://jj-vcs.github.io/jj/latest/config/#code-formatting-and-other-file-content-transformations",
      description = "Format with jj fix",
   },
   method = FORMATTING,
   filetypes = {},
   generator_opts = {
      command = "jj",
      args = { "fix", "--no-index", "--stdin-filepath", "$FILENAME" },
      to_stdin = true,
   },
   factory = h.formatter_factory,
})

(Side note it would also be nice to share the formatter configs with other JJ users in the same repo, can we do that with config #includes yet? Seems no)

Describe alternatives you've considered
Keep livin' in the past

Additional context
None

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions