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"
   )

Reply via email to