From e8f4e79d04b7583849a30a6490cc0f4fe4eb5e4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sat, 11 Apr 2015 02:33:26 +0200 Subject: [PATCH] Rendering multiline list elements indented (checking if line starts with `- ` or `* `). --- .../doc/en_US/general/example.md | 8 ++++- .../markdown/segment/CodeSegment.scala | 33 +++++++++++-------- .../renderer/markdown/segment/Segment.scala | 3 ++ .../markdown/segment/TextSegment.scala | 33 +++++++++++-------- 4 files changed, 50 insertions(+), 27 deletions(-) diff --git a/src/main/resources/assets/opencomputers/doc/en_US/general/example.md b/src/main/resources/assets/opencomputers/doc/en_US/general/example.md index 8044e0ecd..9e2985a3a 100644 --- a/src/main/resources/assets/opencomputers/doc/en_US/general/example.md +++ b/src/main/resources/assets/opencomputers/doc/en_US/general/example.md @@ -35,6 +35,9 @@ isn't*. # not a header +* this is a list item and the text that will be wrapped will be indented appropriately +- this should also `work for code rendered text, if it doesn't i` will be a sad person + asdasd ![oh my god, the recursion!](img/example.png) qweqwe And finally, [this is a link!](https://avatars1.githubusercontent.com/u/514903). @@ -45,4 +48,7 @@ And finally, [this is a link!](https://avatars1.githubusercontent.com/u/514903). wrap testing 12345678901234567890.1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 -`123456789012345678901234567890.12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890` \ No newline at end of file +`123456789012345678901234567890.12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890` + +* 12345678901234567890.1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 +- `123456789012345678901234567890.12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890` \ No newline at end of file diff --git a/src/main/scala/li/cil/oc/client/renderer/markdown/segment/CodeSegment.scala b/src/main/scala/li/cil/oc/client/renderer/markdown/segment/CodeSegment.scala index 0ecbc8d9f..ec942d37f 100644 --- a/src/main/scala/li/cil/oc/client/renderer/markdown/segment/CodeSegment.scala +++ b/src/main/scala/li/cil/oc/client/renderer/markdown/segment/CodeSegment.scala @@ -6,16 +6,19 @@ import net.minecraft.client.gui.FontRenderer import org.lwjgl.opengl.GL11 private[markdown] class CodeSegment(protected val parent: Segment, val text: String) extends Segment { - final val breaks = Set(' ', '.', ',', ':', ';', '!', '?', '_', '=', '-', '+', '*', '/', '\\', ')', '\'', '"') + private final val breaks = Set(' ', '.', ',', ':', ';', '!', '?', '_', '=', '-', '+', '*', '/', '\\', ')', '\'', '"') + private final val lists = Set("- ", "* ") + private lazy val rootPrefix = root.asInstanceOf[TextSegment].text.take(2) override def height(indent: Int, maxWidth: Int, renderer: FontRenderer): Int = { var lines = 0 var chars = text - var lineChars = maxChars(chars, maxWidth - indent, maxWidth) - while (chars.length > lineChars) { + val wrapIndent = computeWrapIndent(renderer) + var numChars = maxChars(chars, maxWidth - indent, maxWidth - wrapIndent) + while (chars.length > numChars) { lines += 1 - chars = chars.drop(lineChars).dropWhile(_.isWhitespace) - lineChars = maxChars(chars, maxWidth, maxWidth) + chars = chars.drop(numChars).dropWhile(_.isWhitespace) + numChars = maxChars(chars, maxWidth - wrapIndent, maxWidth - wrapIndent) } lines * Document.lineHeight(renderer) } @@ -23,11 +26,12 @@ private[markdown] class CodeSegment(protected val parent: Segment, val text: Str override def width(indent: Int, maxWidth: Int, renderer: FontRenderer): Int = { var currentX = indent var chars = text - var lineChars = maxChars(chars, maxWidth - indent, maxWidth) - while (chars.length > lineChars) { - chars = chars.drop(lineChars).dropWhile(_.isWhitespace) - lineChars = maxChars(chars, maxWidth, maxWidth) - currentX = 1 + val wrapIndent = computeWrapIndent(renderer) + var numChars = maxChars(chars, maxWidth - indent, maxWidth - wrapIndent) + while (chars.length > numChars) { + chars = chars.drop(numChars).dropWhile(_.isWhitespace) + numChars = maxChars(chars, maxWidth - wrapIndent, maxWidth - wrapIndent) + currentX = wrapIndent + 1 } currentX + stringWidth(chars) } @@ -38,15 +42,16 @@ private[markdown] class CodeSegment(protected val parent: Segment, val text: Str var currentX = x + indent var currentY = y var chars = text - var numChars = maxChars(chars, maxWidth - indent, maxWidth) + val wrapIndent = computeWrapIndent(renderer) + var numChars = maxChars(chars, maxWidth - indent, maxWidth - wrapIndent) while (chars.length > 0 && (currentY - y) < maxY) { val part = chars.take(numChars) GL11.glColor4f(0.75f, 0.8f, 1, 1) TextBufferRenderCache.renderer.drawString(part, currentX, currentY) - currentX = x + currentX = x + wrapIndent currentY += Document.lineHeight(renderer) chars = chars.drop(numChars).dropWhile(_.isWhitespace) - numChars = maxChars(chars, maxWidth, maxWidth) + numChars = maxChars(chars, maxWidth - wrapIndent, maxWidth - wrapIndent) } None @@ -69,5 +74,7 @@ private[markdown] class CodeSegment(protected val parent: Segment, val text: Str pos } + private def computeWrapIndent(renderer: FontRenderer) = if (lists.contains(rootPrefix)) renderer.getStringWidth(rootPrefix) else 0 + override def toString: String = s"{CodeSegment: text = $text}" } diff --git a/src/main/scala/li/cil/oc/client/renderer/markdown/segment/Segment.scala b/src/main/scala/li/cil/oc/client/renderer/markdown/segment/Segment.scala index 0cf1d0675..be1ec951e 100644 --- a/src/main/scala/li/cil/oc/client/renderer/markdown/segment/Segment.scala +++ b/src/main/scala/li/cil/oc/client/renderer/markdown/segment/Segment.scala @@ -2,6 +2,7 @@ package li.cil.oc.client.renderer.markdown.segment import net.minecraft.client.gui.FontRenderer +import scala.annotation.tailrec import scala.util.matching.Regex trait Segment { @@ -26,6 +27,8 @@ trait Segment { // Used when rendering, to compute the style of a nested segment. protected def parent: Segment + @tailrec protected final def root: Segment = if (parent == null) this else parent.root + // Used during construction, checks a segment for inner segments. private[markdown] def refine(pattern: Regex, factory: (Segment, Regex.Match) => Segment): Iterable[Segment] = Iterable(this) diff --git a/src/main/scala/li/cil/oc/client/renderer/markdown/segment/TextSegment.scala b/src/main/scala/li/cil/oc/client/renderer/markdown/segment/TextSegment.scala index e6019ab93..5baf6843f 100644 --- a/src/main/scala/li/cil/oc/client/renderer/markdown/segment/TextSegment.scala +++ b/src/main/scala/li/cil/oc/client/renderer/markdown/segment/TextSegment.scala @@ -9,7 +9,9 @@ import scala.collection.mutable import scala.util.matching.Regex private[markdown] class TextSegment(protected val parent: Segment, val text: String) extends Segment { - final val breaks = Set(' ', '.', ',', ':', ';', '!', '?', '_', '=', '-', '+', '*', '/', '\\', ')', '\'', '"') + private final val breaks = Set(' ', '.', ',', ':', ';', '!', '?', '_', '=', '-', '+', '*', '/', '\\', ')', '\'', '"') + private final val lists = Set("- ", "* ") + private lazy val rootPrefix = root.asInstanceOf[TextSegment].text.take(2) override def refine(pattern: Regex, factory: (Segment, Regex.Match) => Segment): Iterable[Segment] = { val result = mutable.Buffer.empty[Segment] @@ -41,11 +43,12 @@ private[markdown] class TextSegment(protected val parent: Segment, val text: Str var lines = 0 var chars = text if (indent == 0) chars = chars.dropWhile(_.isWhitespace) - var lineChars = maxChars(chars, maxWidth - indent, maxWidth, renderer) - while (chars.length > lineChars) { + val wrapIndent = computeWrapIndent(renderer) + var numChars = maxChars(chars, maxWidth - indent, maxWidth - wrapIndent, renderer) + while (chars.length > numChars) { lines += 1 - chars = chars.drop(lineChars).dropWhile(_.isWhitespace) - lineChars = maxChars(chars, maxWidth, maxWidth, renderer) + chars = chars.drop(numChars).dropWhile(_.isWhitespace) + numChars = maxChars(chars, maxWidth - wrapIndent, maxWidth - wrapIndent, renderer) } (lines * Document.lineHeight(renderer) * resolvedScale).toInt } @@ -54,11 +57,12 @@ private[markdown] class TextSegment(protected val parent: Segment, val text: Str var currentX = indent var chars = text if (indent == 0) chars = chars.dropWhile(_.isWhitespace) - var lineChars = maxChars(chars, maxWidth - indent, maxWidth, renderer) - while (chars.length > lineChars) { - chars = chars.drop(lineChars).dropWhile(_.isWhitespace) - lineChars = maxChars(chars, maxWidth, maxWidth, renderer) - currentX = 0 + val wrapIndent = computeWrapIndent(renderer) + var numChars = maxChars(chars, maxWidth - indent, maxWidth - wrapIndent, renderer) + while (chars.length > numChars) { + chars = chars.drop(numChars).dropWhile(_.isWhitespace) + numChars = maxChars(chars, maxWidth - wrapIndent, maxWidth - wrapIndent, renderer) + currentX = wrapIndent } currentX + (stringWidth(chars, renderer) * resolvedScale).toInt } @@ -69,7 +73,8 @@ private[markdown] class TextSegment(protected val parent: Segment, val text: Str var currentY = y var chars = text if (indent == 0) chars = chars.dropWhile(_.isWhitespace) - var numChars = maxChars(chars, maxWidth - indent, maxWidth, renderer) + val wrapIndent = computeWrapIndent(renderer) + var numChars = maxChars(chars, maxWidth - indent, maxWidth - wrapIndent, renderer) val interactive = findInteractive() var hovered: Option[InteractiveSegment] = None while (chars.length > 0 && (currentY - y) < maxY) { @@ -81,10 +86,10 @@ private[markdown] class TextSegment(protected val parent: Segment, val text: Str GL11.glTranslatef(-currentX, -currentY, 0) renderer.drawString(resolvedFormat + part, currentX, currentY, resolvedColor) GL11.glPopMatrix() - currentX = x + currentX = x + wrapIndent currentY += (Document.lineHeight(renderer) * fontScale).toInt chars = chars.drop(numChars).dropWhile(_.isWhitespace) - numChars = maxChars(chars, maxWidth, maxWidth, renderer) + numChars = maxChars(chars, maxWidth - wrapIndent, maxWidth - wrapIndent, renderer) } hovered @@ -137,5 +142,7 @@ private[markdown] class TextSegment(protected val parent: Segment, val text: Str pos } + private def computeWrapIndent(renderer: FontRenderer) = if (lists.contains(rootPrefix)) renderer.getStringWidth(rootPrefix) else 0 + override def toString: String = s"{TextSegment: text = $text}" }