-
Couldn't load subscription status.
- Fork 762
cli: ignore $PAGER in environment by default
#7821
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this 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
| if let Ok(value) = env::var("PAGER") { | ||
| layer.set_value("ui.pager", value).unwrap(); | ||
| } |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason we need a deprecation process and multiple releases? I consider the current behavior to be a bug. The only ones who would benefit from a deprecation warning would be those that intentionally set $PAGER to some non-less value. I don't have any actual metrics, but this is likely relatively small (vanishingly small amongst the general population, but only 'relatively' small amongst early jj adopters, I'm assuming).
Contrast with the number of users broken by this bug, whose first experience with jj is that it's completely unusable and they start off with a very negative experience. We can override this at Google and never show the deprecation warning at all, so there's no pressure to shorten this time period from us. But as jj usage is growing outside of Google, I think we should have the out-of-the-box experience be the best it can be, even if it means a sudden change in behavior (a slight regression) for a small subset of current users.
(Also, I'm just not sure how to even implement the deprecation warning: we can't check here because we don't know what the value of ui.pager is going to be from the user's config; we can't check that $PAGER is set when using ui.pager, because if users follow the advice to preserve $PAGER, they'll set ui.pager to be $PAGER... what we'd need is a check when loading the user configs that ui.pager ISN'T set in that config layer but IS set in $PAGER; I don't know if we have anything like that kind of logic already)
cli/src/config.rs
Outdated
| } else if let Ok(value) = env::var("EDITOR") { | ||
| layer.set_value("ui.editor", value).unwrap(); | ||
| } | ||
| // [#3502] Intentionally NOT respecting $PAGER here. |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Elaborated a little bit and converted [#3502] to a link to the issue. I intentionally put it at the bottom because if someone is going to come and try to re-add $PAGER handling, they're most likely to put it at the bottom of the function, so it's more likely to be seen here.
Let me know if you disagree, I don't mind moving it back to the original location, it's where I had it originally.
|
I have mixed feelings about this (might go into more details later about various use-cases; I'm not sure how common they are or even a good idea), but it seems worth trying just to see if it makes people happier or angrier and from the general principle I like of trying to make more people's first impression of One suggestion I have is to create a new I'm not sure that this is absolutely necessary, but it seems like an easy addition with upsides. Update: There are two main motivations I have for suggesting this:
Now, I can quit Of course, I could configure |
Good idea. Done! |
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 restore the previous behavior by setting `ui.pager=:envpager` in their jj config, or they can of course select whichever pager they like if they want a different setting for `jj` vs. other commands. 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`, they'll need to discover `:envpager`. 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
| use crate::formatter::PlainTextFormatter; | ||
|
|
||
| const BUILTIN_PAGER_NAME: &str = ":builtin"; | ||
| const ENV_PAGER_NAME: &str = ":envpager"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: just ":env"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wondered about this, and thought that :envpager might be nice since it answers the question of "what part of the environment is relevant here?". Environment could also refer to a dotfile, or something weird.
But my opinion is not very strong, and :env is undeniably shorter. The downside of envpager is that it can be confused with pagerenv or env-pager. We can go with whatever you and Kyle agree on.
| Ok(Self::External(args)) | ||
| match (args.as_str(), env::var("PAGER")) { | ||
| (Some(BUILTIN_PAGER_NAME), _) => Ok(Self::Builtin(config.get("ui.streampager")?)), | ||
| (Some(ENV_PAGER_NAME), Ok(pager_env)) => Ok(Self::External((&pager_env).into())), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
":envpager" should be an error if $PAGER isn't set.
BTW, I personally don't think we need :envpager. Since the user has to configure it manually, they can just set their pager command as usual. I don't think it's common to temporarily override $PAGER. If they do, they can use sh -c $PAGER or something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The sh command is a good point. Apparently, this was already discussed in #7821 (comment).
I would still prefer having :env/:envpager. That sh command can take some quoting if you want to put it into a jj config set command and can be messed up by putting extra quotes around $PAGER, both mistakes resulting in subtle problems that may not be immediately apparent. It doesn't work on Windows.
But I'm not entirely sure; if your or others' preference against it is strong enough, we'll probably manage without :env as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My feeling is that many users who previously relied on $PAGER would be happy with the new default or configuring ui.pager to their preferred pager. Maybe we can add :envpager later if there are complaints about that?
BTW, I don't have concern about platform compatibility of sh -c because $PAGER is very Unix thing.
| [#7747](https://github.com/jj-vcs/jj/issues/7747) | ||
|
|
||
| * Fixed `PAGER` being set in the environment causing ANSI escape sequences to be | ||
| displayed to the terminal. [#3502](https://github.com/jj-vcs/jj/issues/3502) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I'd call this a bugfix. Perhaps delete this and add "See [#3502](...) for motivation" to the item in "Breaking Changes"?
| } | ||
| if !env::var("NO_COLOR").unwrap_or_default().is_empty() { | ||
| // "User-level configuration files and per-instance command-line arguments | ||
| // should override $NO_COLOR." https://no-color.org/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re commit message: a reminder for later to sync it up with what the commit actually does before merging. Right now, it doesn't mention :envpager AFAICT.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I think I didn't read it carefully enough. Perhaps swap the first and the second paragraph of the commit message? Or just keep it as is if you prefer, it's fine.
| layer.set_value("ui.editor", value).unwrap(); | ||
| } | ||
| // Intentionally NOT respecting $PAGER here as it's very likely to create a bad | ||
| // out-of-the-box experience for users, see http://github.com/jj-vcs/jj/issues/3502. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd perhaps edit this to "... as it often creates a bad out-of-the-box experience for new users, ..."
| Which pager to use can be customized by setting `ui.pager`. When choosing a | ||
| pager, ensure that it either supports color codes or that you disable color (see | ||
| [Colorizing output](#colorizing-output)). | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd add something like: "Unlike some other Unix tools, jj does not respect the PAGER environment variable by default. You can set ui.pager to :envpager to make jj respect PAGER.
| Ok(Self::External(args)) | ||
| match (args.as_str(), env::var("PAGER")) { | ||
| (Some(BUILTIN_PAGER_NAME), _) => Ok(Self::Builtin(config.get("ui.streampager")?)), | ||
| (Some(ENV_PAGER_NAME), Ok(pager_env)) => Ok(Self::External((&pager_env).into())), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's probably better to error if env::var("PAGER") is not OK, or is there some reason not to?
This might require finagling with the error types a little bit, you could change the return type to CommandError or perhaps abuse ConfigGetError::NotFound("`PAGER` environment variable"). The former is probably nicer.
| By default, jj will paginate output that would scroll off the screen. It does | ||
| this by passing output through `less -FRX` on most platforms (on Windows it uses | ||
| [the pager](#builtin-pager) that is built-in to jj). It is possible the default | ||
| will change to `:builtin` for all platforms in the future. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd delete the last sentence, since you haven't introduced the ui.pager variable yet, and this PR takes us in a different direction anyway. If we decide to, we can change the default to :builtin later either way.
$PAGER in environment$PAGER in environment by default
When
$PAGERis set in the environment, jj uses that instead of the default (:builtinon Windows,less -FRXeverywhere else). Commonly, users will havePAGER=lessin 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:To fix this issue that new users stumble upon, ignore
$PAGERfrom 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:
PAGERset. No change.PAGER=lessin their environment. We'll still runless, just with-FRX, so this seems fine. This case is surprisingly common.PAGERset because they prefer another pager. We'll ignore that preference and runless -FRX.PAGERset becauselessisn't available on their platform. This is uncommon except for Windows, where we'll run:builtininstead ofless -FRXby default anyway.This may cause some users who have intentionally set and configured
PAGERto 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
PAGERis set, since we can't be sure the pager supports the color codes.PAGERis set. This seems counterintuitive, but would at least resolve the problem. Users would assume that thejjCLI doesn't support paginating, and either wrap it in a pager themselves (this is a bad outcome) or findui.pagerand change the setting.LESS(iff it's not set already), then invokePAGER. This means that users setting things likeLESS=ibreaks our output as well, and cases wherePAGERisn't 'less' aren't fixed.Fixes #3502
Checklist
If applicable:
CHANGELOG.mdREADME.md,docs/,demos/)cli/src/config-schema.json)