Skip to content

Commit

Permalink
Remove Kiama dependency (#13)
Browse files Browse the repository at this point in the history
* Add sublime text

* Remove Kiama

* Incorporate Rob's comments.

* short circuit union if it fits the layout

* Update README to remove Kiama.

* Revert README to master version.
  • Loading branch information
coltfred authored and bmjames committed Dec 8, 2016
1 parent 7635165 commit a6497c3
Show file tree
Hide file tree
Showing 14 changed files with 280 additions and 63 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
.idea*/
target/
*sublime-project
*sublime-workspace
1 change: 0 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,4 @@ scalacOptions ++= List(

libraryDependencies ++= List(
"org.scalaz" %% "scalaz-core" % "7.2.7",
"com.googlecode.kiama" %% "kiama" % "1.8.0",
"org.scalacheck" %% "scalacheck" % "1.12.6" % "test")
2 changes: 0 additions & 2 deletions src/main/scala/net/bmjames/opts/builder/Builder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ import scalaz.syntax.foldable._
import scalaz.std.option._
import scalaz.std.list._

import org.kiama.output.PrettyPrinter.Doc

private[opts] trait Builder {

// Since Scalaz has no Read type class, there is no 'auto' function here.
Expand Down
4 changes: 1 addition & 3 deletions src/main/scala/net/bmjames/opts/extra/Extra.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ import scalaz.{Const, ~>, -\/, \/-}
import scalaz.syntax.applicative._
import scalaz.syntax.semigroup._

import org.kiama.output.{PrettyPrinter => PP}

private[opts] trait Extra {

/** A hidden "helper" option which always fails */
Expand Down Expand Up @@ -64,7 +62,7 @@ private[opts] trait Extra {
case InfoMsg (_) => ParserHelp.empty
case _ => usageHelp(Chunk.vcatChunks(List(
parserUsage(pprefs, i.parser, unwords(progName :: names)).pure[Chunk],
i.progDesc.map(PP.indent(_, 2))
i.progDesc.map(Doc.indent(2, _))
)))
}

Expand Down
24 changes: 12 additions & 12 deletions src/main/scala/net/bmjames/opts/helpdoc/Chunk.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package net.bmjames.opts.helpdoc

import net.bmjames.opts.internal.words
import net.bmjames.opts.types.Doc

import scalaz.{Applicative, Monoid, MonadPlus}
import scalaz.std.list._
Expand All @@ -10,9 +11,6 @@ import scalaz.syntax.std.option._
import scalaz.syntax.monadPlus._
import scalaz.syntax.foldable._

import org.kiama.output.PrettyPrinter.Doc
import org.kiama.output.{PrettyPrinter => PP}


/** The free monoid on a semigroup A */
final case class Chunk[A](run: Option[A]) {
Expand Down Expand Up @@ -67,38 +65,40 @@ object Chunk {

/** Concatenate two Chunks with a space in between. */
def <<+>>(that: Chunk[Doc]): Chunk[Doc] =
chunked[Doc](_ <+> _)(self, that)
chunked[Doc](_.withSpace(_))(self, that)

/** Concatenate two Chunks with a softline in between */
def <</>>(that: Chunk[Doc]): Chunk[Doc] =
chunked[Doc](_ </> _)(self, that)
chunked[Doc](_.withSoftline(_))(self, that)
}

/** Concatenate Chunks vertically. */
def vcatChunks(chunks: List[Chunk[Doc]]): Chunk[Doc] =
chunks.foldRight(Chunk.empty[Doc])(chunked(_ <@> _))
chunks.foldRight(Chunk.empty[Doc])(chunked(_.withLine(_)))

/** Concatenate Chunks vertically separated by empty lines. */
def vsepChunks(chunks: List[Chunk[Doc]]): Chunk[Doc] =
chunks.foldRight(Chunk.empty[Doc])(chunked((x, y) => x <@> PP.empty <@> y))
chunks.foldRight(Chunk.empty[Doc])(chunked((x, y) => x.withLine(Doc.empty).withLine(y)))

def extract[A : Monoid](chunk: Chunk[A]): A =
chunk.run.orZero

def fromString(s: String): Chunk[Doc] =
s match {
case "" => Chunk.empty
case s => Applicative[Chunk].pure(PP.string(s))
case s => Applicative[Chunk].pure(Doc.string(s))
}

def paragraph(s: String): Chunk[Doc] =
words(s).foldRight(Chunk.empty[Doc])((c, cs) => chunked[Doc](_ </> _)(fromString(c), cs))
words(s).foldRight(Chunk.empty[Doc])((c, cs) => chunked[Doc](_.withSoftline(_))(fromString(c), cs))

def tabulate(table: List[(Doc, Doc)], size: Int = 24): Chunk[Doc] =
table match {
case Nil => Chunk.empty
case xs => Applicative[Chunk].pure(PP.vcat(
for ((k, v) <- table) yield PP.indent(PP.padtobreak(size, k) <+> v, 2)
))
case xs =>
Applicative[Chunk].pure(
xs.map { case (k,v) =>
Doc.indent(2, Doc.fillBreak(size, k).withSpace(v))
}.reduce(_.withLine(_)))
}
}
28 changes: 13 additions & 15 deletions src/main/scala/net/bmjames/opts/helpdoc/Help.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,18 @@ import scalaz.std.option._
import scalaz.syntax.std.list._
import scalaz.syntax.std.boolean._
import scalaz.syntax.functor._
import scalaz.syntax.monoid._

import org.kiama.output.PrettyPrinter.Doc
import org.kiama.output.{PrettyPrinter => PP}

private[opts] trait Help {

import Pretty._
import Chunk._

/** Generate description for a single option. */
def optDesc[A](pprefs: ParserPrefs, style: OptDescStyle, info: OptHelpInfo, opt: Opt[A]): Chunk[Doc] = {
val ns = opt.main.names
val mv = Chunk.fromString(opt.props.metaVar)
val descs = ns.sorted.map(PP.string _ compose showOption)
val descs = ns.sorted.map(Doc.string _ compose showOption)
val desc = Chunk.fromList(descs.intersperse(style.sep)) <<+>> mv
val vis = opt.props.visibility
val showOpt = if (vis == Hidden) style.hidden else vis == Visible
Expand All @@ -30,9 +28,9 @@ private[opts] trait Help {
def render(chunk: Chunk[Doc]): Chunk[Doc] =
if (! showOpt) Chunk.empty
else if (chunk.isEmpty || ! style.surround) chunk <> suffix
else if (info.default) chunk.map(PP.brackets) <> suffix
else if (info.default) chunk.map(_.brackets) <> suffix
else if (descs.drop(1).isEmpty) chunk <> suffix
else chunk.map(PP.parens) <> suffix
else chunk.map(_.parens) <> suffix

render(desc)
}
Expand All @@ -45,21 +43,21 @@ private[opts] trait Help {
case CmdReader(cmds, p) =>
Chunk.tabulate(
for (cmd <- cmds.reverse; d <- p(cmd).map(_.progDesc).toList)
yield (PP.string(cmd), PP.align(extract(d)))
yield (Doc.string(cmd), extract(d).align)
)
case _ => Chunk.empty
})
}))

/** Generate a brief help text for a parser. */
def briefDesc[A](pprefs: ParserPrefs, parser: Parser[A]): Chunk[Doc] = {
val style = OptDescStyle(sep = "|", hidden = false, surround = true)
val style = OptDescStyle(sep = Doc.string("|"), hidden = false, surround = true)

def altNode(chunks: List[Chunk[Doc]]): Chunk[Doc] =
chunks match {
case List(n) => n
case ns => ns.foldRight(Chunk.empty[Doc])(chunked(_ </> PP.char('|') </> _))
.map(PP.parens)
case ns => ns.foldRight(Chunk.empty[Doc])(chunked(_.withSoftline(Doc.string("|")).withSoftline(_)))
.map(_.parens)
}

def foldTree(tree: OptTree[Chunk[Doc]]): Chunk[Doc] =
Expand All @@ -76,14 +74,14 @@ private[opts] trait Help {

/** Generate a full help text for a parser. */
def fullDesc[A](pprefs: ParserPrefs, parser: Parser[A]): Chunk[Doc] = {
val style = OptDescStyle(sep = ",", hidden = true, surround = false)
val style = OptDescStyle(sep = Doc.string(","), hidden = true, surround = false)

tabulate(parser.mapPoly(info => new (Opt ~> ({type λ[α]=Const[Option[(Doc, Doc)],α]})#λ) {
def apply[AA](fa: Opt[AA]): Const[Option[(Doc, Doc)], AA] = Const {
val n = optDesc(pprefs, style, info, fa)
val h = fa.props.help
val hdef = Chunk(fa.props.showDefault.map(s => PP.parens(PP.string("default:") <+> PP.string(s))))
(n.isEmpty || n.isEmpty).prevent[Option]((extract(n), PP.align(extract(h <<+>> hdef))))
val hdef = Chunk(fa.props.showDefault.map(s => (Doc.string("default:") |+| Doc.string(s)).parens))
(n.isEmpty || n.isEmpty).prevent[Option]((extract(n), extract(h <<+>> hdef).align))
}
}).flatten)
}
Expand All @@ -106,14 +104,14 @@ private[opts] trait Help {
/** Generate the help text for a program. */
def parserHelp[A](pprefs: ParserPrefs, parser: Parser[A]): ParserHelp = {
def withTitle(title: String, chunk: Chunk[Doc]): Chunk[Doc] =
chunk.map(PP.string(title) <@> _)
chunk.map(Doc.string(title).withLine(_))

bodyHelp(vsepChunks(List(withTitle("Available options:", fullDesc(pprefs, parser)),
withTitle("Available commands:", cmdDesc(parser)))))
}

/** Generate option summary. */
def parserUsage[A](pprefs: ParserPrefs, parser: Parser[A], progName: String): Doc =
PP.hsep(List("Usage:", progName, PP.align(extract(briefDesc(pprefs, parser)))))
Doc.hsep(List(Doc.string("Usage:"), Doc.string(progName), extract(briefDesc(pprefs, parser)).align))

}
2 changes: 1 addition & 1 deletion src/main/scala/net/bmjames/opts/helpdoc/OptDescStyle.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package net.bmjames.opts.helpdoc

import org.kiama.output.PrettyPrinter.Doc
import net.bmjames.opts.types.Doc

/** Style for rendering an option. */
final case class OptDescStyle(sep: Doc, hidden: Boolean, surround: Boolean)
8 changes: 2 additions & 6 deletions src/main/scala/net/bmjames/opts/helpdoc/ParserHelp.scala
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
package net.bmjames.opts.helpdoc

import net.bmjames.opts.types.Doc
import Chunk._
import scalaz.{Monoid, Show}
import scalaz.std.string._
import scalaz.syntax.semigroup._
import scalaz.syntax.show._

import org.kiama.output.PrettyPrinter.Doc
import org.kiama.output.{PrettyPrinter => PP}
import Pretty._

final case class ParserHelp(error: Chunk[Doc],
header: Chunk[Doc],
usage: Chunk[Doc],
Expand Down Expand Up @@ -42,7 +39,6 @@ object ParserHelp {
extract(vsepChunks(List(help.error, help.header, help.usage, help.body, help.footer)))

/** Convert a help text to a String */
def renderHelp(cols: Int, help: ParserHelp): String =
PP.pretty(helpText(help), cols)
def renderHelp(cols: Int, help: ParserHelp): String = Doc.prettyRender(cols, helpText(help))

}
16 changes: 0 additions & 16 deletions src/main/scala/net/bmjames/opts/helpdoc/Pretty.scala

This file was deleted.

Loading

0 comments on commit a6497c3

Please sign in to comment.