We recently released a cross platform pager as a NuGet package Microsoft.PowerShell.Pager
. The intention is to use the Pager for Get-Help
and dynamic help.
The has been interest expressed in utilizing the Pager in a more general purpose way.
This issue is to discuss if the Pager should be distributed in some other form. Options on top of my mind in no priority order.
Something like, no intention of designing the cmdlet surface here.
Get-Process | Out-Pager
The behavior will be similar to a native pager like less
or more.com
.
Get-Process | pspager
Personally, I think an Out-Pager
cmdlet would be the most useful. If we can mimic some of the typical options from more
or less
as parmeters that'd be ideal, of course. IIRC there are some open issues around Out-Host -Paging that we should probably seek to fix for a new native pager implementation like this / ensure they aren't an issue in the new implementation.
A big part of the draw imo is halting the pipeline. Even with how janky Out-Host -Paging
is I still use it when I'm looking through results that are expensive to pull all at once. Being able to pause downstream ProcessRecord
invocations when the screen fills up is great.
More feedback from @jaykul @vexx32 @jhoneill in issue #13468
I wanna throw out that regardless of what route we take here, I want to see the new pager replace the pager used in Out-Host -Paging
(which we can't take out). We should only have one pager in the product :)
We should only have one pager in the product :)
I guess there are users who will prefer Unix less
. I hope we preserve the environment variable to pick up a preferred pager.
-Pager
switch in cmdlets. So my preference - only implement Out-Pager/Out-HostPager in 7.1 and then wait more feedback.
I wanna throw out that regardless of what route we take here, I want to see the new pager replace the pager used in
Out-Host -Paging
(which we can't take out). We should only have one pager in the product :)
In all my years using PowerShell I don't think I've used Out-host -paging
- I learned | more
- in about 1983 - and that's too much muscle memory to overturn (same applies to | clip
or ping
)
Windows PowerShell has more
as a function wrapping for more.com
and 7 just lets things flow through to the OS's more
and a linux user might well use less
Having just tested it , I can't imagine anyone who just wanted paging would | Out-host -paging
unless they had never heard of more
, writing an error to say you pressed Q... I can, sort of, see that there may some case where you want to know the user didn't look at everything but the muscle memory which says press ctrl+c defeats it.
A big part of the draw imo is halting the pipeline. Even with how janky
Out-Host -Paging
is I still use it when I'm looking through results that are expensive to pull all at once. Being able to pause downstreamProcessRecord
invocations when the screen fills up is great.
Even that is six of one and half a dozen of the other
1..1000 | %{ $_ ; sleep .2} | more
At one screenful you pause for a look, and then hit space for the next screenful and it's buffered and waiting. Downside ? Exiting with Q means waiting for the remaining rows; it needs ctrl + C
1..1000 | %{ $_ ; sleep .2} | out-host -Paging
Puts the brakes on; My hunch is most of the time, most people will want the machine to do the next part in the background while they're reviewing what has been done so far. But some of the people, some of the time will want "Don't do 51-100 until I have reviewed 1-50". I'm trying to think of a case where I'd stop after a screenful not review each item - at least for the first few items.
Having just tested it , I can't imagine anyone who just wanted paging would
| Out-host -paging
unless they had never heard ofmore
, writing an error to say you pressed Q... I can, sort of, see that there may some case where you want to know the user didn't look at everything but the muscle memory which says press ctrl+c defeats it.
Yeah it's pretty terrible, but that's why we're talking about improving it.
At one screenful you pause for a look, and then hit space for the next screenful and it's buffered and waiting. Downside ? Exiting with Q means waiting for the remaining rows; it needs ctrl + C
Nah it can throw PipelineStoppedException
.
My hunch is most of the time, most people will want the machine to do the next part in the background while they're reviewing what has been done so far.
Often retrieving a single page is quite quick while retrieving the entire result set is still expensive. Personally I have the opposite experience, the amount of times I'd have preferred the behavior you described is very rare.
I'm trying to think of a case where I'd stop after a screenful not review each item - at least for the first few items.
Often when exploring something interactively that returns a lot of results, you can tell whether you need to change your search criteria based on the first page. Also if you're fishing for a specific item with broad search criteria, you would want to stop processing the search once you spot what you're looking for.
@PowerShell/powershell-committee discussed this today and advises:
Out-Pager
cmdlet makes sense as Out-Host -Paging
is not discoverableOut-Pager
(or dynamic help in PSReadLine) should use the alternate screen buffer@SteveL-MSFT did the committee also say that Out-Host -Paging
should use the new pager?
@SteveL-MSFT
- We agree that
Out-Pager
cmdlet makes sense asOut-Host -Paging
is not discoverable
It is worth asking the question, why would a user prefer |Out-Pager
over |more
. ?
To give a parallel Test-NetConnection
has not replaced ping
for most use cases because (1) We already know ping
, as a universal command so the new command needs to _overturn a habit_. (2) most of the time we don't need to process objects returned - we don't achieve _benefit_ from changing, and (3) At 18 characters instead of 4 it doesn't offer _convenience_.
Another parallel is | clip
, which I use most days. Windows PowerShell (in V4 or V5) introduced a functionally identical Set-Clipboard
which is more typing for something doesn't work everywhere- | clip.exe
works in bash on Windows, cmd, and legacy PowerShell (which I still have to work with)
I'm not saying no one will ever prefer it, but before embarking on doing something because it's possible, there needs to be clarity on where it offers a gain (and where it doesn't try to), to justify using effort which could deliver something else. It can't be universal, something already does the job, so in what way is this doing the job better?
- It may make sense to have paging as a common feature, but did not agree on whether it's a common parameter or some other configuration/preference set by the user
Think very, _very_, very hard about introducing Do-not-return-objects-but-print-text
options. Some commands _do_ exist to put stuff onthe console for a human to read (format-table
, Get-Help
) and their _objects_ are seldom exploited.
But the thinking which says "-Paged
would be a good common parameter" would also say "-AsTable
, -AsList
and -AsStrings
would be good parameters" and is countered by the same logic which says no, use format-Table
, format-list
, or out-string
And again ask the question if / how / when -paged
gives a better solution than |more
.
@jhoneill the new pager and Out-Host -Paging
pager work in a PSReadLine keyhandler. more/less do not. The intention is to use this pager for dynamic help feature in PSRL.
@TylerLeonhardt
PSRL might be sufficient justification for doing a native pager - meaning PS users, generally speaking, not using it doesn't matter much. Improving the pager in out-host
makes sense, Wrapping that in a PAGE function (any name <= 4 chars), makes more sense to me than adding a cmdlet to do the same job.
My call to avoid -DoNotReturnObjectsButPrintText
common parameters stands though.
@jhoneill the new pager and
Out-Host -Paging
pager work in a PSReadLine keyhandler. more/less do not.
They work, you just need to pipe to Out-Default
:
Set-PSReadLineKeyHandler -Chord 'ctrl+p' -ScriptBlock {
& { gps | more } | Out-Default
}
Doesn't work over remoting though.
@jhoneill personally I'd just prefer to have a native paging cmdlet so I don't have to bother checking what pager(s) might be available on a given system.
A short alias to it is simple enough if it's a separate cmdlet. Out-Host -Paging
already being part of an existing cmdlet tends to mean that adding further options to it will become cumbersome (and discovering them from a function would then either be impossible or require additional unnecessary dev work to manually copy parameters to the function.)
Out-Host -Paging
should IMO be a compatibility effort, maintained for existing use and the basic paging functionality, but pagers tend to expose additional options that would be better suited to their own cmdlet than making bloated parameter sets to expand on Out-Host -Paging
in my opinion.
@jhoneill personally I'd just prefer to have a native paging cmdlet so I don't have to bother checking what pager(s) might be available on a given system.
I think we might talking at cross-purposes. |more
works in pwsh, windows PowerShell, even legacy versions, cmd, bash, whatever. Introducing out-Pager
means I first have to stop and think "What pager is available in this shell" and type the longer | Out-Pager
. So why wouldn't I do |more
?
A short alias to it is simple enough if it's a separate cmdlet.
At least that removes the need for more typing to get the same effect. I agree onOut-Host -Paging
more
only works if that pager is available in the system, from what I can see. It's not provided by PowerShell. Is it usually available? Sure. Always? 馃し
And if you're working in different shells, remembering a slightly different pager command is the _least_ of one's concerns, surely. 馃槀
And even if you forget, as you pointed out, | more
would still work in the majority of cases, so you're not losing out there either.
I would say that it is beneficial for PowerShell to treat everything as cmdlets - either as true cmdlet or as a wrapper cmdlet.
Mostly I don't disagree with what's been said above: there are already a few good pagers out there, and they _mostly_ work fine in PowerShell ... except for this one thing ...
An actual PowerShell pager needs to be able to deal with output in alternative streams. Otherwise, why bother?
There are few things more frustrating and confusing than piping output mixed with some verbose/debug/warnings/errors to | more
and having each page just those few lines more than a page, thanks to the uncounted alternate stream lines.
(I know I can write it as *>&1 | more
but then Warning, Verbose, Debug streams are indistinguishable from the output, it's just a different mess)
Hmm. A pager implementation could be made to format non-output streams according to their typical standard formatting, though, since non-output streams have their own discrete types. That would make it possible to do something like *>&1 | Out-Pager
and have the pager still render them recognisably. Whether that should be a default or exposed in a different way... don't know.
more
only works if that pager is available in the system, from what I can see. It's not provided by PowerShell. Is it usually available? Sure. Always? 馃し
Every Microsoft operating system (certainly from DOS 3.1, including OS/2, NT3.1 and upwards, and Windows 9x) and every Unix based operating system from when I first used it in 1985, has supported |more and I've never seen it removed from a system. Any computer I've met which uses | supports more.
And if you're working in different shells, remembering a slightly different pager command is the _least_ of one's concerns, surely. 馃槀
It's not the least but one of many small concerns. Don't worry about is test-netconnection
, / Get-LocalGroupMember
/ Set-clipboard
valid here when Ping, net localgroup or clip do the job. Just like they did 20 years ago. There are cases where you want the Ping objects, or GroupMember objects, but for clipboard or more, where's the benefit.
And even if you forget, as you pointed out,
| more
would still work in the majority of cases, so you're not losing out there either.
My point is not _forgetting_. It's non-adoption.
One other point (regarding the -Pager
switch in Get-Help): we have "always" had a help
function which is just a proxy for Get-Help @PSBoundParameters | more
. In my opinion, that's the right way to deliver paging to help -- except that it should respect an environment variable for which pager to use!
We shouldn't be putting custom unique paging functionality into commands, because I want to use the pager which is the best, every time I use a pager (and that might not be your pager, but if you make it handle additional streams, it probably will be).
Hmm. A pager implementation could be made to format non-output streams according to their typical standard formatting, though, since non-output streams have their own discrete types.
This could be handled similar to how Out-Null
is currently implemented. During PipelineProcessor
init it can check if the downstream command is Out-Pager
. If it is then do MergeMyResults(PipelineResultTypes.All, PipelineResultTypes.Output)
Downside is that it might change the order of some things due to the table formatters delay, though the displayed order would be more "correct".
It's not the least but one of many small concerns. Don't worry about is
test-netconnection
, /Get-LocalGroupMember
/Set-clipboard
valid here when Ping, net localgroup or clip do the job. Just like they did 20 years ago. There are cases where you want the Ping objects, or GroupMember objects, but for clipboard or more, where's the benefit.
For clip
I recently forced myself to start using scb
because of extra new line characters and encoding issues. ping
is sort of a loaded scenario because it Test-Connection
was pretty wonk for some time (ty @vexx32 for fixing it).
Also all the talk about how native more
/less
variants are better but none of those work over remoting still right? It's still just Out-Host -Paging
that works?
Most helpful comment
I wanna throw out that regardless of what route we take here, I want to see the new pager replace the pager used in
Out-Host -Paging
(which we can't take out). We should only have one pager in the product :)