mirror of
https://github.com/enso-org/enso.git
synced 2024-12-22 18:38:11 +03:00
Remove documentation style sheet, fix code blocks (#1202)
This commit is contained in:
parent
1fbf3ad692
commit
91346a41fc
@ -169,12 +169,8 @@ object Doc {
|
|||||||
*
|
*
|
||||||
* @param elems - lines of code
|
* @param elems - lines of code
|
||||||
*/
|
*/
|
||||||
/*TODO [MM]: Next PR
|
final case class CodeBlock(elems: List1[CodeBlock.Line], isInGui: Boolean)
|
||||||
Code showing button - we need other design here.
|
extends Elem {
|
||||||
Basically we don't want to display always button
|
|
||||||
we want to be able to display it maybe as a button on website
|
|
||||||
and completely differently in gui, it should be configurable*/
|
|
||||||
final case class CodeBlock(elems: List1[CodeBlock.Line]) extends Elem {
|
|
||||||
val newLn: Elem = Elem.Newline
|
val newLn: Elem = Elem.Newline
|
||||||
val repr: Repr.Builder = R + elems.head + elems.tail.map(R + newLn + _)
|
val repr: Repr.Builder = R + elems.head + elems.tail.map(R + newLn + _)
|
||||||
val html: HTML = {
|
val html: HTML = {
|
||||||
@ -182,22 +178,28 @@ object Doc {
|
|||||||
val uniqueIDBtn = Random.alphanumeric.take(8).mkString("")
|
val uniqueIDBtn = Random.alphanumeric.take(8).mkString("")
|
||||||
val htmlIdCode = HTML.`id` := uniqueIDCode
|
val htmlIdCode = HTML.`id` := uniqueIDCode
|
||||||
val htmlIdBtn = HTML.`id` := uniqueIDBtn
|
val htmlIdBtn = HTML.`id` := uniqueIDBtn
|
||||||
|
val htmlStyle = HTML.`style` := "inline-block"
|
||||||
val elemsHTML = elems.toList.map(elem => elem.html)
|
val elemsHTML = elems.toList.map(elem => elem.html)
|
||||||
val btnAction = onclick :=
|
val btnAction = onclick :=
|
||||||
s"""var code = document.getElementById("$uniqueIDCode");
|
s"""var code = document.getElementById("$uniqueIDCode");
|
||||||
|var btn = document.getElementById("$uniqueIDBtn").firstChild;
|
|var btn = document.getElementById("$uniqueIDBtn").firstChild;
|
||||||
|btn.data = btn.data == "Show" ? "Hide" : "Show";
|
|btn.data = btn.data == "Show" ? "Hide" : "Show";
|
||||||
|code.style.display = code.style.display ==
|
|code.style.display = code.style.display ==
|
||||||
|"inline-block" ? "none" : "inline-block";""".stripMargin
|
|"inline-block" ? "none" : "inline-block";""".stripMargin
|
||||||
.replaceAll("\n", "")
|
.replaceAll("\n", "")
|
||||||
val btn = HTML.button(btnAction)(htmlIdBtn)("Show")
|
val btn = HTML.button(btnAction)(htmlIdBtn)("Show")
|
||||||
Seq(HTML.div(btn, HTML.div(htmlCls())(htmlIdCode)(elemsHTML)))
|
if (isInGui) {
|
||||||
|
Seq(HTML.div(htmlCls())(htmlStyle)(elemsHTML))
|
||||||
|
} else {
|
||||||
|
Seq(HTML.div(btn, HTML.div(htmlCls())(htmlIdCode)(elemsHTML)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
object CodeBlock {
|
object CodeBlock {
|
||||||
def apply(elem: CodeBlock.Line): CodeBlock = CodeBlock(List1(elem))
|
def apply(elem: CodeBlock.Line): CodeBlock =
|
||||||
|
CodeBlock(List1(elem), isInGui = true)
|
||||||
def apply(elems: CodeBlock.Line*): CodeBlock =
|
def apply(elems: CodeBlock.Line*): CodeBlock =
|
||||||
CodeBlock(List1(elems.head, elems.tail.toList))
|
CodeBlock(List1(elems.head, elems.tail.toList), isInGui = true)
|
||||||
|
|
||||||
/** Inline - line of code which is in line with other elements
|
/** Inline - line of code which is in line with other elements
|
||||||
* Line - elem which is a part of Code Block
|
* Line - elem which is a part of Code Block
|
||||||
|
@ -26,25 +26,27 @@ case class DocParserDef() extends Parser[Doc] {
|
|||||||
var doc: Option[Doc] = None
|
var doc: Option[Doc] = None
|
||||||
var stack: List[Elem] = Nil
|
var stack: List[Elem] = Nil
|
||||||
|
|
||||||
def push(): Unit = logger.trace {
|
def push(): Unit =
|
||||||
if (current.isDefined) {
|
logger.trace {
|
||||||
logger.log(s"Pushed: $current")
|
if (current.isDefined) {
|
||||||
stack +:= current.get
|
logger.log(s"Pushed: $current")
|
||||||
current = None
|
stack +:= current.get
|
||||||
} else {
|
current = None
|
||||||
logger.err("Undefined current")
|
} else {
|
||||||
|
logger.err("Undefined current")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
def pop(): Unit = logger.trace {
|
def pop(): Unit =
|
||||||
if (stack.nonEmpty) {
|
logger.trace {
|
||||||
current = Some(stack.head)
|
if (stack.nonEmpty) {
|
||||||
stack = stack.tail
|
current = Some(stack.head)
|
||||||
logger.log(s"New result: $current")
|
stack = stack.tail
|
||||||
} else {
|
logger.log(s"New result: $current")
|
||||||
logger.err("Trying to pop empty AST stack")
|
} else {
|
||||||
|
logger.err("Trying to pop empty AST stack")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
@ -71,34 +73,37 @@ case class DocParserDef() extends Parser[Doc] {
|
|||||||
/** text - used to manage normal text, made of Strings
|
/** text - used to manage normal text, made of Strings
|
||||||
*/
|
*/
|
||||||
final object text {
|
final object text {
|
||||||
def onPushing(in: String): Unit = logger.trace {
|
def onPushing(in: String): Unit =
|
||||||
if (documentation.isBeginning()) {
|
logger.trace {
|
||||||
if (!tags.checkIfTagExistInPushedText(in)) {
|
if (documentation.isBeginning()) {
|
||||||
|
if (!tags.checkIfTagExistInPushedText(in)) {
|
||||||
|
val text = removeWhitespaces(in)
|
||||||
|
push(text)
|
||||||
|
}
|
||||||
|
} else if (section.isBeginning()) {
|
||||||
val text = removeWhitespaces(in)
|
val text = removeWhitespaces(in)
|
||||||
push(text)
|
push(text)
|
||||||
}
|
} else {
|
||||||
} else if (section.isBeginning()) {
|
push(in)
|
||||||
val text = removeWhitespaces(in)
|
|
||||||
push(text)
|
|
||||||
} else {
|
|
||||||
push(in)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def removeWhitespaces(in: String): String = logger.trace {
|
|
||||||
var text = in
|
|
||||||
if (text.nonEmpty) {
|
|
||||||
while (text.head == ' ' && text.length > 1) {
|
|
||||||
text = text.tail
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
text
|
|
||||||
}
|
|
||||||
|
|
||||||
def push(in: String): Unit = logger.trace {
|
def removeWhitespaces(in: String): String =
|
||||||
result.current = Some(Elem.Text(in))
|
logger.trace {
|
||||||
result.push()
|
var text = in
|
||||||
}
|
if (text.nonEmpty) {
|
||||||
|
while (text.head == ' ' && text.length > 1) {
|
||||||
|
text = text.tail
|
||||||
|
}
|
||||||
|
}
|
||||||
|
text
|
||||||
|
}
|
||||||
|
|
||||||
|
def push(in: String): Unit =
|
||||||
|
logger.trace {
|
||||||
|
result.current = Some(Elem.Text(in))
|
||||||
|
result.push()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ROOT || normalText || text.onPushing(currentMatch)
|
ROOT || normalText || text.onPushing(currentMatch)
|
||||||
@ -135,33 +140,35 @@ case class DocParserDef() extends Parser[Doc] {
|
|||||||
result.current = None
|
result.current = None
|
||||||
}
|
}
|
||||||
|
|
||||||
def checkIfTagExistInPushedText(in: String): Boolean = logger.trace {
|
def checkIfTagExistInPushedText(in: String): Boolean =
|
||||||
val inArray = in.split(" ")
|
logger.trace {
|
||||||
var containsTag = false
|
val inArray = in.split(" ")
|
||||||
|
var containsTag = false
|
||||||
|
|
||||||
def tryFindingTagInAvailableTags(elem: String): Unit = logger.trace {
|
def tryFindingTagInAvailableTags(elem: String): Unit =
|
||||||
for (tagType <- possibleTagsList) {
|
logger.trace {
|
||||||
if (elem == tagType.toString.toUpperCase) {
|
for (tagType <- possibleTagsList) {
|
||||||
containsTag = true
|
if (elem == tagType.toString.toUpperCase) {
|
||||||
val tagDet = in.replaceFirst(tagType.toString.toUpperCase, "")
|
containsTag = true
|
||||||
pushTag(section.currentIndentRaw, tagType, tagDet)
|
val tagDet = in.replaceFirst(tagType.toString.toUpperCase, "")
|
||||||
|
pushTag(section.currentIndentRaw, tagType, tagDet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!containsTag && !elem.contains(newline)) {
|
||||||
|
pushTag(section.currentIndentRaw, Tags.Tag.Unrecognized, in)
|
||||||
|
containsTag = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (elem <- inArray) {
|
||||||
|
if (elem.isEmpty) {
|
||||||
|
section.currentIndentRaw += 1
|
||||||
|
} else if (elem == elem.toUpperCase) {
|
||||||
|
tryFindingTagInAvailableTags(elem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!containsTag && !elem.contains(newline)) {
|
containsTag
|
||||||
pushTag(section.currentIndentRaw, Tags.Tag.Unrecognized, in)
|
|
||||||
containsTag = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (elem <- inArray) {
|
|
||||||
if (elem.isEmpty) {
|
|
||||||
section.currentIndentRaw += 1
|
|
||||||
} else if (elem == elem.toUpperCase) {
|
|
||||||
tryFindingTagInAvailableTags(elem)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
containsTag
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
@ -171,29 +178,32 @@ case class DocParserDef() extends Parser[Doc] {
|
|||||||
/** code - used to manage code in documentation
|
/** code - used to manage code in documentation
|
||||||
*/
|
*/
|
||||||
final object code {
|
final object code {
|
||||||
def onPushingInline(in: String): Unit = logger.trace {
|
def onPushingInline(in: String): Unit =
|
||||||
val code = in.substring(1).dropRight(1)
|
logger.trace {
|
||||||
result.current = Some(Elem.CodeBlock.Inline(code))
|
val code = in.substring(1).dropRight(1)
|
||||||
result.push()
|
result.current = Some(Elem.CodeBlock.Inline(code))
|
||||||
}
|
result.push()
|
||||||
|
}
|
||||||
def onPushingMultiline(in: String): Unit = logger.trace {
|
|
||||||
val dummyLine = Elem.CodeBlock.Line(0, "")
|
def onPushingMultiline(in: String): Unit =
|
||||||
do {
|
logger.trace {
|
||||||
result.pop()
|
val dummyLine = Elem.CodeBlock.Line(0, "")
|
||||||
} while (result.current.get == Elem.Newline)
|
do {
|
||||||
result.current match {
|
result.pop()
|
||||||
case Some(code @ (_: Elem.CodeBlock)) =>
|
} while (result.current.get == Elem.Newline)
|
||||||
val newElem = Elem.CodeBlock.Line(indent.current, in)
|
result.current match {
|
||||||
if (code.elems.head == dummyLine) {
|
case Some(code @ (_: Elem.CodeBlock)) =>
|
||||||
result.current = Some(Elem.CodeBlock(newElem))
|
val newElem = Elem.CodeBlock.Line(indent.current, in)
|
||||||
} else {
|
if (code.elems.head == dummyLine) {
|
||||||
result.current = Some(Elem.CodeBlock(code.elems.append(newElem)))
|
result.current = Some(Elem.CodeBlock(newElem))
|
||||||
}
|
} else {
|
||||||
case Some(_) | None => result.push()
|
result.current =
|
||||||
|
Some(Elem.CodeBlock(code.elems.append(newElem), isInGui = true))
|
||||||
|
}
|
||||||
|
case Some(_) | None => result.push()
|
||||||
|
}
|
||||||
|
result.push()
|
||||||
}
|
}
|
||||||
result.push()
|
|
||||||
}
|
|
||||||
|
|
||||||
val inlineCodeTrigger = '`'
|
val inlineCodeTrigger = '`'
|
||||||
val inlinePattern: Pattern =
|
val inlinePattern: Pattern =
|
||||||
@ -204,7 +214,7 @@ case class DocParserDef() extends Parser[Doc] {
|
|||||||
val CODE: State = state.define("Code")
|
val CODE: State = state.define("Code")
|
||||||
|
|
||||||
ROOT || code.inlinePattern || code.onPushingInline(currentMatch)
|
ROOT || code.inlinePattern || code.onPushingInline(currentMatch)
|
||||||
CODE || newline || { state.end(); state.begin(NEWLINE) }
|
CODE || newline || { state.end(); state.begin(NEWLINE) }
|
||||||
CODE || notNewLine || code.onPushingMultiline(currentMatch)
|
CODE || notNewLine || code.onPushingMultiline(currentMatch)
|
||||||
CODE || eof || { state.end(); documentation.onEOF() }
|
CODE || eof || { state.end(); documentation.onEOF() }
|
||||||
|
|
||||||
@ -237,7 +247,9 @@ case class DocParserDef() extends Parser[Doc] {
|
|||||||
def getElemsFromStack(typ: Elem.Formatter.Type): List[Elem] =
|
def getElemsFromStack(typ: Elem.Formatter.Type): List[Elem] =
|
||||||
logger.trace {
|
logger.trace {
|
||||||
var listOfFormattedAST: List[Elem] = Nil
|
var listOfFormattedAST: List[Elem] = Nil
|
||||||
while (result.stack.head != Elem.Formatter(typ) && result.stack.nonEmpty) {
|
while (
|
||||||
|
result.stack.head != Elem.Formatter(typ) && result.stack.nonEmpty
|
||||||
|
) {
|
||||||
result.pop()
|
result.pop()
|
||||||
result.current match {
|
result.current match {
|
||||||
case Some(value) => listOfFormattedAST +:= value
|
case Some(value) => listOfFormattedAST +:= value
|
||||||
@ -247,38 +259,41 @@ case class DocParserDef() extends Parser[Doc] {
|
|||||||
listOfFormattedAST
|
listOfFormattedAST
|
||||||
}
|
}
|
||||||
|
|
||||||
def addEmptyToStack(typ: Elem.Formatter.Type): Unit = logger.trace {
|
def addEmptyToStack(typ: Elem.Formatter.Type): Unit =
|
||||||
stack +:= typ
|
logger.trace {
|
||||||
result.current = Some(Elem.Formatter(typ))
|
stack +:= typ
|
||||||
result.push()
|
result.current = Some(Elem.Formatter(typ))
|
||||||
}
|
result.push()
|
||||||
|
}
|
||||||
|
|
||||||
def decideWhichToCheckIfUnclosed(
|
def decideWhichToCheckIfUnclosed(
|
||||||
typ: Elem.Formatter.Type
|
typ: Elem.Formatter.Type
|
||||||
): List[Elem.Formatter.Type] = logger.trace {
|
): List[Elem.Formatter.Type] =
|
||||||
typ match {
|
logger.trace {
|
||||||
case Elem.Formatter.Strikeout =>
|
typ match {
|
||||||
List(Elem.Formatter.Bold, Elem.Formatter.Italic)
|
case Elem.Formatter.Strikeout =>
|
||||||
case Elem.Formatter.Italic =>
|
List(Elem.Formatter.Bold, Elem.Formatter.Italic)
|
||||||
List(Elem.Formatter.Bold, Elem.Formatter.Strikeout)
|
case Elem.Formatter.Italic =>
|
||||||
case Elem.Formatter.Bold =>
|
List(Elem.Formatter.Bold, Elem.Formatter.Strikeout)
|
||||||
List(Elem.Formatter.Italic, Elem.Formatter.Strikeout)
|
case Elem.Formatter.Bold =>
|
||||||
case _ => throw new Error("Trying to use non-existing formatter")
|
List(Elem.Formatter.Italic, Elem.Formatter.Strikeout)
|
||||||
}
|
case _ => throw new Error("Trying to use non-existing formatter")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
def checkForUnclosed(typ: Elem.Formatter.Type): Unit = logger.trace {
|
|
||||||
if (stack.nonEmpty) {
|
def checkForUnclosed(typ: Elem.Formatter.Type): Unit =
|
||||||
if (stack.head == typ) {
|
logger.trace {
|
||||||
val listOfFormattedAST: List[Elem] = getElemsFromStack(typ)
|
if (stack.nonEmpty) {
|
||||||
result.pop()
|
if (stack.head == typ) {
|
||||||
result.current =
|
val listOfFormattedAST: List[Elem] = getElemsFromStack(typ)
|
||||||
Some(Elem.Formatter.Unclosed(typ, listOfFormattedAST))
|
result.pop()
|
||||||
stack = stack.tail
|
result.current =
|
||||||
result.push()
|
Some(Elem.Formatter.Unclosed(typ, listOfFormattedAST))
|
||||||
|
stack = stack.tail
|
||||||
|
result.push()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
val boldTrigger: Char = Elem.Formatter.Bold.marker
|
val boldTrigger: Char = Elem.Formatter.Bold.marker
|
||||||
val italicTrigger: Char = Elem.Formatter.Italic.marker
|
val italicTrigger: Char = Elem.Formatter.Italic.marker
|
||||||
@ -301,31 +316,33 @@ case class DocParserDef() extends Parser[Doc] {
|
|||||||
/** header - used to create section headers in Documentation
|
/** header - used to create section headers in Documentation
|
||||||
*/
|
*/
|
||||||
final object header {
|
final object header {
|
||||||
def create(): Unit = logger.trace {
|
def create(): Unit =
|
||||||
section.current match {
|
logger.trace {
|
||||||
case Some(_) => loopThroughStackToFindHeader()
|
section.current match {
|
||||||
case None =>
|
case Some(_) => loopThroughStackToFindHeader()
|
||||||
result.pop()
|
case None =>
|
||||||
result.current match {
|
result.pop()
|
||||||
case Some(_: Section.Header) => loopThroughStackToFindHeader()
|
result.current match {
|
||||||
case _ => result.push()
|
case Some(_: Section.Header) => loopThroughStackToFindHeader()
|
||||||
}
|
case _ => result.push()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
def loopThroughStackToFindHeader(): Unit = logger.trace {
|
def loopThroughStackToFindHeader(): Unit =
|
||||||
var listForHeader: List[Elem] = Nil
|
logger.trace {
|
||||||
do {
|
var listForHeader: List[Elem] = Nil
|
||||||
result.pop()
|
do {
|
||||||
listForHeader +:= result.current.get
|
result.pop()
|
||||||
} while (result.current.get != Elem.Newline && result.stack.nonEmpty)
|
listForHeader +:= result.current.get
|
||||||
if (result.current.get == Elem.Newline) {
|
} while (result.current.get != Elem.Newline && result.stack.nonEmpty)
|
||||||
|
if (result.current.get == Elem.Newline) {
|
||||||
|
result.push()
|
||||||
|
listForHeader = listForHeader.tail
|
||||||
|
}
|
||||||
|
result.current = Some(Section.Header(listForHeader.reverse))
|
||||||
result.push()
|
result.push()
|
||||||
listForHeader = listForHeader.tail
|
|
||||||
}
|
}
|
||||||
result.current = Some(Section.Header(listForHeader.reverse))
|
|
||||||
result.push()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
@ -337,53 +354,60 @@ case class DocParserDef() extends Parser[Doc] {
|
|||||||
* there are 2 possible link types - Image and normal URL
|
* there are 2 possible link types - Image and normal URL
|
||||||
*/
|
*/
|
||||||
final object link {
|
final object link {
|
||||||
def onCreatingURL(): Unit = logger.trace {
|
def onCreatingURL(): Unit =
|
||||||
if (currentMatch.contains("]") && currentMatch.contains("(")) {
|
logger.trace {
|
||||||
val in = currentMatch.substring(1).dropRight(1).split(']')
|
if (currentMatch.contains("]") && currentMatch.contains("(")) {
|
||||||
val name = in(0)
|
val in = currentMatch.substring(1).dropRight(1).split(']')
|
||||||
val url = in(1).substring(1)
|
val name = in(0)
|
||||||
pushURL(name, url)
|
val url = in(1).substring(1)
|
||||||
} else {
|
pushURL(name, url)
|
||||||
onInvalidLink()
|
} else {
|
||||||
|
onInvalidLink()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
def pushURL(name: String, url: String): Unit = logger.trace {
|
def pushURL(name: String, url: String): Unit =
|
||||||
result.current = Some(Elem.Link.URL(name, url))
|
logger.trace {
|
||||||
result.push()
|
result.current = Some(Elem.Link.URL(name, url))
|
||||||
}
|
result.push()
|
||||||
|
|
||||||
def onCreatingImage(): Unit = logger.trace {
|
|
||||||
if (currentMatch.contains("]") && currentMatch.contains("(")) {
|
|
||||||
val in = currentMatch.substring(2).dropRight(1).split(']')
|
|
||||||
val name = in(0)
|
|
||||||
val url = in(1).substring(1)
|
|
||||||
pushImage(name, url)
|
|
||||||
} else {
|
|
||||||
onInvalidLink()
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
def pushImage(name: String, url: String): Unit = logger.trace {
|
def onCreatingImage(): Unit =
|
||||||
result.current = Some(Elem.Link.Image(name, url))
|
logger.trace {
|
||||||
result.push()
|
if (currentMatch.contains("]") && currentMatch.contains("(")) {
|
||||||
}
|
val in = currentMatch.substring(2).dropRight(1).split(']')
|
||||||
|
val name = in(0)
|
||||||
|
val url = in(1).substring(1)
|
||||||
|
pushImage(name, url)
|
||||||
|
} else {
|
||||||
|
onInvalidLink()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def onInvalidLink(): Unit = logger.trace {
|
def pushImage(name: String, url: String): Unit =
|
||||||
result.current = Some(Elem.Link.Invalid(currentMatch))
|
logger.trace {
|
||||||
result.push()
|
result.current = Some(Elem.Link.Image(name, url))
|
||||||
}
|
result.push()
|
||||||
|
}
|
||||||
|
|
||||||
def onInvalidLinkNewline(): Unit = logger.trace {
|
def onInvalidLink(): Unit =
|
||||||
result.current = Some(Elem.Link.Invalid(currentMatch.dropRight(1)))
|
logger.trace {
|
||||||
result.push()
|
result.current = Some(Elem.Link.Invalid(currentMatch))
|
||||||
indent.onPushingNewLine()
|
result.push()
|
||||||
}
|
}
|
||||||
|
|
||||||
def onInvalidLinkEOF(): Unit = logger.trace {
|
def onInvalidLinkNewline(): Unit =
|
||||||
onInvalidLink()
|
logger.trace {
|
||||||
documentation.onEOF()
|
result.current = Some(Elem.Link.Invalid(currentMatch.dropRight(1)))
|
||||||
}
|
result.push()
|
||||||
|
indent.onPushingNewLine()
|
||||||
|
}
|
||||||
|
|
||||||
|
def onInvalidLinkEOF(): Unit =
|
||||||
|
logger.trace {
|
||||||
|
onInvalidLink()
|
||||||
|
documentation.onEOF()
|
||||||
|
}
|
||||||
|
|
||||||
val urlNameTrigger: String = "["
|
val urlNameTrigger: String = "["
|
||||||
val imageNameTrigger: String = Elem.Link.Image().marker.get + urlNameTrigger
|
val imageNameTrigger: String = Elem.Link.Image().marker.get + urlNameTrigger
|
||||||
@ -413,65 +437,71 @@ case class DocParserDef() extends Parser[Doc] {
|
|||||||
*/
|
*/
|
||||||
final object indent {
|
final object indent {
|
||||||
var stack: List[Int] = Nil
|
var stack: List[Int] = Nil
|
||||||
def current: Int = stack match {
|
def current: Int =
|
||||||
case Nil => 0
|
stack match {
|
||||||
case ::(head, _) => head
|
case Nil => 0
|
||||||
}
|
case ::(head, _) => head
|
||||||
|
|
||||||
def onIndent(): Unit = logger.trace {
|
|
||||||
val diff = currentMatch.length - current
|
|
||||||
if (diff < 0 && list.inListFlag) {
|
|
||||||
list.appendInnerToOuter()
|
|
||||||
stack = stack.tail
|
|
||||||
} else if (currentMatch.length > section.currentIndentRaw && result.stack.nonEmpty) {
|
|
||||||
tryToFindCodeInStack()
|
|
||||||
stack +:= currentMatch.length
|
|
||||||
state.begin(CODE)
|
|
||||||
} else {
|
|
||||||
section.currentIndentRaw = currentMatch.length
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
def tryToFindCodeInStack(): Unit = logger.trace {
|
def onIndent(): Unit =
|
||||||
result.pop()
|
logger.trace {
|
||||||
result.stack.head match {
|
val diff = currentMatch.length - current
|
||||||
case _: Elem.CodeBlock =>
|
if (diff < 0 && list.inListFlag) {
|
||||||
case _ =>
|
list.appendInnerToOuter()
|
||||||
result.push()
|
stack = stack.tail
|
||||||
val dummyLine = Elem.CodeBlock.Line(0, "")
|
} else if (
|
||||||
result.current = Some(Elem.CodeBlock(dummyLine))
|
currentMatch.length > section.currentIndentRaw && result.stack.nonEmpty
|
||||||
|
) {
|
||||||
|
tryToFindCodeInStack()
|
||||||
|
stack +:= currentMatch.length
|
||||||
|
state.begin(CODE)
|
||||||
|
} else {
|
||||||
|
section.currentIndentRaw = currentMatch.length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def tryToFindCodeInStack(): Unit =
|
||||||
|
logger.trace {
|
||||||
|
result.pop()
|
||||||
|
result.stack.head match {
|
||||||
|
case _: Elem.CodeBlock =>
|
||||||
|
case _ =>
|
||||||
|
result.push()
|
||||||
|
val dummyLine = Elem.CodeBlock.Line(0, "")
|
||||||
|
result.current = Some(Elem.CodeBlock(dummyLine))
|
||||||
|
}
|
||||||
|
result.push()
|
||||||
}
|
}
|
||||||
result.push()
|
|
||||||
}
|
|
||||||
|
|
||||||
def onIndentForListCreation(
|
def onIndentForListCreation(
|
||||||
indent: Int,
|
indent: Int,
|
||||||
typ: Elem.List.Type,
|
typ: Elem.List.Type,
|
||||||
content: String
|
content: String
|
||||||
): Unit = logger.trace {
|
): Unit =
|
||||||
val diff = indent - current
|
logger.trace {
|
||||||
if (diff > 0) {
|
val diff = indent - current
|
||||||
/* NOTE
|
if (diff > 0) {
|
||||||
* Used to push new line before pushing first list
|
/* NOTE
|
||||||
*/
|
* Used to push new line before pushing first list
|
||||||
if (!list.inListFlag) onPushingNewLine()
|
*/
|
||||||
stack +:= indent
|
if (!list.inListFlag) onPushingNewLine()
|
||||||
list.inListFlag = true
|
stack +:= indent
|
||||||
list.addNew(indent, typ, content)
|
list.inListFlag = true
|
||||||
} else if (diff == 0 && list.inListFlag) {
|
list.addNew(indent, typ, content)
|
||||||
list.addContent(content)
|
} else if (diff == 0 && list.inListFlag) {
|
||||||
} else if (diff < 0 && list.inListFlag) {
|
|
||||||
if (stack.tail.head != indent) {
|
|
||||||
onInvalidIndent(indent, typ, content)
|
|
||||||
} else {
|
|
||||||
list.appendInnerToOuter()
|
|
||||||
list.addContent(content)
|
list.addContent(content)
|
||||||
stack = stack.tail
|
} else if (diff < 0 && list.inListFlag) {
|
||||||
|
if (stack.tail.head != indent) {
|
||||||
|
onInvalidIndent(indent, typ, content)
|
||||||
|
} else {
|
||||||
|
list.appendInnerToOuter()
|
||||||
|
list.addContent(content)
|
||||||
|
stack = stack.tail
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
onInvalidIndent(indent, typ, content)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
onInvalidIndent(indent, typ, content)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
def onInvalidIndent(
|
def onInvalidIndent(
|
||||||
indent: Int,
|
indent: Int,
|
||||||
@ -493,33 +523,37 @@ case class DocParserDef() extends Parser[Doc] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def onPushingNewLine(): Unit = logger.trace {
|
def onPushingNewLine(): Unit =
|
||||||
result.current = Some(Elem.Newline)
|
logger.trace {
|
||||||
result.push()
|
result.current = Some(Elem.Newline)
|
||||||
}
|
result.push()
|
||||||
|
|
||||||
def onEmptyLine(): Unit = logger.trace {
|
|
||||||
if (list.inListFlag) {
|
|
||||||
list.appendInnerToOuter()
|
|
||||||
list.inListFlag = false
|
|
||||||
}
|
}
|
||||||
onPushingNewLine()
|
|
||||||
section.onEOS()
|
|
||||||
}
|
|
||||||
|
|
||||||
def onIndentPattern(): Unit = logger.trace {
|
def onEmptyLine(): Unit =
|
||||||
state.end()
|
logger.trace {
|
||||||
if (result.stack.nonEmpty) {
|
if (list.inListFlag) {
|
||||||
|
list.appendInnerToOuter()
|
||||||
|
list.inListFlag = false
|
||||||
|
}
|
||||||
|
onPushingNewLine()
|
||||||
|
section.onEOS()
|
||||||
|
}
|
||||||
|
|
||||||
|
def onIndentPattern(): Unit =
|
||||||
|
logger.trace {
|
||||||
|
state.end()
|
||||||
|
if (result.stack.nonEmpty) {
|
||||||
|
indent.onPushingNewLine()
|
||||||
|
}
|
||||||
|
indent.onIndent()
|
||||||
|
}
|
||||||
|
|
||||||
|
def onEOFPattern(): Unit =
|
||||||
|
logger.trace {
|
||||||
|
state.end()
|
||||||
indent.onPushingNewLine()
|
indent.onPushingNewLine()
|
||||||
|
documentation.onEOF()
|
||||||
}
|
}
|
||||||
indent.onIndent()
|
|
||||||
}
|
|
||||||
|
|
||||||
def onEOFPattern(): Unit = logger.trace {
|
|
||||||
state.end()
|
|
||||||
indent.onPushingNewLine()
|
|
||||||
documentation.onEOF()
|
|
||||||
}
|
|
||||||
|
|
||||||
val emptyLine: Pattern = whitespace.opt >> newline
|
val emptyLine: Pattern = whitespace.opt >> newline
|
||||||
val indentPattern: Pattern = whitespace.opt.many
|
val indentPattern: Pattern = whitespace.opt.many
|
||||||
@ -549,55 +583,63 @@ case class DocParserDef() extends Parser[Doc] {
|
|||||||
result.push()
|
result.push()
|
||||||
}
|
}
|
||||||
|
|
||||||
def addContent(content: Elem): Unit = logger.trace {
|
def addContent(content: Elem): Unit =
|
||||||
result.pop()
|
logger.trace {
|
||||||
result.current match {
|
result.pop()
|
||||||
case Some(list @ (_: Elem.List)) =>
|
result.current match {
|
||||||
var currentContent = list.elems
|
case Some(list @ (_: Elem.List)) =>
|
||||||
currentContent = currentContent.append(content)
|
var currentContent = list.elems
|
||||||
result.current =
|
currentContent = currentContent.append(content)
|
||||||
Some(Elem.List(list.indent, list.typ, currentContent))
|
result.current =
|
||||||
case _ =>
|
Some(Elem.List(list.indent, list.typ, currentContent))
|
||||||
|
case _ =>
|
||||||
|
}
|
||||||
|
result.push()
|
||||||
}
|
}
|
||||||
result.push()
|
|
||||||
}
|
|
||||||
|
|
||||||
def appendInnerToOuter(): Unit = logger.trace {
|
def appendInnerToOuter(): Unit =
|
||||||
result.pop()
|
logger.trace {
|
||||||
val innerList = result.current.orNull
|
result.pop()
|
||||||
result.stack.head match {
|
val innerList = result.current.orNull
|
||||||
case outerList @ (_: Elem.List) =>
|
result.stack.head match {
|
||||||
var outerContent = outerList.elems
|
case outerList @ (_: Elem.List) =>
|
||||||
innerList match {
|
var outerContent = outerList.elems
|
||||||
case Elem.Newline =>
|
innerList match {
|
||||||
case _ => outerContent = outerContent.append(innerList)
|
case Elem.Newline =>
|
||||||
}
|
case _ => outerContent = outerContent.append(innerList)
|
||||||
result.pop()
|
}
|
||||||
result.current =
|
result.pop()
|
||||||
Some(Elem.List(outerList.indent, outerList.typ, outerContent))
|
result.current =
|
||||||
case _ =>
|
Some(Elem.List(outerList.indent, outerList.typ, outerContent))
|
||||||
|
case _ =>
|
||||||
|
}
|
||||||
|
result.push()
|
||||||
|
innerList match {
|
||||||
|
case Elem.Newline => indent.onPushingNewLine()
|
||||||
|
case _ =>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
result.push()
|
|
||||||
innerList match {
|
|
||||||
case Elem.Newline => indent.onPushingNewLine()
|
|
||||||
case _ =>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def onOrdered(): Unit = logger.trace {
|
def onOrdered(): Unit =
|
||||||
state.end()
|
logger.trace {
|
||||||
val matchedContent = currentMatch.split(orderedListTrigger)
|
state.end()
|
||||||
val listIndent = matchedContent(0).length
|
val matchedContent = currentMatch.split(orderedListTrigger)
|
||||||
val listElems = matchedContent(1)
|
val listIndent = matchedContent(0).length
|
||||||
indent.onIndentForListCreation(listIndent, Elem.List.Ordered, listElems)
|
val listElems = matchedContent(1)
|
||||||
}
|
indent.onIndentForListCreation(listIndent, Elem.List.Ordered, listElems)
|
||||||
def onUnordered(): Unit = logger.trace {
|
}
|
||||||
state.end()
|
def onUnordered(): Unit =
|
||||||
val matchedContent = currentMatch.split(unorderedListTrigger)
|
logger.trace {
|
||||||
val listIndent = matchedContent(0).length
|
state.end()
|
||||||
val listElems = matchedContent(1)
|
val matchedContent = currentMatch.split(unorderedListTrigger)
|
||||||
indent.onIndentForListCreation(listIndent, Elem.List.Unordered, listElems)
|
val listIndent = matchedContent(0).length
|
||||||
}
|
val listElems = matchedContent(1)
|
||||||
|
indent.onIndentForListCreation(
|
||||||
|
listIndent,
|
||||||
|
Elem.List.Unordered,
|
||||||
|
listElems
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
val orderedListTrigger: Char = Elem.List.Ordered.marker
|
val orderedListTrigger: Char = Elem.List.Ordered.marker
|
||||||
val unorderedListTrigger: Char = Elem.List.Unordered.marker
|
val unorderedListTrigger: Char = Elem.List.Unordered.marker
|
||||||
@ -642,11 +684,12 @@ case class DocParserDef() extends Parser[Doc] {
|
|||||||
current = typ
|
current = typ
|
||||||
}
|
}
|
||||||
|
|
||||||
def onNewMarked(typ: Section.Marked.Type): Unit = logger.trace {
|
def onNewMarked(typ: Section.Marked.Type): Unit =
|
||||||
createMarkedSectionIndent(typ)
|
logger.trace {
|
||||||
onNew(Some(typ))
|
createMarkedSectionIndent(typ)
|
||||||
currentIndentRaw += currentMatch.length
|
onNew(Some(typ))
|
||||||
}
|
currentIndentRaw += currentMatch.length
|
||||||
|
}
|
||||||
|
|
||||||
def createMarkedSectionIndent(typ: Section.Marked.Type): Unit =
|
def createMarkedSectionIndent(typ: Section.Marked.Type): Unit =
|
||||||
logger.trace {
|
logger.trace {
|
||||||
@ -663,69 +706,77 @@ case class DocParserDef() extends Parser[Doc] {
|
|||||||
indentAfterMarker = inArr.tail.head.length - 1
|
indentAfterMarker = inArr.tail.head.length - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
def onNewRaw(): Unit = logger.trace {
|
def onNewRaw(): Unit =
|
||||||
indent.onEmptyLine()
|
logger.trace {
|
||||||
onNew(None)
|
indent.onEmptyLine()
|
||||||
}
|
onNew(None)
|
||||||
|
}
|
||||||
|
|
||||||
def onNewRawWithHeader(): Unit = logger.trace {
|
def onNewRawWithHeader(): Unit =
|
||||||
state.end()
|
logger.trace {
|
||||||
onNewRaw()
|
state.end()
|
||||||
result.current = Some(Section.Header())
|
onNewRaw()
|
||||||
result.push()
|
result.current = Some(Section.Header())
|
||||||
}
|
result.push()
|
||||||
|
}
|
||||||
|
|
||||||
def isBeginning(): Boolean = logger.trace {
|
def isBeginning(): Boolean =
|
||||||
result.stack.isEmpty || result.stack.head.isInstanceOf[Section.Header]
|
logger.trace {
|
||||||
}
|
result.stack.isEmpty || result.stack.head.isInstanceOf[Section.Header]
|
||||||
|
}
|
||||||
|
|
||||||
//// End of Section ////
|
//// End of Section ////
|
||||||
def checkForUnclosedFormattersOnEOS(): Unit = logger.trace {
|
def checkForUnclosedFormattersOnEOS(): Unit =
|
||||||
formatter.checkForUnclosed(Elem.Formatter.Bold)
|
logger.trace {
|
||||||
formatter.checkForUnclosed(Elem.Formatter.Italic)
|
formatter.checkForUnclosed(Elem.Formatter.Bold)
|
||||||
formatter.checkForUnclosed(Elem.Formatter.Strikeout)
|
formatter.checkForUnclosed(Elem.Formatter.Italic)
|
||||||
}
|
formatter.checkForUnclosed(Elem.Formatter.Strikeout)
|
||||||
|
|
||||||
def reverseStackOnEOS(): Unit = logger.trace {
|
|
||||||
result.stack = result.stack.reverse
|
|
||||||
}
|
|
||||||
|
|
||||||
def push(): Unit = logger.trace {
|
|
||||||
result.stack match {
|
|
||||||
case Nil =>
|
|
||||||
/* NOTE
|
|
||||||
* We don't want to push an empty section into stack
|
|
||||||
* in case of parsing for example empty file
|
|
||||||
* Then we want to get back Doc(None) and not Doc(Section())
|
|
||||||
*/
|
|
||||||
case _ =>
|
|
||||||
section.current match {
|
|
||||||
case Some(marker) =>
|
|
||||||
section.stack +:= Section.Marked(
|
|
||||||
indentBeforeMarker,
|
|
||||||
indentAfterMarker,
|
|
||||||
marker,
|
|
||||||
result.stack
|
|
||||||
)
|
|
||||||
case None =>
|
|
||||||
section.stack +:= Section.Raw(currentIndentRaw, result.stack)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
def cleanupOnEOS(): Unit = logger.trace {
|
def reverseStackOnEOS(): Unit =
|
||||||
result.current = None
|
logger.trace {
|
||||||
result.stack = Nil
|
result.stack = result.stack.reverse
|
||||||
formatter.stack = Nil
|
}
|
||||||
}
|
|
||||||
|
|
||||||
def onEOS(): Unit = logger.trace {
|
def push(): Unit =
|
||||||
checkForUnclosedFormattersOnEOS()
|
logger.trace {
|
||||||
reverseStackOnEOS()
|
result.stack match {
|
||||||
header.create()
|
case Nil =>
|
||||||
push()
|
/* NOTE
|
||||||
cleanupOnEOS()
|
* We don't want to push an empty section into stack
|
||||||
}
|
* in case of parsing for example empty file
|
||||||
|
* Then we want to get back Doc(None) and not Doc(Section())
|
||||||
|
*/
|
||||||
|
case _ =>
|
||||||
|
section.current match {
|
||||||
|
case Some(marker) =>
|
||||||
|
section.stack +:= Section.Marked(
|
||||||
|
indentBeforeMarker,
|
||||||
|
indentAfterMarker,
|
||||||
|
marker,
|
||||||
|
result.stack
|
||||||
|
)
|
||||||
|
case None =>
|
||||||
|
section.stack +:= Section.Raw(currentIndentRaw, result.stack)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def cleanupOnEOS(): Unit =
|
||||||
|
logger.trace {
|
||||||
|
result.current = None
|
||||||
|
result.stack = Nil
|
||||||
|
formatter.stack = Nil
|
||||||
|
}
|
||||||
|
|
||||||
|
def onEOS(): Unit =
|
||||||
|
logger.trace {
|
||||||
|
checkForUnclosedFormattersOnEOS()
|
||||||
|
reverseStackOnEOS()
|
||||||
|
header.create()
|
||||||
|
push()
|
||||||
|
cleanupOnEOS()
|
||||||
|
}
|
||||||
|
|
||||||
val importantTrigger: Char = Section.Marked.Important.marker
|
val importantTrigger: Char = Section.Marked.Important.marker
|
||||||
val infoTrigger: Char = Section.Marked.Info.marker
|
val infoTrigger: Char = Section.Marked.Info.marker
|
||||||
@ -763,56 +814,64 @@ case class DocParserDef() extends Parser[Doc] {
|
|||||||
* is it just ran as DocParser - for example in test suite
|
* is it just ran as DocParser - for example in test suite
|
||||||
*/
|
*/
|
||||||
final object documentation {
|
final object documentation {
|
||||||
def reverseSectionsStackOnEOF(): Unit = logger.trace {
|
def reverseSectionsStackOnEOF(): Unit =
|
||||||
section.stack = section.stack.reverse
|
logger.trace {
|
||||||
}
|
section.stack = section.stack.reverse
|
||||||
|
|
||||||
def reverseTagsStackOnEOF(): Unit = logger.trace {
|
|
||||||
tags.stack = tags.stack.reverse
|
|
||||||
}
|
|
||||||
|
|
||||||
def createDoc(): Unit = logger.trace {
|
|
||||||
val tags: Option[Tags] = createTags()
|
|
||||||
val synopsis: Option[Synopsis] = createSynopsis()
|
|
||||||
val body: Option[Body] = createBody()
|
|
||||||
result.doc = Some(Doc(tags, synopsis, body))
|
|
||||||
}
|
|
||||||
|
|
||||||
def createTags(): Option[Tags] = logger.trace {
|
|
||||||
tags.stack match {
|
|
||||||
case Nil => None
|
|
||||||
case x :: xs => Some(Tags(List1(x, xs)))
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
def createSynopsis(): Option[Synopsis] = logger.trace {
|
def reverseTagsStackOnEOF(): Unit =
|
||||||
section.stack match {
|
logger.trace {
|
||||||
case Nil => None
|
tags.stack = tags.stack.reverse
|
||||||
case x :: _ => Some(Synopsis(x))
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
def createBody(): Option[Body] = logger.trace {
|
def createDoc(): Unit =
|
||||||
section.stack match {
|
logger.trace {
|
||||||
case Nil => None
|
val tags: Option[Tags] = createTags()
|
||||||
case _ :: xs =>
|
val synopsis: Option[Synopsis] = createSynopsis()
|
||||||
xs match {
|
val body: Option[Body] = createBody()
|
||||||
case Nil => None
|
result.doc = Some(Doc(tags, synopsis, body))
|
||||||
case y :: ys => Some(Body(List1(y, ys)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
def onEOF(): Unit = logger.trace {
|
def createTags(): Option[Tags] =
|
||||||
section.onEOS()
|
logger.trace {
|
||||||
reverseSectionsStackOnEOF()
|
tags.stack match {
|
||||||
reverseTagsStackOnEOF()
|
case Nil => None
|
||||||
createDoc()
|
case x :: xs => Some(Tags(List1(x, xs)))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def isBeginning(): Boolean = logger.trace {
|
def createSynopsis(): Option[Synopsis] =
|
||||||
result.stack.isEmpty && section.stack.isEmpty
|
logger.trace {
|
||||||
}
|
section.stack match {
|
||||||
|
case Nil => None
|
||||||
|
case x :: _ => Some(Synopsis(x))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def createBody(): Option[Body] =
|
||||||
|
logger.trace {
|
||||||
|
section.stack match {
|
||||||
|
case Nil => None
|
||||||
|
case _ :: xs =>
|
||||||
|
xs match {
|
||||||
|
case Nil => None
|
||||||
|
case y :: ys => Some(Body(List1(y, ys)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def onEOF(): Unit =
|
||||||
|
logger.trace {
|
||||||
|
section.onEOS()
|
||||||
|
reverseSectionsStackOnEOF()
|
||||||
|
reverseTagsStackOnEOF()
|
||||||
|
createDoc()
|
||||||
|
}
|
||||||
|
|
||||||
|
def isBeginning(): Boolean =
|
||||||
|
logger.trace {
|
||||||
|
result.stack.isEmpty && section.stack.isEmpty
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ROOT || eof || documentation.onEOF()
|
ROOT || eof || documentation.onEOF()
|
||||||
|
@ -283,22 +283,17 @@ object DocParserHTMLGenerator {
|
|||||||
* reformatted [[AST.Documented]]
|
* reformatted [[AST.Documented]]
|
||||||
*
|
*
|
||||||
* @param ast - parsed AST.Module and reformatted using Doc Parser
|
* @param ast - parsed AST.Module and reformatted using Doc Parser
|
||||||
* @param cssFileName - name of file containing stylesheets for the HTML code
|
|
||||||
*/
|
*/
|
||||||
def generateHTMLForEveryDocumented(
|
def generateHTMLForEveryDocumented(ast: AST): String = {
|
||||||
ast: AST,
|
|
||||||
cssFileName: String = "style.css"
|
|
||||||
): String = {
|
|
||||||
ast.map { elem =>
|
ast.map { elem =>
|
||||||
elem match {
|
elem match {
|
||||||
case AST.Documented.any(documented) =>
|
case AST.Documented.any(documented) =>
|
||||||
val file = onHTMLRendering(documented, cssFileName)
|
val file = onHTMLRendering(documented)
|
||||||
return file.code.toString() + generateHTMLForEveryDocumented(
|
return file.code.toString() + generateHTMLForEveryDocumented(
|
||||||
documented,
|
documented
|
||||||
cssFileName
|
|
||||||
)
|
)
|
||||||
case _ =>
|
case _ =>
|
||||||
generateHTMLForEveryDocumented(elem, cssFileName)
|
generateHTMLForEveryDocumented(elem)
|
||||||
}
|
}
|
||||||
elem
|
elem
|
||||||
}
|
}
|
||||||
@ -309,14 +304,10 @@ object DocParserHTMLGenerator {
|
|||||||
* Function to generate HTML File from pure doc comment w/o connection to AST
|
* Function to generate HTML File from pure doc comment w/o connection to AST
|
||||||
*
|
*
|
||||||
* @param doc - Doc from Doc Parser
|
* @param doc - Doc from Doc Parser
|
||||||
* @param cssLink - string containing CSS file name
|
|
||||||
* @return - HTML Code from Doc
|
* @return - HTML Code from Doc
|
||||||
*/
|
*/
|
||||||
def generateHTMLPureDoc(
|
def generateHTMLPureDoc(doc: Doc): String = {
|
||||||
doc: Doc,
|
HTML.html(createHTMLHead(""), HTML.body(doc.html)).toString()
|
||||||
cssLink: String = "style.css"
|
|
||||||
): String = {
|
|
||||||
HTML.html(createHTMLHead("", cssLink), HTML.body(doc.html)).toString()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
@ -328,14 +319,10 @@ object DocParserHTMLGenerator {
|
|||||||
* Runner finished it's job
|
* Runner finished it's job
|
||||||
*
|
*
|
||||||
* @param documented - documented made by Doc Parser Runner from AST and Doc
|
* @param documented - documented made by Doc Parser Runner from AST and Doc
|
||||||
* @param cssFileName - name of file containing stylesheets for the HTML code
|
|
||||||
* @return - HTML code with file name
|
* @return - HTML code with file name
|
||||||
*/
|
*/
|
||||||
def onHTMLRendering(
|
def onHTMLRendering(documented: AST.Documented): htmlFile = {
|
||||||
documented: AST.Documented,
|
val htmlCode = renderHTML(documented.ast, documented.doc)
|
||||||
cssFileName: String
|
|
||||||
): htmlFile = {
|
|
||||||
val htmlCode = renderHTML(documented.ast, documented.doc, cssFileName)
|
|
||||||
val astLines = documented.ast.show().split("\n")
|
val astLines = documented.ast.show().split("\n")
|
||||||
val fileName =
|
val fileName =
|
||||||
astLines.head
|
astLines.head
|
||||||
@ -352,18 +339,13 @@ object DocParserHTMLGenerator {
|
|||||||
*
|
*
|
||||||
* @param ast - AST from Parser
|
* @param ast - AST from Parser
|
||||||
* @param doc - Doc from Doc Parser
|
* @param doc - Doc from Doc Parser
|
||||||
* @param cssLink - string containing CSS file name
|
|
||||||
* @return - HTML Code from Doc and contents of [[AST.Def]] or
|
* @return - HTML Code from Doc and contents of [[AST.Def]] or
|
||||||
* [[AST.App.Infix]], with optional title made from AST
|
* [[AST.App.Infix]], with optional title made from AST
|
||||||
*/
|
*/
|
||||||
def renderHTML(
|
def renderHTML(ast: AST, doc: Doc): TypedTag[String] = {
|
||||||
ast: AST,
|
|
||||||
doc: Doc,
|
|
||||||
cssLink: String
|
|
||||||
): TypedTag[String] = {
|
|
||||||
val title = ast.show().split("\n").head.split("=").head
|
val title = ast.show().split("\n").head.split("=").head
|
||||||
val documentation = DocumentedToHtml(ast, doc)
|
val documentation = DocumentedToHtml(ast, doc)
|
||||||
HTML.html(createHTMLHead(title, cssLink), HTML.body(documentation))
|
HTML.html(createHTMLHead(title), HTML.body(documentation))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -376,10 +358,7 @@ object DocParserHTMLGenerator {
|
|||||||
* @return - HTML Code from Doc and contents of [[AST.Def]] or
|
* @return - HTML Code from Doc and contents of [[AST.Def]] or
|
||||||
* [[AST.App.Infix]]
|
* [[AST.App.Infix]]
|
||||||
*/
|
*/
|
||||||
def DocumentedToHtml(
|
def DocumentedToHtml(ast: AST, doc: Doc): TypedTag[String] = {
|
||||||
ast: AST,
|
|
||||||
doc: Doc
|
|
||||||
): TypedTag[String] = {
|
|
||||||
val docClass = HTML.`class` := "Documentation"
|
val docClass = HTML.`class` := "Documentation"
|
||||||
val astHeadCls = HTML.`class` := "ASTHead"
|
val astHeadCls = HTML.`class` := "ASTHead"
|
||||||
val astHTML = createHTMLFromAST(ast)
|
val astHTML = createHTMLFromAST(ast)
|
||||||
@ -576,18 +555,14 @@ object DocParserHTMLGenerator {
|
|||||||
* Function invoked by [[DocumentedToHtml]] to create HTML.Head part of file
|
* Function invoked by [[DocumentedToHtml]] to create HTML.Head part of file
|
||||||
*
|
*
|
||||||
* @param title - HTML page title
|
* @param title - HTML page title
|
||||||
* @param cssLink - string containing CSS file name
|
|
||||||
* @return - HTML Head Code
|
* @return - HTML Head Code
|
||||||
*/
|
*/
|
||||||
def createHTMLHead(title: String, cssLink: String): TypedTag[String] = {
|
def createHTMLHead(title: String): TypedTag[String] = {
|
||||||
val metaEquiv = HTML.httpEquiv := "Content-Type"
|
val metaEquiv = HTML.httpEquiv := "Content-Type"
|
||||||
val metaCont = HTML.content := "text/html"
|
val metaCont = HTML.content := "text/html"
|
||||||
val metaChar = HTML.charset := "UTF-8"
|
val metaChar = HTML.charset := "UTF-8"
|
||||||
val meta = HTML.meta(metaEquiv)(metaCont)(metaChar)
|
val meta = HTML.meta(metaEquiv)(metaCont)(metaChar)
|
||||||
val cssRel = HTML.rel := "stylesheet"
|
|
||||||
val cssHref = HTML.href := cssLink
|
|
||||||
val css = HTML.link(cssRel)(cssHref)
|
|
||||||
val fileTitle = scalatags.Text.tags2.title(title)
|
val fileTitle = scalatags.Text.tags2.title(title)
|
||||||
HTML.head(meta, css)(fileTitle)
|
HTML.head(meta)(fileTitle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,446 +0,0 @@
|
|||||||
/*///////////
|
|
||||||
//// DOM ////
|
|
||||||
///////////*/
|
|
||||||
|
|
||||||
$defaultLineHeight: 1.52947
|
|
||||||
$defaultFontSize: 17px
|
|
||||||
$defaultFontFamily: "SF Pro Text", "SF Pro Icons", "Helvetica Neue", "Helvetica", "Arial", sans-serif
|
|
||||||
$defaultFontWeight: 400
|
|
||||||
$defaultBoldFontWeight: 600
|
|
||||||
$defaultHeaderFontWeight: 500
|
|
||||||
$defaultLetterSpacing: -0.021em
|
|
||||||
$defaultTextColor: #333333
|
|
||||||
$defaultCodeColor: #0070c9
|
|
||||||
|
|
||||||
|
|
||||||
body
|
|
||||||
-webkit-font-smoothing: antialiased
|
|
||||||
font-style: normal
|
|
||||||
word-wrap: break-word
|
|
||||||
font-size: $defaultFontSize
|
|
||||||
line-height: $defaultLineHeight
|
|
||||||
font-weight: $defaultFontWeight
|
|
||||||
letter-spacing: $defaultLetterSpacing
|
|
||||||
font-family: $defaultFontFamily
|
|
||||||
background-color: white
|
|
||||||
color: $defaultTextColor
|
|
||||||
margin: 0
|
|
||||||
padding: 0
|
|
||||||
|
|
||||||
p
|
|
||||||
display: block
|
|
||||||
margin-block-start: 1em
|
|
||||||
margin-block-end: 1em
|
|
||||||
margin-inline-start: 0
|
|
||||||
margin-inline-end: 0
|
|
||||||
|
|
||||||
a:hover
|
|
||||||
color: $defaultCodeColor !important
|
|
||||||
text-decoration: inherit
|
|
||||||
|
|
||||||
a
|
|
||||||
color: $defaultTextColor
|
|
||||||
background-color: transparent
|
|
||||||
text-decoration: inherit
|
|
||||||
display: inline-block
|
|
||||||
transition: all 0.3s ease
|
|
||||||
|
|
||||||
img
|
|
||||||
display: block
|
|
||||||
|
|
||||||
code
|
|
||||||
color: $defaultCodeColor
|
|
||||||
background-color: transparent
|
|
||||||
font-size: inherit
|
|
||||||
font-family: $defaultFontFamily
|
|
||||||
line-height: inherit
|
|
||||||
display: inline-block
|
|
||||||
white-space: pre-wrap
|
|
||||||
|
|
||||||
button
|
|
||||||
display: inline-block
|
|
||||||
padding: 8px 30px
|
|
||||||
margin: 10px 0
|
|
||||||
outline: none
|
|
||||||
background-color: transparent
|
|
||||||
border: 1px solid $defaultTextColor
|
|
||||||
color: $defaultTextColor
|
|
||||||
border-radius: 5px
|
|
||||||
font-size: 13px
|
|
||||||
vertical-align: top
|
|
||||||
transition: all 0.3s ease
|
|
||||||
|
|
||||||
button:hover
|
|
||||||
background-color: $defaultTextColor
|
|
||||||
color: #e5e5e5
|
|
||||||
|
|
||||||
b
|
|
||||||
font-weight: $defaultBoldFontWeight
|
|
||||||
|
|
||||||
h1
|
|
||||||
font-size: 34px
|
|
||||||
line-height: 1.08824
|
|
||||||
font-weight: $defaultHeaderFontWeight
|
|
||||||
letter-spacing: 0.01em
|
|
||||||
|
|
||||||
|
|
||||||
h2
|
|
||||||
font-size: 28px
|
|
||||||
line-height: 1.1073
|
|
||||||
font-weight: $defaultHeaderFontWeight
|
|
||||||
letter-spacing: 0.012em
|
|
||||||
|
|
||||||
|
|
||||||
.Body h2
|
|
||||||
margin: 0.65rem 0 0
|
|
||||||
|
|
||||||
li
|
|
||||||
padding-left: 10px
|
|
||||||
|
|
||||||
|
|
||||||
/*///////////////////
|
|
||||||
//// Invalid AST ////
|
|
||||||
///////////////////*/
|
|
||||||
|
|
||||||
// Creator - a special mode for displaying parsing errors in output
|
|
||||||
.creator
|
|
||||||
.Unclosed,
|
|
||||||
.invalidIndent,
|
|
||||||
.invalidLink
|
|
||||||
display: inline
|
|
||||||
color: orangered
|
|
||||||
|
|
||||||
.Tags
|
|
||||||
.UNRECOGNIZED
|
|
||||||
border: 2px solid
|
|
||||||
color: orangered
|
|
||||||
|
|
||||||
.Unclosed,
|
|
||||||
.invalidIndent,
|
|
||||||
.invalidLink
|
|
||||||
display: inline
|
|
||||||
|
|
||||||
/*//////////////
|
|
||||||
//// Header ////
|
|
||||||
//////////////*/
|
|
||||||
|
|
||||||
.Header
|
|
||||||
font-size: 19px
|
|
||||||
font-weight: $defaultHeaderFontWeight
|
|
||||||
|
|
||||||
|
|
||||||
.Important .Header,
|
|
||||||
.Info .Header,
|
|
||||||
.Example .Header
|
|
||||||
margin-bottom: 0.7em
|
|
||||||
font-weight: $defaultBoldFontWeight
|
|
||||||
letter-spacing: $defaultLetterSpacing
|
|
||||||
line-height: $defaultFontSize
|
|
||||||
font-synthesis: none
|
|
||||||
font-family: $defaultFontFamily
|
|
||||||
|
|
||||||
/*////////////
|
|
||||||
//// Tags ////
|
|
||||||
////////////*/
|
|
||||||
|
|
||||||
.Tags
|
|
||||||
margin-left: auto
|
|
||||||
margin-right: auto
|
|
||||||
margin-bottom: 20px
|
|
||||||
padding-top: 15px
|
|
||||||
|
|
||||||
.DEPRECATED,
|
|
||||||
.MODIFIED,
|
|
||||||
.ADDED,
|
|
||||||
.UPCOMING,
|
|
||||||
.REMOVED,
|
|
||||||
.UNRECOGNIZED
|
|
||||||
line-height: 1.5
|
|
||||||
font-weight: $defaultFontWeight
|
|
||||||
border-radius: 4px
|
|
||||||
font-size: 12px
|
|
||||||
letter-spacing: $defaultLetterSpacing
|
|
||||||
display: inline-flex
|
|
||||||
padding: 5px 15px
|
|
||||||
margin: 2px
|
|
||||||
white-space: nowrap
|
|
||||||
background: transparent
|
|
||||||
|
|
||||||
.DEPRECATED
|
|
||||||
$col: #d20606
|
|
||||||
border: 1px solid $col
|
|
||||||
color: $col
|
|
||||||
|
|
||||||
.MODIFIED
|
|
||||||
$col: #003ec3
|
|
||||||
border: 1px solid $col
|
|
||||||
color: $col
|
|
||||||
|
|
||||||
.ADDED
|
|
||||||
$col: #79A129
|
|
||||||
border: 1px solid $col
|
|
||||||
color: $col
|
|
||||||
|
|
||||||
.UPCOMING,
|
|
||||||
.REMOVED,
|
|
||||||
.UNRECOGNIZED
|
|
||||||
$col: #666666
|
|
||||||
border: 1px solid $col
|
|
||||||
color: $col
|
|
||||||
|
|
||||||
.ExtForTagDetails
|
|
||||||
margin: 0 3px
|
|
||||||
color: #999999
|
|
||||||
|
|
||||||
/*////////////////
|
|
||||||
//// Sections ////
|
|
||||||
////////////////*/
|
|
||||||
|
|
||||||
.Raw,
|
|
||||||
.Important,
|
|
||||||
.Info,
|
|
||||||
.CodeBlock,
|
|
||||||
.Example
|
|
||||||
margin-top: 0
|
|
||||||
margin-left: auto
|
|
||||||
margin-right: auto
|
|
||||||
position: relative
|
|
||||||
text-decoration: inherit
|
|
||||||
|
|
||||||
|
|
||||||
.Body .Raw
|
|
||||||
margin-bottom: 0.6rem
|
|
||||||
font-size: $defaultFontSize
|
|
||||||
line-height: $defaultLineHeight
|
|
||||||
font-weight: $defaultFontWeight
|
|
||||||
letter-spacing: $defaultLetterSpacing
|
|
||||||
font-family: $defaultFontFamily
|
|
||||||
color: $defaultTextColor
|
|
||||||
font-style: normal
|
|
||||||
|
|
||||||
.Important,
|
|
||||||
.Info,
|
|
||||||
.CodeBlock,
|
|
||||||
.Example
|
|
||||||
font-size: $defaultFontSize
|
|
||||||
padding: 15px 10px 15px 20px
|
|
||||||
border: 0
|
|
||||||
border-radius: 6px
|
|
||||||
margin: 0.7em 0
|
|
||||||
|
|
||||||
|
|
||||||
.Important
|
|
||||||
background-color: #FBECC2
|
|
||||||
|
|
||||||
|
|
||||||
.Info
|
|
||||||
background-color: #D6E1CA
|
|
||||||
|
|
||||||
|
|
||||||
.Example
|
|
||||||
background-color: #fafafa
|
|
||||||
|
|
||||||
.CodeBlock
|
|
||||||
background-color: #fefefe
|
|
||||||
margin: 10px 20px
|
|
||||||
display: none
|
|
||||||
|
|
||||||
code
|
|
||||||
font-family: monospace
|
|
||||||
|
|
||||||
|
|
||||||
/*///////////////////////////////////
|
|
||||||
//// HTML generated - Def, Infix ////
|
|
||||||
///////////////////////////////////*/
|
|
||||||
|
|
||||||
.Def
|
|
||||||
margin: 40px auto auto
|
|
||||||
padding: 0 15px
|
|
||||||
text-decoration: inherit
|
|
||||||
|
|
||||||
.Synopsis,
|
|
||||||
.Body,
|
|
||||||
.Tags,
|
|
||||||
.ASTData
|
|
||||||
padding-left: 0
|
|
||||||
text-decoration: inherit
|
|
||||||
|
|
||||||
.Synopsis
|
|
||||||
padding: 0
|
|
||||||
margin-bottom: 15px
|
|
||||||
font-size: $defaultFontSize
|
|
||||||
font-weight: $defaultFontWeight
|
|
||||||
color: $defaultTextColor
|
|
||||||
font-style: normal
|
|
||||||
|
|
||||||
.constr
|
|
||||||
padding: 25px 0
|
|
||||||
margin: 0
|
|
||||||
|
|
||||||
.DefDoc
|
|
||||||
.Body
|
|
||||||
display: none
|
|
||||||
|
|
||||||
.documentation
|
|
||||||
display: inline-flex
|
|
||||||
width: 100%
|
|
||||||
margin-bottom: 10px
|
|
||||||
|
|
||||||
|
|
||||||
.ASTHead
|
|
||||||
width: 30% !important
|
|
||||||
margin: 10px 0
|
|
||||||
|
|
||||||
.DefTitle,
|
|
||||||
.Infix
|
|
||||||
padding: 0
|
|
||||||
font-size: $defaultFontSize
|
|
||||||
font-weight: $defaultFontWeight
|
|
||||||
font-style: normal
|
|
||||||
text-decoration: inherit
|
|
||||||
|
|
||||||
.ASTData
|
|
||||||
width: 70% !important
|
|
||||||
|
|
||||||
.Doc
|
|
||||||
text-decoration: inherit
|
|
||||||
|
|
||||||
.Synopsis
|
|
||||||
text-decoration: inherit
|
|
||||||
margin: 10px 0
|
|
||||||
|
|
||||||
.Tags
|
|
||||||
margin: 2px 0 0 auto
|
|
||||||
padding: 0
|
|
||||||
|
|
||||||
.DefNoDoc
|
|
||||||
padding-bottom: 10px
|
|
||||||
|
|
||||||
.DefTitle
|
|
||||||
display: inline-flex
|
|
||||||
font-size: x-large
|
|
||||||
font-weight: $defaultFontWeight
|
|
||||||
margin-bottom: 20px
|
|
||||||
|
|
||||||
|
|
||||||
.DefArgs
|
|
||||||
margin-left: 5px
|
|
||||||
font-weight: $defaultFontWeight
|
|
||||||
color: $defaultCodeColor
|
|
||||||
|
|
||||||
/*/////////////////////////
|
|
||||||
//// Synopsis & Detail ////
|
|
||||||
/////////////////////////*/
|
|
||||||
|
|
||||||
.Synopsis,
|
|
||||||
.Body
|
|
||||||
margin: 0 auto
|
|
||||||
padding: 5px
|
|
||||||
text-align: left
|
|
||||||
|
|
||||||
|
|
||||||
.Synopsis
|
|
||||||
margin-top: 35px
|
|
||||||
font-size: 20px
|
|
||||||
|
|
||||||
.Documentation
|
|
||||||
.ASTData,
|
|
||||||
.ASTHead
|
|
||||||
text-align: left
|
|
||||||
line-height: 1.05
|
|
||||||
border-radius: 6px
|
|
||||||
|
|
||||||
.ASTData
|
|
||||||
width: 100%
|
|
||||||
background-color: #fafafa
|
|
||||||
|
|
||||||
|
|
||||||
.ASTHead
|
|
||||||
margin: 20px auto 5px
|
|
||||||
background-color: #ffffff
|
|
||||||
|
|
||||||
.DefTitle
|
|
||||||
font-size: 42px
|
|
||||||
margin: 0
|
|
||||||
|
|
||||||
.ASTData
|
|
||||||
.ASTHead
|
|
||||||
background-color: #fafafa
|
|
||||||
|
|
||||||
.DefTitle
|
|
||||||
font-size: x-large
|
|
||||||
|
|
||||||
.Documented
|
|
||||||
margin: 0
|
|
||||||
width: 100%
|
|
||||||
background-color: #ffffff
|
|
||||||
|
|
||||||
.DefNoBody
|
|
||||||
text-decoration: inherit
|
|
||||||
|
|
||||||
|
|
||||||
/*///////////////////////////
|
|
||||||
//// RWD ////
|
|
||||||
///////////////////////////*/
|
|
||||||
@media (max-width: 500px)
|
|
||||||
.Synopsis,
|
|
||||||
.Body,
|
|
||||||
.Tags,
|
|
||||||
.Documentation .ASTData .Def
|
|
||||||
max-width: 380px
|
|
||||||
|
|
||||||
.Documentation .ASTHead,
|
|
||||||
.DefNoBody,
|
|
||||||
.DefBody
|
|
||||||
max-width: 400px
|
|
||||||
|
|
||||||
.Def
|
|
||||||
padding: 5px
|
|
||||||
|
|
||||||
@media (min-width: 500px)
|
|
||||||
.Synopsis,
|
|
||||||
.Body,
|
|
||||||
.Tags,
|
|
||||||
.Documentation .ASTData .Def
|
|
||||||
max-width: 440px
|
|
||||||
|
|
||||||
.Documentation .ASTHead,
|
|
||||||
.DefNoBody,
|
|
||||||
.DefBody
|
|
||||||
max-width: 470px
|
|
||||||
|
|
||||||
@media (min-width: 600px)
|
|
||||||
.Synopsis,
|
|
||||||
.Body,
|
|
||||||
.Tags,
|
|
||||||
.Documentation .ASTData .Def
|
|
||||||
max-width: 490px
|
|
||||||
|
|
||||||
.Documentation .ASTHead,
|
|
||||||
.DefNoBody,
|
|
||||||
.DefBody
|
|
||||||
max-width: 520px
|
|
||||||
|
|
||||||
@media (min-width: 900px)
|
|
||||||
.Synopsis,
|
|
||||||
.Body,
|
|
||||||
.Tags,
|
|
||||||
.Documentation .ASTData .Def
|
|
||||||
max-width: 680px
|
|
||||||
|
|
||||||
.Documentation .ASTHead,
|
|
||||||
.DefNoBody,
|
|
||||||
.DefBody
|
|
||||||
max-width: 710px
|
|
||||||
|
|
||||||
@media (min-width: 1300px)
|
|
||||||
.Synopsis,
|
|
||||||
.Body,
|
|
||||||
.Tags,
|
|
||||||
.Documentation .ASTData .Def
|
|
||||||
max-width: 790px
|
|
||||||
|
|
||||||
.Documentation .ASTHead,
|
|
||||||
.DefNoBody,
|
|
||||||
.DefBody
|
|
||||||
max-width: 820px
|
|
@ -573,7 +573,6 @@ object Main extends scala.App {
|
|||||||
println("===== DOCUMENTATION =====")
|
println("===== DOCUMENTATION =====")
|
||||||
val droppedMeta = parser.dropMacroMeta(mod)
|
val droppedMeta = parser.dropMacroMeta(mod)
|
||||||
val doc = DocParserRunner.createDocs(droppedMeta)
|
val doc = DocParserRunner.createDocs(droppedMeta)
|
||||||
val cssFileName = "style.css"
|
|
||||||
|
|
||||||
println(Debug.pretty(doc.toString))
|
println(Debug.pretty(doc.toString))
|
||||||
println("------")
|
println("------")
|
||||||
|
Loading…
Reference in New Issue
Block a user