Skip to content

Conversation

spectral54
Copy link
Contributor

When $PAGER is set in the environment, jj uses that instead of the default (:builtin on Windows, less -FRX everywhere else). Commonly, users will have PAGER=less in their environment for various reasons, and this is respected by jj. This means that every jj command, even one that only outputs one or two lines, will still invoke a full screen pager. It also means that every jj command which uses escape sequences for color, which is most of them, will be output through a pager that doesn't handle that well, so users see output that looks like this, which isn't very readable:

ESC[1mESC[38;5;2m@ESC[0m  ESC[1mESC[38;5;13mspmESC[38;5;8mwzlkq...

To fix this issue that new users stumble upon, ignore $PAGER from the environment, and always use our per-platform default. Users can override this and select whatever pager they want by setting ui.pager in their jj config.

This seems like the least bad option for resolving #3502. The cases I considered were:

  1. User doesn't have PAGER set. No change.
  2. User has PAGER=less in their environment. We'll still run less, just with -FRX, so this seems fine. This case is surprisingly common.
  3. User has PAGER set because they prefer another pager. We'll ignore that preference and run less -FRX.
  4. User has PAGER set because less isn't available on their platform. This is uncommon except for Windows, where we'll run :builtin instead of less -FRX by default anyway.

This may cause some users who have intentionally set and configured PAGER to be frustrated that we aren't respecting that value, but it's generally not possible to respect that value in all cases and have a consistent and usable experience out of the box for the majority of users.

Alternatives considered

  1. Disable color and OSC8 hyperlinks if PAGER is set, since we can't be sure the pager supports the color codes.
  2. Don't paginate by default if PAGER is set. This seems counterintuitive, but would at least resolve the problem. Users would assume that the jj CLI doesn't support paginating, and either wrap it in a pager themselves (this is a bad outcome) or find ui.pager and change the setting.
  3. Set LESS (iff it's not set already), then invoke PAGER. This means that users setting things like LESS=i breaks our output as well, and cases where PAGER isn't 'less' aren't fixed.

Fixes #3502

Checklist

If applicable:

  • I have updated CHANGELOG.md
  • I have updated the documentation (README.md, docs/, demos/)
  • I have updated the config schema (cli/src/config-schema.json)
  • I have added/updated tests to cover my changes

When `$PAGER` is set in the environment, jj uses that instead of the
default (`:builtin` on Windows, `less -FRX` everywhere else). Commonly,
users will have `PAGER=less` in their environment for various reasons,
and this is respected by jj. This means that every jj command, even one
that only outputs one or two lines, will still invoke a full screen
pager. It also means that every jj command which uses escape sequences
for color, which is most of them, will be output through a pager that
doesn't handle that well, so users see output that looks like this,
which isn't very readable:

```
ESC[1mESC[38;5;2m@ESC[0m  ESC[1mESC[38;5;13mspmESC[38;5;8mwzlkq...
```

To fix this issue that new users stumble upon, ignore `$PAGER` from the
environment, and always use our per-platform default. Users can override
this and select whatever pager they want by setting ui.pager in their jj
config.

This seems like the least bad option for resolving jj-vcs#3502. The cases I
considered were:

1. User doesn't have `PAGER` set. No change.
2. User has `PAGER=less` in their environment. We'll still run `less`,
just with `-FRX`, so this seems fine. This case is surprisingly common.
3. User has `PAGER` set because they prefer another pager. We'll ignore
that preference and run `less -FRX`.
4. User has `PAGER` set because `less` isn't available on their
platform. This is uncommon except for Windows, where we'll run
`:builtin` instead of `less -FRX` by default anyway.

This may cause some users who have intentionally set and configured
`PAGER` to be frustrated that we aren't respecting that value, but it's
generally not possible to respect that value in all cases _and_ have a
consistent and usable experience out of the box for the majority of
users.

#### Alternatives considered

1. Disable color and OSC8 hyperlinks if `PAGER` is set, since we can't
be sure the pager supports the color codes.
2. Don't paginate by default if `PAGER` is set. This seems
counterintuitive, but would at least resolve the problem. Users would
assume that the `jj` CLI doesn't support paginating, and either wrap it
in a pager themselves (this is a bad outcome) or find `ui.pager` and
change the setting.
3. Set `LESS` (iff it's not set already), then invoke `PAGER`. This
means that users setting things like `LESS=i` breaks our output as well,
and cases where `PAGER` isn't 'less' aren't fixed.

Fixes jj-vcs#3502
@spectral54 spectral54 requested a review from a team as a code owner October 23, 2025 01:10
} else if let Ok(value) = env::var("EDITOR") {
layer.set_value("ui.editor", value).unwrap();
}
// [#3502] Intentionally NOT respecting $PAGER here.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to update at least config.md

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated config.md.

- `diff.format`

* `jj` now ignores `$PAGER` set in the environment. To override the default
pager, set this via the `ui.pager` config instead.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think it's useful to suggest running jj config set --user ui.pager "$PAGER" here for users who have the variable set?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think here we can (I'd be wary about doing this in a deprecation warning because it'll likely be run blindly and perpetuate problems). We could also theoretically suggest something like:

jj config set --user ui.pager '["sh", "-c", "$PAGER"]'

to make jj respect the $PAGER value as it is in the environment when executing jj (instead of locking it in). I'm really reluctant to suggeset this because it relies on sh and I really don't think this is going to come up often at all :)

Copy link
Contributor

@PhilipMetzger PhilipMetzger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a deprecation process question and a minor nit

Comment on lines -673 to -675
if let Ok(value) = env::var("PAGER") {
layer.set_value("ui.pager", value).unwrap();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I think we can sensibly deprecate this in 3 releases, so currently adding a warning here may be the option before straight up removing it. I'm up making the removal processes shorter if you deem this to hard for Google.

} else if let Ok(value) = env::var("EDITOR") {
layer.set_value("ui.editor", value).unwrap();
}
// [#3502] Intentionally NOT respecting $PAGER here.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Move the comment to the place where you removed the code and explain the decision a bit more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Setting PAGER=less in the environment causes ANSI escape sequences to appear by default

3 participants