pallets/click#3777

Forward PAGER parameters to the temp file pager and tokenize less raw-mode detection

3 files changed +227 −12

Summary

_tempfilepager now receives cmd_params and runs the pager as [cmd_path, *cmd_params, tempfile]. Before, it ran [cmd_path, tempfile] and dropped flags from PAGER. On Windows, PAGER="less -R" now runs less -R on the temporary file.

_pipepager now decides whether less already shows raw color through a new helper, _less_uses_raw_mode. The helper shlex-splits LESS, appends cmd_params, and accepts only dash-prefixed short-option clusters containing r/R or the exact --raw-control-chars token. The old check matched any r or R anywhere in the joined string. The less match now compares cmd_path.stem, so less.exe counts, and it casefolds on Windows. LESS=-R is still injected only when both LESS and cmd_params are empty.

Changes

Flow

get_pager_file resolves PAGER into a command path and params. _pager_contextmanager routes them to either the pipe backend or the temp file backend. The pipe backend asks _less_uses_raw_mode whether to enable color.
Components and connections

Components

  • get_pager_file entry point
  • _pager_contextmanager function, changed src/click/_termui_impl.py
  • _pipepager function, changed src/click/_termui_impl.py
  • _less_uses_raw_mode function, changed src/click/_termui_impl.py
  • _tempfilepager function, changed src/click/_termui_impl.py
  • pager subprocess external service

Connections

  • get_pager_file → _pager_contextmanager (color)
  • _pager_contextmanager → _pipepager (cmd_path, cmd_params)
  • _pager_contextmanager → _tempfilepager (cmd_path, cmd_params)
  • _pipepager → _less_uses_raw_mode (LESS, cmd_params)
  • _pipepager → pager subprocess (Popen with env LESS)
  • _tempfilepager → pager subprocess (argv params + file)

Risks

0 high · 1 medium · 2 low

  1. Medium

    Dash-less LESS values like FRX no longer enable color

    src/click/_termui_impl.py:537–543

    less accepts option letters in LESS without a leading dash; git, for example, sets LESS=FRX. The old check found R in that string and set color = True. The new loop skips tokens that do not start with -, so FRX returns False. LESS is non-empty, so -R is not injected either. ANSI codes are then stripped where they used to be shown.

  2. Low

    Abbreviated --raw long option not detected

    src/click/_termui_impl.py:538–540

    less accepts unambiguous long-option prefixes such as --raw. The new code requires the exact --raw-control-chars token, so PAGER="less --raw" leaves color off. The old substring check enabled it.

  3. Low

    Option arguments in short clusters cause false positives

    src/click/_termui_impl.py:541–543

    Any dash token containing r counts, including values attached to options such as -pError (search pattern) or -+R (reset R to default). These report raw mode as on when less does not use it, so ANSI output passes through unfiltered.

Test checklist

0 of 6 done