This is an automated email from the ASF dual-hosted git repository.

aradzinski pushed a commit to branch NLPCRAFT-108
in repository https://gitbox.apache.org/repos/asf/incubator-nlpcraft.git


The following commit(s) were added to refs/heads/NLPCRAFT-108 by this push:
     new 9fd3578  WIP.
9fd3578 is described below

commit 9fd357817a6f22f223746c04e606db584d81eb2e
Author: Aaron Radzinski <[email protected]>
AuthorDate: Tue Aug 25 23:12:42 2020 -0700

    WIP.
---
 .../nlpcraft/common/ascii/NCAsciiTable.scala       | 152 +++++++++++++++++----
 .../model/tools/cmdline/NCCommandLine.scala        |  74 +++++++---
 .../nlpcraft/common/ascii/NCAsciiTableSpec.scala   |   6 +-
 3 files changed, 182 insertions(+), 50 deletions(-)

diff --git 
a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/ascii/NCAsciiTable.scala 
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/ascii/NCAsciiTable.scala
index db86fec..6bde0cf 100644
--- 
a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/ascii/NCAsciiTable.scala
+++ 
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/ascii/NCAsciiTable.scala
@@ -33,9 +33,10 @@ class NCAsciiTable {
     /**
      * Cell style.
      */
-    private sealed case class Style(
+    private final case class Style(
         var leftPad: Int = 1, // >= 0
         var rightPad: Int = 1, // >= 0
+        var maxWidth: Int = Int.MaxValue, // > 0
         var align: String = "center" // center, left, right
         ) {
         /** Gets overall padding (left + right). */
@@ -57,7 +58,7 @@ class NCAsciiTable {
                 for (e ← sty.split(',')) {
                     val a = e.split(":")
 
-                    assume(a.length == 2, s"Invalid cell style: ${e.trim}")
+                    require(a.length == 2, s"Invalid cell style: ${e.trim}")
 
                     val a0 = a(0).trim
                     val a1 = a(1).trim
@@ -65,20 +66,29 @@ class NCAsciiTable {
                     a0 match {
                         case "leftPad" ⇒ cs.leftPad = a1.toInt
                         case "rightPad" ⇒ cs.rightPad = a1.toInt
-                        case "align" ⇒ cs.align = a1
+                        case "maxWidth" ⇒ cs.maxWidth = a1.toInt
+                        case "align" ⇒ cs.align = a1.toLowerCase
                         case _ ⇒ assert(assertion = false, s"Invalid style: 
${e.trim}")
                     }
                 }
             }
 
+            require(cs.leftPad >= 0, "Style 'leftPad' must >= 0.")
+            require(cs.rightPad >= 0, "Style 'rightPad' must >= 0.")
+            require(cs.maxWidth > 0, "Style 'maxWidth' must > 0.")
+            require(cs.align == "center" || cs.align == "left" || cs.align == 
"right", "Style 'align' must be 'left', 'right' or 'center'.")
+
             cs
         }
     }
 
     /**
      * Cell holder.
+     *
+     * @param style
+     * @param lines Lines that are already cut up per `style`, if required.
      */
-    private sealed case class Cell(style: Style, lines: Seq[String]) {
+    private final case class Cell(style: Style, lines: Seq[String]) {
         // Cell's calculated width including padding.
         lazy val width: Int =
             if (height > 0)
@@ -97,8 +107,8 @@ class NCAsciiTable {
         top: Int = 0,
         right: Int = 0,
         bottom: Int = 0,
-        left: Int = 0) {
-    }
+        left: Int = 0
+    )
 
     // Table drawing symbols.
     private val HDR_HOR = "="
@@ -119,31 +129,28 @@ class NCAsciiTable {
     private var margin = Margin()
 
     /**
-     * Flag indicating whether or not to draw inside horizontal lines
+     * Global flag indicating whether or not to draw inside horizontal lines
      * between individual rows.
      */
     var insideBorder = false
 
     /**
-     * Flag indicating whether of not to automatically draw horizontal lines
+     * Global Flag indicating whether of not to automatically draw horizontal 
lines
      * for multiline rows.
      */
     var autoBorder = true
 
     /**
-     * Maximum width of the cell. If any line in the cell exceeds this width
-     * it will be cut in two or more lines.
-     *
-     * '''NOTE''': it doesn't include into account the padding. Only the actual
-     * string length is counted.
+     * If lines exceeds the style's maximum width it will be broken up
+     * either by nearest space (by whole words) or mid-word.
      */
-    var maxCellWidth: Int = Int.MaxValue
+    var breakUpByWords = true
 
-    /** Row style. */
-    var rowStyle: String = DFLT_ROW_STYLE
+    /** Default row style. */
+    var defaultRowStyle: String = DFLT_ROW_STYLE
 
-    /** Header style. */
-    var headerStyle: String = DFLT_HEADER_STYLE
+    /** Default header style. */
+    var defaultHeaderStyle: String = DFLT_HEADER_STYLE
 
     // Dash drawing.
     private def dash(ch: String, len: Int): String = (for (_ ← 1 to len) yield 
ch).mkString("")
@@ -198,6 +205,25 @@ class NCAsciiTable {
     }
 
     /**
+     * Adds row (one or more row cells) with a given style.
+     *
+     * @param style Style to use.
+     * @param cells Row cells. For multi-line cells - use `Seq(...)`.
+     */
+    def +/(style: String, cells: Any*): NCAsciiTable = {
+        startRow()
+
+        cells foreach {
+            case i: Iterable[_] ⇒ addStyledRowCell(style, i.iterator.toSeq: _*)
+            case a ⇒ addStyledRowCell(style, a)
+        }
+
+        endRow()
+
+        this
+    }
+
+    /**
       * Adds row.
       *
       * @param cells Row cells.
@@ -227,12 +253,39 @@ class NCAsciiTable {
     }
 
     /**
+     * Adds styled header (one or more header cells).
+     *
+     * @param style Style to use.
+     * @param cells Header cells. For multi-line cells - use `Seq(...)`.
+     */
+    def #/(style: String, cells: Any*): NCAsciiTable = {
+        cells foreach {
+            case i: Iterable[_] ⇒ addStyledHeaderCell(style, i.iterator.toSeq: 
_*)
+            case a ⇒ addStyledHeaderCell(style, a)
+        }
+
+        this
+    }
+
+    /**
       * Adds headers.
       *
       * @param cells Header cells.
       */
     def addHeaders(cells: java.util.List[Any]): NCAsciiTable = {
-        cells.asScala.foreach(p ⇒ addHeaderCell(p))
+        cells.asScala.foreach(addHeaderCell(_))
+
+        this
+    }
+
+    /**
+     * Adds headers with the given `style`.
+     *
+     * @param style Style top use.
+     * @param cells Header cells.
+     */
+    def addStyledHeaders(style: String, cells: java.util.List[Any]): 
NCAsciiTable = {
+        cells.asScala.foreach(addHeaderCell(style, _))
 
         this
     }
@@ -245,31 +298,72 @@ class NCAsciiTable {
 
     /**
      *
+     * @param maxWidth
+     * @param lines
+     * @return
+     */
+    private def breakUpByNearestSpace(maxWidth: Int, lines: Seq[Any]): 
Seq[String] = ???
+
+    /**
+     *
      * @param style
      * @param lines
      * @return
      */
-    private def mkRowCell(style: String, lines: Any*): Cell =
-        Cell(Style(style), (for (line ← lines) yield 
x(line).grouped(maxCellWidth)).flatten)
+    private def mkRowCell(style: String, lines: Any*): Cell = {
+        val st = Style(style)
+
+        Cell(
+            st,
+            if (breakUpByWords)
+                breakUpByNearestSpace(st.maxWidth, lines)
+            else
+                (for (line ← lines) yield x(line).grouped(st.maxWidth)).flatten
+        )
+    }
 
     /**
-     * Adds single header cell.
+     * Adds single header cell with the default style..
      *
      * @param lines One or more cell lines.
      */
     def addHeaderCell(lines: Any*): NCAsciiTable = {
-        hdr :+= mkRowCell(headerStyle, lines: _*)
+        hdr :+= mkRowCell(defaultHeaderStyle, lines: _*)
 
         this
     }
 
     /**
-     * Adds single row cell.
+     * Adds single row cell with the default style.
      *
      * @param lines One or more row cells. Multiple lines will be printed on 
separate lines.
      */
     def addRowCell(lines: Any*): NCAsciiTable = {
-        curRow :+= mkRowCell(rowStyle, lines: _*)
+        curRow :+= mkRowCell(defaultRowStyle, lines: _*)
+
+        this
+    }
+
+    /**
+     * Adds single header cell with the default style..
+     *
+     * @param style Style to use.
+     * @param lines One or more cell lines.
+     */
+    def addStyledHeaderCell(style: String, lines: Any*): NCAsciiTable = {
+        hdr :+= mkRowCell(style, lines: _*)
+
+        this
+    }
+
+    /**
+     * Adds single row cell with the default style.
+     *
+     * @param style Style to use.
+     * @param lines One or more row cells. Multiple lines will be printed on 
separate lines.
+     */
+    def addStyledRowCell(style: String, lines: Any*): NCAsciiTable = {
+        curRow :+= mkRowCell(style, lines: _*)
 
         this
     }
@@ -352,12 +446,12 @@ class NCAsciiTable {
         for (_ ← 0 until margin.top)
             tbl ++= " \n"
 
-        def mkRow(crs: String, cor: String): String =
+        def mkAsciiLine(crs: String, cor: String): String =
             s"${space(margin.left)}$crs${dash(cor, 
tableW)}$crs${space(margin.right)}\n"
 
         // Print header, if any.
         if (isHdr) {
-            tbl ++= mkRow(HDR_CRS, HDR_HOR)
+            tbl ++= mkAsciiLine(HDR_CRS, HDR_HOR)
 
             for (i ← 0 until hdrH) {
                 // Left margin and '|'.
@@ -378,10 +472,10 @@ class NCAsciiTable {
                 tbl ++= s"${space(margin.right)}\n"
             }
 
-            tbl ++= mkRow(HDR_CRS, HDR_HOR)
+            tbl ++= mkAsciiLine(HDR_CRS, HDR_HOR)
         }
         else
-            tbl ++= mkRow(ROW_CRS, ROW_HOR)
+            tbl ++= mkAsciiLine(ROW_CRS, ROW_HOR)
 
         // Print rows, if any.
         if (rows.nonEmpty) {
diff --git 
a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/cmdline/NCCommandLine.scala
 
b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/cmdline/NCCommandLine.scala
index 26458cd..f215ccd 100644
--- 
a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/cmdline/NCCommandLine.scala
+++ 
b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/cmdline/NCCommandLine.scala
@@ -21,6 +21,8 @@ import org.apache.nlpcraft.common.ascii.NCAsciiTable
 import org.apache.nlpcraft.common.util.NCUtils
 import org.apache.nlpcraft.common.version.NCVersion
 
+import scala.collection.mutable
+
 /**
  * 'nlpcraft' script entry point.
  */
@@ -33,12 +35,13 @@ object NCCommandLine extends App {
 
     // Single CLI command.
     case class Command(
+        id: String,
         names: Seq[String],
         synopsis: String,
-        desc: String = "",
+        desc: Option[String] = None,
         params: Seq[Parameter] = Seq.empty,
         examples: Seq[Example] = Seq.empty,
-        body: Seq[String] => Unit
+        body: (Command, Seq[String]) => Unit
     ) {
         final val extNames = names.flatMap(name => // Safeguard against 
"common" errors.
             Seq(
@@ -49,6 +52,15 @@ object NCCommandLine extends App {
                 s"\\$name"
             )
         )
+
+        /**
+         *
+         * @param paramId
+         * @param cliParams
+         * @return
+         */
+        def isParamPresent(paramId: String, cliParams: Seq[String]): Boolean =
+            params.find(_.id == 
paramId).get.names.intersect(cliParams).nonEmpty
     }
     // Single command's example.
     case class Example(
@@ -57,6 +69,7 @@ object NCCommandLine extends App {
     )
     // Single command's parameter.
     case class Parameter(
+        id: String,
         names: Seq[String],
         valueDesc: Option[String] = None,
         arity: (Int, Int) = (1, 1), // Mandatory by default.
@@ -66,22 +79,24 @@ object NCCommandLine extends App {
     // All supported commands.
     private final val CMDS = Seq(
         Command(
+            id = "help",
             names = Seq("help", "?"),
             synopsis = s"Displays manual page for $SCRIPT_NAME.",
-            desc =
-                s"""
-                   |By default, without '-all' or '-cmd' parameters, displays 
the abbreviated form of manual
-                   |only listing the commands without parameters or examples.
-                   |""".stripMargin,
+            desc = Some(
+                s"By default, without '-all' or '-cmd' parameters, displays 
the abbreviated form of manual " +
+                s"only listing the commands without parameters or examples."
+            ),
             body = cmdHelp,
             params = Seq(
                 Parameter(
+                    id = "cmd",
                     names = Seq("--cmd", "-c"),
                     valueDesc = Some("{cmd}"),
                     arity = (0, 3),
                     desc = "Set of commands to show the manual for."
                 ),
                 Parameter(
+                    id = "all",
                     names = Seq("--all", "-a"),
                     arity = (0, 1),
                     desc = "Flag to show full manual for all commands."
@@ -89,25 +104,27 @@ object NCCommandLine extends App {
             )
         ),
         Command(
+            id = "ver",
             names = Seq("version", "ver"),
             synopsis = s"Displays version of $SCRIPT_NAME runtime.",
             body = cmdVersion
         ),
         Command(
+            id = "repl",
             names = Seq("repl"),
             synopsis = s"Starts '$SCRIPT_NAME' in interactive REPL mode.",
             body = cmdRepl
         )
     )
 
-    private final val HELP_CMD = CMDS.find(_.names.contains("help")).get
-    private final val DFLT_CMD = CMDS.find(_.names.contains("repl")).get
+    private final val HELP_CMD = CMDS.find(_.id == "help").get
+    private final val DFLT_CMD = CMDS.find(_.id ==  "repl").get
 
     /**
-     *
+     * @param cmd Command descriptor.
      * @param params Parameters, if any, for this command.
      */
-    private def cmdHelp(params: Seq[String]): Unit = {
+    private def cmdHelp(cmd: Command, params: Seq[String]): Unit = {
         log(
             s"""    |NAME
                     |    $SCRIPT_NAME - command line interface to control 
NLPCraft.
@@ -118,14 +135,33 @@ object NCCommandLine extends App {
                     |COMMANDS""".stripMargin
         )
 
-        if (params.isEmpty) {
-            val tbl = NCAsciiTable().margin(left = 4)
+        val tbl = NCAsciiTable().margin(left = 4)
+
+        tbl.maxCellWidth = 55
 
+        if (params.isEmpty)  // Default - show abbreviated help.
             CMDS.foreach(cmd => tbl += (cmd.names.mkString(", "), 
cmd.synopsis))
+        else if (cmd.isParamPresent("all", params)) { // Show a full format 
help for all commands.
+            CMDS.foreach(cmd => {
+                var lines = mutable.Buffer.empty[String]
 
-            log(tbl.toString)
+                if (cmd.desc.isDefined)
+                    lines += cmd.synopsis + " " + cmd.desc.get
+                else
+                    lines += cmd.synopsis
+
+                lines += ""
+
+                if (cmd.params.nonEmpty) {
+                    lines += "PARAMETERS"
+                }
+
+                tbl += (cmd.names.mkString(", "), lines)
+            })
         }
 
+        log(tbl.toString)
+
 
 
 
@@ -178,17 +214,19 @@ object NCCommandLine extends App {
 
     /**
      *
+     * @param cmd Command descriptor.
      * @param params Parameters, if any, for this command.
      */
-    private def cmdRepl(params: Seq[String]): Unit = {
+    private def cmdRepl(cmd: Command, params: Seq[String]): Unit = {
 
     }
 
     /**
      *
+     * @param cmd Command descriptor.
      * @param params Parameters, if any, for this command.
      */
-    private def cmdVersion(params: Seq[String]): Unit = {
+    private def cmdVersion(cmd: Command, params: Seq[String]): Unit = {
         // Nothing - common header with version will be printed before anyways.
     }
 
@@ -215,12 +253,12 @@ object NCCommandLine extends App {
         log()
 
         if (args.isEmpty)
-            NCCommandLine.DFLT_CMD.body(Seq.empty)
+            NCCommandLine.DFLT_CMD.body(DFLT_CMD, Seq.empty)
         else {
             val cmdName = args.head
 
             CMDS.find(_.extNames.contains(cmdName)) match {
-                case Some(cmd) => cmd.body(args.tail)
+                case Some(cmd) => cmd.body(cmd, args.tail)
                 case None =>
                     error(s"Unknown command: $cmdName")
                     errorHelp()
diff --git 
a/nlpcraft/src/test/scala/org/apache/nlpcraft/common/ascii/NCAsciiTableSpec.scala
 
b/nlpcraft/src/test/scala/org/apache/nlpcraft/common/ascii/NCAsciiTableSpec.scala
index 8081b9d..2abb4b1 100644
--- 
a/nlpcraft/src/test/scala/org/apache/nlpcraft/common/ascii/NCAsciiTableSpec.scala
+++ 
b/nlpcraft/src/test/scala/org/apache/nlpcraft/common/ascii/NCAsciiTableSpec.scala
@@ -27,7 +27,7 @@ class NCAsciiTableSpec {
     def test() {
         val t = NCAsciiTable()
         
-        t.headerStyle = "leftPad: 10, rightPad: 5"
+        t.defaultHeaderStyle = "leftPad: 10, rightPad: 5"
 
         t.margin(5, 5, 5, 5)
 
@@ -45,7 +45,7 @@ class NCAsciiTableSpec {
     def testWithSequenceHeader() {
         val t = NCAsciiTable()
         
-        t.headerStyle = "leftPad: 10, rightPad: 5"
+        t.defaultHeaderStyle = "leftPad: 10, rightPad: 5"
 
         t.margin(5, 5, 5, 5)
 
@@ -65,7 +65,7 @@ class NCAsciiTableSpec {
 
         val t = NCAsciiTable()
         
-        t.headerStyle = "leftPad: 10, rightPad: 5"
+        t.defaultHeaderStyle = "leftPad: 10, rightPad: 5"
 
         t #= (Seq("Header 1", "Header 2", "Header 3"): _*)
 

Reply via email to