This is an automated email from the ASF dual-hosted git repository.
slawrence pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/daffodil.git
The following commit(s) were added to refs/heads/master by this push:
new 66dda26 Update jansi to 2.3.2 and JLine to 3.19.0
66dda26 is described below
commit 66dda260ce09c9963cbf1c8146712739f7590afc
Author: Scala Steward <[email protected]>
AuthorDate: Thu Mar 18 14:08:48 2021 +0100
Update jansi to 2.3.2 and JLine to 3.19.0
- In TestCLIDebugger.scala and TestCLIParsing.scala, remove
-Djline.terminal=jline.UnsupportedTerminal since JLine 3 doesn't
understand that option anymore. A possible replacement is
-Dorg.jline.terminal.dumb=true, but JLine 3 may not need that option.
- In bash-template, remove -Djline.terminal=jline.UnixTerminal since
JLine 3 doesn't understand that option and probably doesn't need it
anymore.
- Replace JLine 2 imports and calls with JLine 3 imports and calls,
including replacing ConsoleReader with LineReader, calling close on
reader.getTerminal instead of reader itself, and passing prompt to
reader.readLine.
- Rewrite JLine debugger completer using new JLine 3 features
(ParsedLine, Candidate objects, etc.) to support improved tab
completion, including typo detection. Greatly simplifies the code as
well.
- Moves all jline related code to daffodil-cli so it is no longer a
dependency to daffodil jars fetched from maven--now it's only needed
when using the CLI.
---
daffodil-cli/bin.LICENSE | 8 +-
.../apache/daffodil/debugger/TestCLIDebugger.scala | 7 +-
.../apache/daffodil/parsing/TestCLIParsing.scala | 2 +-
.../daffodil/debugger/CLIDebuggerRunner.scala | 86 ++++++++++++++++++---
daffodil-cli/src/templates/bash-template | 1 -
.../daffodil/debugger/InteractiveDebugger.scala | 87 ----------------------
project/Dependencies.scala | 4 +-
7 files changed, 85 insertions(+), 110 deletions(-)
diff --git a/daffodil-cli/bin.LICENSE b/daffodil-cli/bin.LICENSE
index f5fe806..d75313f 100644
--- a/daffodil-cli/bin.LICENSE
+++ b/daffodil-cli/bin.LICENSE
@@ -756,14 +756,14 @@ is subject to the terms and conditions of the following
licenses.
on the JDOM Project, please see <http://www.jdom.org/>.
This product bundles 'JLine', including the following files:
- - lib/jline.jline-<VERSION>.jar
+ - lib/org.jline.jline-<VERSION>.jar
These files are available under a BSD-3-Clause license. For details, see
- https://github.com/jline/jline2/blob/master/LICENSE.txt
+ https://github.com/jline/jline3/blob/master/LICENSE.txt
- Copyright (c) 2002-2016, the original author or authors.
+ Copyright (c) 2002-2018, the original author or authors.
All rights reserved.
- http://www.opensource.org/licenses/bsd-license.php
+ https://opensource.org/licenses/BSD-3-Clause
Redistribution and use in source and binary forms, with or
without modification, are permitted provided that the following
diff --git
a/daffodil-cli/src/it/scala/org/apache/daffodil/debugger/TestCLIDebugger.scala
b/daffodil-cli/src/it/scala/org/apache/daffodil/debugger/TestCLIDebugger.scala
index 7202392..cb845c3 100644
---
a/daffodil-cli/src/it/scala/org/apache/daffodil/debugger/TestCLIDebugger.scala
+++
b/daffodil-cli/src/it/scala/org/apache/daffodil/debugger/TestCLIDebugger.scala
@@ -28,12 +28,7 @@ import org.apache.daffodil.CLI.Util
class TestCLIdebugger {
- val DAFFODIL_JAVA_OPTS = Map("DAFFODIL_JAVA_OPTS" -> "-Xms256m -Xmx2048m
-Djline.terminal=jline.UnsupportedTerminal -Dfile.encoding=UTF-8")
- // Dubugging tests were not executing under Windows and especially under
Eclipse
- // due to the use of a non-interactive console.
- // Set the DAFFODIL_JAVA_OPTS environment variable for Debugger tests to
specify
- // the use of an unsupported terminal:
-Djline.terminal=jline.UnsupportedTerminal
- // Also added a Java option to specify the character encoding:
-Dfile.encoding=UTF-8
+ val DAFFODIL_JAVA_OPTS = Map("DAFFODIL_JAVA_OPTS" -> "-Xms256m -Xmx2048m
-Dfile.encoding=UTF-8")
@Test def test_3385_CLI_Debugger_invalidExpressions(): Unit = {
val schemaFile =
Util.daffodilPath("daffodil-test/src/test/resources/org/apache/daffodil/section06/entities/charClassEntities.dfdl.xsd")
diff --git
a/daffodil-cli/src/it/scala/org/apache/daffodil/parsing/TestCLIParsing.scala
b/daffodil-cli/src/it/scala/org/apache/daffodil/parsing/TestCLIParsing.scala
index 94cde1f..33b6b59 100644
--- a/daffodil-cli/src/it/scala/org/apache/daffodil/parsing/TestCLIParsing.scala
+++ b/daffodil-cli/src/it/scala/org/apache/daffodil/parsing/TestCLIParsing.scala
@@ -1044,7 +1044,7 @@ class TestCLIparsing {
val xcatalogFile =
Util.daffodilPath("daffodil-cli/src/it/resources/org/apache/daffodil/CLI/xcatalog_invalid.xml")
val testXcatalogFile = if (Util.isWindows) Util.cmdConvert(xcatalogFile)
else xcatalogFile
- val DAFFODIL_JAVA_OPTS = Map("DAFFODIL_JAVA_OPTS" ->
("-Dxml.catalog.files=" + testXcatalogFile + " -Xms256m -Xmx2048m
-Djline.terminal=jline.UnsupportedTerminal -Dfile.encoding=UTF-8"))
+ val DAFFODIL_JAVA_OPTS = Map("DAFFODIL_JAVA_OPTS" ->
("-Dxml.catalog.files=" + testXcatalogFile + " -Xms256m -Xmx2048m
-Dfile.encoding=UTF-8"))
val shell = Util.startIncludeErrors("", envp = DAFFODIL_JAVA_OPTS)
diff --git
a/daffodil-cli/src/main/scala/org/apache/daffodil/debugger/CLIDebuggerRunner.scala
b/daffodil-cli/src/main/scala/org/apache/daffodil/debugger/CLIDebuggerRunner.scala
index df07059..7c8528c 100644
---
a/daffodil-cli/src/main/scala/org/apache/daffodil/debugger/CLIDebuggerRunner.scala
+++
b/daffodil-cli/src/main/scala/org/apache/daffodil/debugger/CLIDebuggerRunner.scala
@@ -18,10 +18,20 @@
package org.apache.daffodil.debugger
import java.io.File
+
+import scala.collection.JavaConverters._
import scala.io.Source
-import jline.console.ConsoleReader
+
+import org.jline.reader.Candidate
+import org.jline.reader.Completer
+import org.jline.reader.LineReader
+import org.jline.reader.LineReaderBuilder
+import org.jline.reader.ParsedLine
+
class CLIDebuggerRunner(cmdsIter: Iterator[String]) extends
InteractiveDebuggerRunner {
+ private val prompt = "(debug) "
+
def this() {
this(Iterator.empty)
}
@@ -34,18 +44,16 @@ class CLIDebuggerRunner(cmdsIter: Iterator[String]) extends
InteractiveDebuggerR
this(seq.iterator)
}
- var reader: Option[ConsoleReader] = None
+ var reader: Option[LineReader] = None
def init(id: InteractiveDebugger): Unit = {
- val r = new ConsoleReader()
- r.setPrompt("(debug) ")
- r.addCompleter(id.DebugCommandBase.completer)
- r.setExpandEvents(false)
+ val completer = new CLIDebuggerCompleter(id)
+ val r = LineReaderBuilder.builder().completer(completer).build()
reader = Some(r)
}
def fini(): Unit = {
- reader.map { _.close }
+ reader.map { _.getTerminal.close }
reader = None
}
@@ -55,10 +63,10 @@ class CLIDebuggerRunner(cmdsIter: Iterator[String]) extends
InteractiveDebuggerR
if (line.length > 0) {
reader.get.getHistory.add(line)
}
- println("%s%s".format(reader.get.getPrompt, line))
+ println("%s%s".format(prompt, line))
line
} else {
- val line = reader.get.readLine
+ val line = reader.get.readLine(prompt)
if (line == null) "quit" else line
}
cmd.trim
@@ -68,3 +76,63 @@ class CLIDebuggerRunner(cmdsIter: Iterator[String]) extends
InteractiveDebuggerR
println(" " + line)
}
}
+
+class CLIDebuggerCompleter(id: InteractiveDebugger) extends Completer {
+
+ def complete(reader: LineReader, line: ParsedLine, candidates:
java.util.List[Candidate]): Unit = {
+ // JLine3 completely parses the line, taking care of delmiters/quotes/etc.,
+ // and stores it in the ParsedLine, with delimeted fields split up in to
the
+ // line.words array. The last item in this array is the thing we are
+ // trying to autocomplete. Everything preceeding that last word (i.e.
+ // line.words.init) are the subcommands, which determines what the possible
+ // candidates are of that last word.
+ val cmds = line.words.asScala.init
+
+ // iterate over the list of commands to find the last subcommand which is
+ // used to determine what possible candidates there are
+ val optCmd = cmds.foldLeft(Some(id.DebugCommandBase):
Option[id.DebugCommand]) { case (optCurCmd, nextCmdName) =>
+ optCurCmd match {
+ case Some(id.DebugCommandBase.Info) => {
+ // We found the info command, even if there are more command names
+ // after that, we are going to ignore them and just keep the Info
+ // command. This lets use provide and autocomplete multiple info
+ // commands at once and complete only the last one, e.g. "info foo
+ // bar baz"
+ optCurCmd
+ }
+ case Some(cmd) => {
+ // We have the name for the next command, try to find the
+ // associated subcommand of the current DebugCommand. If we don't
+ // find one, it just means they user typed something that's not a
+ // valid command and we no command to use for completing
+ val nextCmd = cmd.subcommands.find { _.name == nextCmdName }
+ nextCmd
+ }
+ case None => {
+ // We previously failed to find a next command, likely because one
+ // of the subcommands was misspelled. That means we'll have no idea
+ // how to complete the last word, so we'll have no candidates
+ None
+ }
+ }
+ }
+
+ optCmd match {
+ case Some(cmd) => {
+ // We found a command used for autocompleting. All subcommands of the
+ // last found command are potential completion candidates. If there
+ // are no subcommands, then there are no candidates. Of these
+ // canidates, JLine will filter out any candidates that do not match
+ // the last word so we don't have to do that. It may also uses these
+ // candidates if it looks like there is a type in the word being
+ // completed, so it's a bit smarter than just doing .startsWith. We
+ // let Jline figure that out.
+ cmd.subcommands.foreach { sub => candidates.add(new
Candidate(sub.name)) }
+ }
+ case None => {
+ // We found words that weren't actually subcommands, so we don't know
+ // how to complete this last thing. We have no candidates
+ }
+ }
+ }
+}
diff --git a/daffodil-cli/src/templates/bash-template
b/daffodil-cli/src/templates/bash-template
index ebe6783..31ccc76 100755
--- a/daffodil-cli/src/templates/bash-template
+++ b/daffodil-cli/src/templates/bash-template
@@ -71,7 +71,6 @@ if uname -a | grep -qi cygwin
then
# if run from cygwin, convert unix paths to windows paths
CLASSPATH=$(cygpath -apw "$CLASSPATH")
- JOPTS="$JOPTS -Djline.terminal=jline.UnixTerminal"
fi
exec java $JOPTS -cp "$CLASSPATH" "$MAINCLASS" "$@"
diff --git
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/debugger/InteractiveDebugger.scala
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/debugger/InteractiveDebugger.scala
index 42dfb0c..2194262 100644
---
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/debugger/InteractiveDebugger.scala
+++
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/debugger/InteractiveDebugger.scala
@@ -19,12 +19,6 @@ package org.apache.daffodil.debugger
import java.io.File
-import scala.collection.JavaConverters._
-
-import jline.console.completer.AggregateCompleter
-import jline.console.completer.Completer
-import jline.console.completer.StringsCompleter
-
import org.apache.daffodil.BasicComponent
import org.apache.daffodil.api.DaffodilTunables
import org.apache.daffodil.dpath.ExpressionEvaluationException
@@ -532,56 +526,6 @@ class InteractiveDebugger(runner:
InteractiveDebuggerRunner, eCompilers: Express
}
}
- class DebugCommandCompleter(dc: DebugCommand) extends Completer {
- val subcommandsCompleter = new
AggregateCompleter(dc.subcommands.sortBy(_.name).map(_.completer): _*)
-
- def getCompleteString(args: String) = {
- // just remove leading whitespace
- val trimmed = args.replaceAll("^\\s+", "")
- trimmed
- }
-
- def complete(buffer: String, cursor: Int, candidates:
java.util.List[CharSequence]): Int = {
- val cmds = buffer.replaceAll("^\\s+", "").split("(?= )", 2).toList
- val (cmd, args) = cmds match {
- case c :: rest => rest match {
- case a :: Nil => (c, a)
- case Nil => (c, "")
- case _ => Assert.impossible("cmd/args were split incorrectly")
- }
- case Nil => ("", "")
- }
-
- if (args != "") {
- if (dc == cmd) {
- val completeString = getCompleteString(args)
- val subcandidates = new java.util.ArrayList[CharSequence]
- val newCursor = subcommandsCompleter.complete(completeString,
cursor, subcandidates)
- val seq = subcandidates.asScala
- seq.foreach(c => candidates.add(c))
- buffer.lastIndexOf(completeString) + newCursor
- } else {
- -1
- }
- } else {
- if (dc.name.startsWith(cmd)) {
- candidates.add(dc.name + " ")
- buffer.lastIndexOf(cmd)
- } else {
- -1
- }
- }
- }
- }
-
- def completer: Completer = {
- if (subcommands.isEmpty) {
- new StringsCompleter(name)
- } else {
- new DebugCommandCompleter(this)
- }
- }
-
// This ensures that there are no naming conflicts (e.g. short form names
// conflict). This is really just a sanity check, and really only needs to
// be run whenever names change or new commands are added.
@@ -685,19 +629,6 @@ class InteractiveDebugger(runner:
InteractiveDebuggerRunner, eCompilers: Express
newState
}
- override def completer: Completer = {
- new DebugCommandCompleter(this) {
- override def complete(buffer: String, cursor: Int, candidates:
java.util.List[CharSequence]): Int = {
- val cmd = buffer.replaceAll("^\\s+", "")
- val subcandidates = new java.util.ArrayList[CharSequence]
- val newCursor = subcommandsCompleter.complete(cmd, cursor,
subcandidates)
- val seq = subcandidates.asScala
- seq.foreach(c => candidates.add(c))
- buffer.lastIndexOf(cmd) + newCursor
- }
- }
- }
-
object Break extends DebugCommand with DebugCommandValidateSingleArg {
val name = "break"
val desc = "create a breakpoint"
@@ -1284,24 +1215,6 @@ class InteractiveDebugger(runner:
InteractiveDebuggerRunner, eCompilers: Express
DebugState.Pause
}
- override def completer = new InfoCommandCompleter(this)
-
- class InfoCommandCompleter(dc: DebugCommand) extends
DebugCommandCompleter(dc) {
- override def getCompleteString(args: String) = {
- val lastInfoCommand =
- if (args.endsWith(" ")) {
- "" // this allows the subcommand completers to match anything
- } else {
- // otherwise, it will only match against the last info argument,
- // so 'info foo bar inf\t' will match 'inf' to infoset. The
- // default getComplteString would match against 'foo bar inf',
- // which wouldn't find anything
- args.split("\\s+").last
- }
- lastInfoCommand
- }
- }
-
trait InfoDiffable {
/**
* Outputs any differences between previousProcessorState and state for
the mixed in debugger command
diff --git a/project/Dependencies.scala b/project/Dependencies.scala
index 7717272..874e977 100644
--- a/project/Dependencies.scala
+++ b/project/Dependencies.scala
@@ -28,7 +28,6 @@ object Dependencies {
"xerces" % "xercesImpl" % "2.12.1",
"xml-resolver" % "xml-resolver" % "1.2",
"commons-io" % "commons-io" % "2.8.0",
- "jline" % "jline" % "2.14.6",
"com.typesafe" % "config" % "1.4.1"
)
@@ -39,7 +38,8 @@ object Dependencies {
)
lazy val cli = Seq(
- "org.fusesource.jansi" % "jansi" % "1.18",
+ "org.fusesource.jansi" % "jansi" % "2.3.2",
+ "org.jline" % "jline" % "3.19.0",
"org.rogach" %% "scallop" % "4.0.2",
"net.sf.expectit" % "expectit-core" % "0.9.0" % "it,test"
)