diff options
author | Vlad Ureche <vlad.ureche@gmail.com> | 2012-03-20 01:20:52 +0100 |
---|---|---|
committer | Vlad Ureche <vlad.ureche@gmail.com> | 2012-03-20 01:20:52 +0100 |
commit | c7d852558302c5c4abc2eadacf42d51d5050c7f2 (patch) | |
tree | f39882e67e3eb443bade2b2fb13a76d2141108d4 | |
parent | bc7bf663f2df564805fa5121de7b0006cf2149f2 (diff) | |
download | scala-c7d852558302c5c4abc2eadacf42d51d5050c7f2.tar.gz scala-c7d852558302c5c4abc2eadacf42d51d5050c7f2.tar.bz2 scala-c7d852558302c5c4abc2eadacf42d51d5050c7f2.zip |
Adapted indentation in scaladoc code blocks
and fixed a pesky crash in the syntax highlighting caused by invalid
chars (0x0E) in MarkupParser.scala.
-rw-r--r-- | src/compiler/scala/tools/nsc/doc/html/SyntaxHigh.scala | 12 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala | 60 | ||||
-rw-r--r-- | src/library/scala/xml/parsing/MarkupParser.scala | 22 | ||||
-rw-r--r-- | test/scaladoc/resources/code-indent.scala | 37 | ||||
-rw-r--r-- | test/scaladoc/scala/html/HtmlFactoryTest.scala | 19 |
5 files changed, 131 insertions, 19 deletions
diff --git a/src/compiler/scala/tools/nsc/doc/html/SyntaxHigh.scala b/src/compiler/scala/tools/nsc/doc/html/SyntaxHigh.scala index f19f449d2c..f67abc58da 100644 --- a/src/compiler/scala/tools/nsc/doc/html/SyntaxHigh.scala +++ b/src/compiler/scala/tools/nsc/doc/html/SyntaxHigh.scala @@ -219,24 +219,24 @@ private[html] object SyntaxHigh { parse(" ", i+1) case '&' => parse("&", i+1) - case '<' => + case '<' if i+1 < buf.length => val ch = buf(i+1).toChar if (ch == '-' || ch == ':' || ch == '%') parse("<span class=\"kw\"><"+ch+"</span>", i+2) else parse("<", i+1) case '>' => - if (buf(i+1) == ':') + if (i+1 < buf.length && buf(i+1) == ':') parse("<span class=\"kw\">>:</span>", i+2) else parse(">", i+1) case '=' => - if (buf(i+1) == '>') + if (i+1 < buf.length && buf(i+1) == '>') parse("<span class=\"kw\">=></span>", i+2) else parse(buf(i).toChar.toString, i+1) case '/' => - if (buf(i+1) == '/' || buf(i+1) == '*') { + if (i+1 < buf.length && (buf(i+1) == '/' || buf(i+1) == '*')) { val c = comment(i+1) parse("<span class=\"cmt\">"+c+"</span>", i+c.length) } else @@ -257,9 +257,9 @@ private[html] object SyntaxHigh { else parse(buf(i).toChar.toString, i+1) case _ => - if (i == 0 || !Character.isJavaIdentifierPart(buf(i-1).toChar)) { + if (i == 0 || (i >= 1 && !Character.isJavaIdentifierPart(buf(i-1).toChar))) { if (Character.isDigit(buf(i)) || - (buf(i) == '.' && Character.isDigit(buf(i+1)))) { + (buf(i) == '.' && i + 1 < buf.length && Character.isDigit(buf(i+1)))) { val s = numlit(i) parse("<span class=\"num\">"+s+"</span>", i+s.length) } else { diff --git a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala b/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala index efa524503c..dbbd6ab432 100644 --- a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala @@ -491,7 +491,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory => else jump("}}}") blockEnded("code block") - Code(getRead) + Code(normalizeIndentation(getRead)) } /** {{{ title ::= ('=' inline '=' | "==" inline "==" | ...) '\n' }}} */ @@ -732,6 +732,64 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory => nextChar() } + /** + * Eliminates the (common) leading spaces in all lines, based on the first line + * For indented pieces of code, it reduces the indent to the least whitespace prefix: + * {{{ + * indented example + * another indented line + * if (condition) + * then do something; + * ^ this is the least whitespace prefix + * }}} + */ + def normalizeIndentation(_code: String): String = { + + var code = _code.trim + var maxSkip = Integer.MAX_VALUE + var crtSkip = 0 + var wsArea = true + var index = 0 + var firstLine = true + var emptyLine = true + + while (index < code.length) { + code(index) match { + case ' ' => + if (wsArea) + crtSkip += 1 + case c => + wsArea = (c == '\n') + maxSkip = if (firstLine || emptyLine) maxSkip else if (maxSkip <= crtSkip) maxSkip else crtSkip + crtSkip = if (c == '\n') 0 else crtSkip + firstLine = if (c == '\n') false else firstLine + emptyLine = if (c == '\n') true else false + } + index += 1 + } + + if (maxSkip == 0) + code + else { + index = 0 + val builder = new StringBuilder + while (index < code.length) { + builder.append(code(index)) + if (code(index) == '\n') { + // we want to skip as many spaces are available, if there are less spaces (like on empty lines, do not + // over-consume them) + index += 1 + val limit = index + maxSkip + while ((index < code.length) && (code(index) == ' ') && index < limit) + index += 1 + } + else + index += 1 + } + builder.toString + } + } + def checkParaEnded(): Boolean = { (char == endOfText) || ((char == endOfLine) && { diff --git a/src/library/scala/xml/parsing/MarkupParser.scala b/src/library/scala/xml/parsing/MarkupParser.scala index 1de08b3025..74781914e3 100644 --- a/src/library/scala/xml/parsing/MarkupParser.scala +++ b/src/library/scala/xml/parsing/MarkupParser.scala @@ -134,7 +134,7 @@ trait MarkupParser extends MarkupParserCommon with TokenTests // /** {{{ - * <? prolog ::= xml S ... ?> + * <? prolog ::= xml S ... ?> * }}} */ def xmlProcInstr(): MetaData = { xToken("xml") @@ -195,7 +195,7 @@ trait MarkupParser extends MarkupParserCommon with TokenTests } /** {{{ - * <? prolog ::= xml S? + * <? prolog ::= xml S? * // this is a bit more lenient than necessary... * }}} */ def prolog(): (Option[String], Option[String], Option[Boolean]) = @@ -355,7 +355,7 @@ trait MarkupParser extends MarkupParserCommon with TokenTests } /** {{{ - * '<! CharData ::= [CDATA[ ( {char} - {char}"]]>"{char} ) ']]>' + * '<! CharData ::= [CDATA[ ( {char} - {char}"]]>"{char} ) ']]>' * * see [15] * }}} */ @@ -369,7 +369,7 @@ trait MarkupParser extends MarkupParserCommon with TokenTests } /** {{{ - * Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->' + * Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->' * * see [15] * }}} */ @@ -399,7 +399,7 @@ trait MarkupParser extends MarkupParserCommon with TokenTests } /** {{{ - * '<' content1 ::= ... + * '<' content1 ::= ... * }}} */ def content1(pscope: NamespaceBinding, ts: NodeBuffer) { ch match { @@ -420,7 +420,7 @@ trait MarkupParser extends MarkupParserCommon with TokenTests } /** {{{ - * content1 ::= '<' content1 | '&' charref ... + * content1 ::= '<' content1 | '&' charref ... * }}} */ def content(pscope: NamespaceBinding): NodeSeq = { var ts = new NodeBuffer @@ -490,7 +490,7 @@ trait MarkupParser extends MarkupParserCommon with TokenTests /** parses document type declaration and assigns it to instance variable * dtd. * {{{ - * <! parseDTD ::= DOCTYPE name ... > + * <! parseDTD ::= DOCTYPE name ... > * }}} */ def parseDTD() { // dirty but fast var extID: ExternalID = null @@ -545,8 +545,8 @@ trait MarkupParser extends MarkupParserCommon with TokenTests } /** {{{ - * '<' element ::= xmlTag1 '>' { xmlExpr | '{' simpleExpr '}' } ETag - * | xmlTag1 '/' '>' + * '<' element ::= xmlTag1 '>' { xmlExpr | '{' simpleExpr '}' } ETag + * | xmlTag1 '/' '>' * }}} */ def element1(pscope: NamespaceBinding): NodeSeq = { val pos = this.pos @@ -778,7 +778,7 @@ trait MarkupParser extends MarkupParserCommon with TokenTests } /** {{{ - * <! attlist := ATTLIST + * <! attlist := ATTLIST * }}} */ def attrDecl() = { xToken("TTLIST") @@ -824,7 +824,7 @@ trait MarkupParser extends MarkupParserCommon with TokenTests } /** {{{ - * <! element := ELEMENT + * <! element := ELEMENT * }}} */ def entityDecl() = { var isParameterEntity = false diff --git a/test/scaladoc/resources/code-indent.scala b/test/scaladoc/resources/code-indent.scala new file mode 100644 index 0000000000..88946ffc7f --- /dev/null +++ b/test/scaladoc/resources/code-indent.scala @@ -0,0 +1,37 @@ +/** + * This is an example of indented comments: + * {{{ + * a typicial indented + * comment on multiple + * comment lines + * }}} + * {{{ one liner }}} + * {{{ two lines, one useful + * }}} + * {{{ + * line1 + * line2 + * line3 + * line4}}} + * {{{ + * a ragged example + * a (condition) + * the t h e n branch + * an alternative + * the e l s e branch + * }}} + * NB: Trailing spaces are necessary for this test! + * {{{ + * l1 + * + * l2 + * + * l3 + * + * l4 + * + * l5 + * }}} + + */ +class C diff --git a/test/scaladoc/scala/html/HtmlFactoryTest.scala b/test/scaladoc/scala/html/HtmlFactoryTest.scala index d46a9581b9..818230238d 100644 --- a/test/scaladoc/scala/html/HtmlFactoryTest.scala +++ b/test/scaladoc/scala/html/HtmlFactoryTest.scala @@ -580,7 +580,24 @@ object Test extends Properties("HtmlFactory") { """, true) ) } - + + property("Indentation normalization for code blocks") = { + val files = createTemplates("code-indent.scala") + + files("C.html") match { + case node: scala.xml.Node => { + val s = node.toString + s.contains("<pre>a typicial indented\ncomment on multiple\ncomment lines</pre>") && + s.contains("<pre>one liner</pre>") && + s.contains("<pre>two lines, one useful</pre>") && + s.contains("<pre>line1\nline2\nline3\nline4</pre>") && + s.contains("<pre>a ragged example\na (condition)\n the t h e n branch\nan alternative\n the e l s e branch</pre>") && + s.contains("<pre>l1\n\nl2\n\nl3\n\nl4\n\nl5</pre>") + } + case _ => false + } + } + { val files = createTemplates("basic.scala") //println(files) |