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
How can I paginate picocli results like Git does it? #1252
Comments
Just to be clear, I do have some code lying around that attempts to do what is described in the Twitter thread, I simply didn't get it to function as expected just yet. Most of the noteworthy code is quite small : private fun executionStrategy(parseResult: ParseResult): Int {
println("in there")
val processBuilder = ProcessBuilder("less")
val process = processBuilder.start()
this.spec.commandLine().out = PrintWriter(process.outputStream)
return RunLast().execute(parseResult)
}
companion object{
@JvmStatic
fun main(args: Array<String>){
val app = SwaCLIPaginateDummy()
exitProcess(CommandLine(app)
.setExecutionStrategy(app::executionStrategy)
.execute(*args))
}
} I tried to strip down as many things as possible in there. Example to be ran with the "planets" argument to trigger the printing of the dummy string |
Thank you for raising this! EDIT: sorry, on Twitter I said |
No hurry really, this is not a priority. I keep tinkering with it and I think someone used to the library might be going faster. Thanks! |
No success yet. One small thing: @Command(name = "planets", description = ["Search for planets"])
class PlanetsCommandPaginateDummy : Callable<Int> {
@Spec
lateinit var spec: CommandSpec
override fun call(): Int {
spec.commandLine().out.println(dummyLongString)
return 0
}
} I tried writing to a temp file, but no joy yet... |
I got it to work with a temp file and by calling package nl.lengrand.swacli
import picocli.CommandLine
import picocli.CommandLine.*
import picocli.CommandLine.Model.CommandSpec
import java.io.*
import java.nio.file.Files
import java.util.concurrent.Callable
import java.util.concurrent.TimeUnit
import kotlin.system.exitProcess
const val dummyLongString =
"""
Found 60 total results for that query
Showing 10 results
Tatooine
Climate : arid
Diameter (km) : 10465
Gravity : 1 standard
Orbital period : 304
Alderaan
Climate : temperate
Diameter (km) : 12500
Gravity : 1 standard
Orbital period : 364
Yavin IV
Climate : temperate, tropical
Diameter (km) : 10200
Gravity : 1 standard
Orbital period : 4818
Hoth
Climate : frozen
Diameter (km) : 7200
Gravity : 1.1 standard
Orbital period : 549
Dagobah
Climate : murky
Diameter (km) : 8900
Gravity : N/A
Orbital period : 341
Bespin
Climate : temperate
Diameter (km) : 118000
Gravity : 1.5 (surface), 1 standard (Cloud City)
Orbital period : 5110
Endor
Climate : temperate
Diameter (km) : 4900
Gravity : 0.85 standard
Orbital period : 402
Naboo
Climate : temperate
Diameter (km) : 12120
Gravity : 1 standard
Orbital period : 312
Coruscant
Climate : temperate
Diameter (km) : 12240
Gravity : 1 standard
Orbital period : 368
Kamino
Climate : temperate
Diameter (km) : 19720
Gravity : 1 standard
Orbital period : 463
"""
@Command(
mixinStandardHelpOptions = true,
subcommands = [PlanetsCommandPaginateDummy::class, HelpCommand::class]
)
class SwaCLIPaginateDummy : Callable<Int> {
@Spec
lateinit var spec: CommandSpec
private fun executionStrategy(parseResult: ParseResult): Int {
println("in there")
val file = Files.createTempFile("pico", ".tmp").toFile()
this.spec.commandLine().out = PrintWriter(FileWriter(file), true)
println("writing to ${file}")
val result = RunLast().execute(parseResult)
this.spec.commandLine().out.flush() // may not be needed
println("starting `less ${file.absolutePath}`")
val processBuilder = ProcessBuilder("less", file.absolutePath).inheritIO()
val process = processBuilder.start()
process.waitFor()
return result
}
override fun call(): Int {
spec.commandLine().usage(System.out)
return 0
}
companion object{
@JvmStatic
fun main(args: Array<String>){
val app = SwaCLIPaginateDummy()
exitProcess(CommandLine(app)
.setExecutionStrategy(app::executionStrategy)
.execute(*args))
}
}
}
@Command(name = "planets", description = ["Search for planets"])
class PlanetsCommandPaginateDummy : Callable<Int> {
@Spec
lateinit var spec: CommandSpec
override fun call(): Int {
spec.commandLine().out.println(dummyLongString)
return 0
}
} |
Thanks for the help! I didn't think about using a temp file, good idea I can confirm indeed that this does the trick. A few limitations I can see when testing :
Thanks again, I don't expect you to test all the comments here :), I'm listing them in case someone else ends up here at some point. I'll be looking if I can improve those myself. |
Ok, so getting around the usage and help part is quite simple. You gotta avoid the mambo jambo in case no subcommand is detected. private fun executionStrategy(parseResult: ParseResult): Int {
if (!parseResult.hasSubcommand())
return RunLast().execute(parseResult)
val file = Files.createTempFile("pico", ".tmp").toFile()
this.spec.commandLine().out = PrintWriter(FileWriter(file), true)
val result = RunLast().execute(parseResult)
this.spec.commandLine().out.flush() // may not be needed
val processBuilder = ProcessBuilder("less", file.absolutePath).inheritIO()
val process = processBuilder.start()
process.waitFor()
return result
} would work in that case. It could become more complex in a real life application. |
Thanks for all the help @remkop. I used your changes and the working example can be found here https://github.com/jlengrand/swacli/blob/main/src/main/kotlin/nl/lengrand/swacli/SwaCLIPaginate.kt. It is possible to play around with the less options to get more or less info in the output for those that would want to dive deeper into it :). |
Hey there,
I am creating an issue based on a question I raised a few weeks back on Twitter.
I currently have a fun little API that returns results from the Star Wars API. Depending on the query, it returns a lot of results.
I would like to be able to present the results paginated, like Git does it. Like @remkop already mentions it on Twitter, it would be best to leverage already existing infrastructure on the system rather than implement a local pagination.
I've been fiddling around with code for the past few days but I'm afraid I didn't manage to come up with anything conclusive yet. The twitter thread seems to mention
IExecutionHandler
but I couldn't find anything related in the source code of picocli, so I have been looking at creating a customIParseResultHandler
instead. Past that, I also ran into stdin forwarding issues withProcessBuilder
, so it's hard to come with a minimal reproducible example.Any help moving in the right direction would be most appreciated!
The text was updated successfully, but these errors were encountered: