From 4b3c5abf18c72deaf233869b6a09b74fac4869e8 Mon Sep 17 00:00:00 2001 From: mattirn Date: Mon, 24 Dec 2018 23:17:36 +0100 Subject: [PATCH] moved JLine3 example to picocli-shell-jline3 --- picocli-shell-jline2/build.gradle | 1 - picocli-shell-jline3/README.md | 155 ++++++++++++++++++ picocli-shell-jline3/build.gradle | 84 ++++++++++ .../shell/jline3/PicocliJLineCompleter.java | 1 - .../picocli/shell/jline3/example/Example.java | 0 settings.gradle | 1 + 6 files changed, 240 insertions(+), 2 deletions(-) create mode 100644 picocli-shell-jline3/README.md create mode 100644 picocli-shell-jline3/build.gradle rename {picocli-shell-jline2 => picocli-shell-jline3}/src/main/java/picocli/shell/jline3/PicocliJLineCompleter.java (97%) rename {picocli-shell-jline2 => picocli-shell-jline3}/src/test/java/picocli/shell/jline3/example/Example.java (100%) diff --git a/picocli-shell-jline2/build.gradle b/picocli-shell-jline2/build.gradle index 1a47d618..6ba7864b 100644 --- a/picocli-shell-jline2/build.gradle +++ b/picocli-shell-jline2/build.gradle @@ -12,7 +12,6 @@ sourceCompatibility = 1.5 dependencies { compile rootProject compile "jline:jline:$jlineVersion" - compile "org.jline:jline:$jline3Version" testCompile "junit:junit:$junitVersion" } diff --git a/picocli-shell-jline3/README.md b/picocli-shell-jline3/README.md new file mode 100644 index 00000000..97fd7d78 --- /dev/null +++ b/picocli-shell-jline3/README.md @@ -0,0 +1,155 @@ +

picocli

+ + +# Picocli Shell JLine3 - build interactive shells with ease + +Picocli Shell JLine3 contains components and documentation for building +interactive shell command line applications with JLine 3 and picocli. + +JLine and picocli complement each other very well and have little or none functional overlap. + +JLine provides interactive shell functionality but has no built-in command line parsing functionality. +What it does provide is a tokenizer for splitting a single command line String into an array of command line argument Strings. + +Given an array of Strings, picocli can execute a command or subcommand. +Combining these two libraries makes it easy to build powerful interactive shell applications. + + +## About JLine 3 + +[JLine 3](https://github.com/jline/jline3) is a well-known library for building interactive shell applications. +From the JLine [web site](https://github.com/jline/jline.github.io/blob/master/index.md): + +> JLine is a Java library for handling console input. It is similar in functionality to [BSD editline](http://www.thrysoee.dk/editline/) and [GNU readline](http://www.gnu.org/s/readline/) but with additional features that bring it in par with [ZSH line editor](http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html). + +## About picocli +Picocli is a Java command line parser with both an annotations API and a programmatic API, featuring usage help with ANSI colors, autocomplete and nested subcommands. + +The picocli user manual is [here](https://picocli.info), and the GitHub project is [here](https://github.com/remkop/picocli). + +## Command Completer +`PicocliJLineCompleter` is a small component that generates completion candidates to allow users to +get command line TAB auto-completion for a picocli-based application running in a JLine 2 shell. + +## Example + +```java +package picocli.shell.jline3.example; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.concurrent.Callable; +import java.util.concurrent.TimeUnit; + +import org.jline.reader.Completer; +import org.jline.reader.LineReader; +import org.jline.reader.LineReaderBuilder; +import org.jline.reader.impl.DefaultParser; +import org.jline.reader.impl.LineReaderImpl; +import org.jline.terminal.TerminalBuilder; +import org.jline.terminal.Terminal; +import org.jline.reader.MaskingCallback; + +import picocli.CommandLine; +import picocli.CommandLine.Command; +import picocli.CommandLine.Option; +import picocli.CommandLine.ParentCommand; +import picocli.shell.jline3.PicocliJLineCompleter; + +/** + * Example that demonstrates how to build an interactive shell with JLine3 and picocli. + * @since 3.7 + */ +public class Example { + + /** + * Top-level command that just prints help. + */ + @Command(name = "", description = "Example interactive shell with completion", + footer = {"", "Press Ctl-D to exit."}, + subcommands = {MyCommand.class, ClearScreen.class}) + static class CliCommands implements Runnable { + LineReaderImpl reader; + PrintWriter out; + + CliCommands() {} + + public void setReader(LineReader reader){ + this.reader = (LineReaderImpl)reader; + out = reader.getTerminal().writer(); + } + + public void run() { + out.println(new CommandLine(this).getUsageMessage()); + } + } + + /** + * A command with some options to demonstrate completion. + */ + @Command(name = "cmd", mixinStandardHelpOptions = true, version = "1.0", + description = "Command with some options to demonstrate TAB-completion" + + " (note that enum values also get completed)") + static class MyCommand implements Runnable { + @Option(names = {"-v", "--verbose"}) + private boolean[] verbosity = {}; + + @Option(names = {"-d", "--duration"}) + private int amount; + + @Option(names = {"-u", "--timeUnit"}) + private TimeUnit unit; + + @ParentCommand CliCommands parent; + + public void run() { + if (verbosity.length > 0) { + parent.out.printf("Hi there. You asked for %d %s.%n", amount, unit); + } else { + parent.out.println("hi!"); + } + } + } + + /** + * Command that clears the screen. + */ + @Command(name = "cls", aliases = "clear", mixinStandardHelpOptions = true, + description = "Clears the screen", version = "1.0") + static class ClearScreen implements Callable { + + @ParentCommand CliCommands parent; + + public Void call() throws IOException { + parent.reader.clearScreen(); + return null; + } + } + + public static void main(String[] args) { + try { + // set up the completion + CliCommands commands = new CliCommands(); + CommandLine cmd = new CommandLine(commands); + Terminal terminal = TerminalBuilder.builder().build(); + LineReader reader = LineReaderBuilder.builder() + .terminal(terminal) + .completer(new PicocliJLineCompleter(cmd.getCommandSpec())) + .parser(new DefaultParser()) + .build(); + commands.setReader(reader); + String prompt = "prompt> "; + String rightPrompt = null; + + // start the shell and process input until the user quits with Ctl-D + String line; + while (true) { + line = reader.readLine(prompt, rightPrompt, (MaskingCallback) null, null); + CommandLine.run(commands, line.split("\\s+")); + } + } catch (Throwable t) { + t.printStackTrace(); + } + } +} +``` diff --git a/picocli-shell-jline3/build.gradle b/picocli-shell-jline3/build.gradle new file mode 100644 index 00000000..6e2c2cbf --- /dev/null +++ b/picocli-shell-jline3/build.gradle @@ -0,0 +1,84 @@ +plugins { + id 'java' + id 'distribution' + id 'maven-publish' +} + +group 'info.picocli' +description 'Picocli Shell JLine2 - easily build interactive shell applications with JLine 2 and picocli.' +version "$projectVersion" +sourceCompatibility = 1.5 + +dependencies { + compile rootProject + compile "org.jline:jline:$jline3Version" + testCompile "junit:junit:$junitVersion" +} + +jar { + manifest { + attributes 'Specification-Title' : 'Picocli Shell JLine2', + 'Specification-Vendor' : 'Remko Popma', + 'Specification-Version' : version, + 'Implementation-Title' : 'Picocli Shell JLine2', + 'Implementation-Vendor' : 'Remko Popma', + 'Implementation-Version': version, + 'Automatic-Module-Name' : 'info.picocli.shell.jline2' + } +} + +ext { + bintrayBaseUrl = 'https://api.bintray.com/maven' + bintrayRepository = 'picocli' + bintrayPackage = 'picocli-shell-jline2' + bintrayUsername = System.getenv('BINTRAY_USER') + bintrayApiKey = System.getenv('BINTRAY_KEY') +} +publishing { + publications { + plugin(MavenPublication) { + from components.java + artifact sourcesJar + artifact testJar + artifact testSourcesJar + artifact javadocJar + pom.withXml { + def root = asNode() + root.appendNode('packaging', 'jar') + root.appendNode('name', 'picocli-shell-jline2') + root.appendNode('description', description) + root.appendNode('url', 'http://picocli.info') + root.appendNode('inceptionYear', '2018') + + def license = root.appendNode('licenses').appendNode('license') + license.appendNode('name', 'The Apache Software License, version 2.0') + license.appendNode('url', 'http://www.apache.org/licenses/LICENSE-2.0.txt') + license.appendNode('distribution', 'repo') + + def developer = root.appendNode('developers').appendNode('developer') + developer.appendNode('id', 'rpopma') + developer.appendNode('name', 'Remko Popma') + developer.appendNode('email', 'rpopma@apache.org') + + def scm = root.appendNode('scm') + scm.appendNode('connection', 'scm:git:https://github.com/remkop/picocli.git') + scm.appendNode('developerConnection', 'scm:git:ssh://github.com:remkop/picocli.git') + scm.appendNode('url', 'https://github.com/remkop/picocli/tree/master') + } + } + } + repositories { + maven { + name 'myLocal' + url "file://$rootDir/../repo/$bintrayUsername" + } + maven { + name 'Bintray' + url "$bintrayBaseUrl/$bintrayUsername/$bintrayRepository/$bintrayPackage" + credentials { + username = bintrayUsername + password = bintrayApiKey + } + } + } +} diff --git a/picocli-shell-jline2/src/main/java/picocli/shell/jline3/PicocliJLineCompleter.java b/picocli-shell-jline3/src/main/java/picocli/shell/jline3/PicocliJLineCompleter.java similarity index 97% rename from picocli-shell-jline2/src/main/java/picocli/shell/jline3/PicocliJLineCompleter.java rename to picocli-shell-jline3/src/main/java/picocli/shell/jline3/PicocliJLineCompleter.java index 6421d0fa..608f0482 100644 --- a/picocli-shell-jline2/src/main/java/picocli/shell/jline3/PicocliJLineCompleter.java +++ b/picocli-shell-jline3/src/main/java/picocli/shell/jline3/PicocliJLineCompleter.java @@ -1,6 +1,5 @@ package picocli.shell.jline3; -import org.jline.reader.impl.completer.ArgumentCompleter; import org.jline.reader.LineReader; import org.jline.reader.Completer; import org.jline.reader.Candidate; diff --git a/picocli-shell-jline2/src/test/java/picocli/shell/jline3/example/Example.java b/picocli-shell-jline3/src/test/java/picocli/shell/jline3/example/Example.java similarity index 100% rename from picocli-shell-jline2/src/test/java/picocli/shell/jline3/example/Example.java rename to picocli-shell-jline3/src/test/java/picocli/shell/jline3/example/Example.java diff --git a/settings.gradle b/settings.gradle index d92b1789..c7999ff9 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,6 @@ rootProject.name = 'picocli' include 'picocli-examples' include 'picocli-shell-jline2' +include 'picocli-shell-jline3' include 'picocli-codegen'