From 8f55c90980ef0f95056d260af4fe8d55e27b2e6a Mon Sep 17 00:00:00 2001 From: Joscha Date: Wed, 4 Sep 2024 19:02:18 +0200 Subject: [PATCH] Reformat single files --- .../scala/de/plugh/asciiprooftree/Main.scala | 14 +++++- .../de/plugh/asciiprooftree/file/Block.scala | 23 ++++++++++ .../plugh/asciiprooftree/file/Formatter.scala | 45 +++++++++++++++++++ .../de/plugh/asciiprooftree/tree/Parser.scala | 6 +-- 4 files changed, 83 insertions(+), 5 deletions(-) create mode 100644 src/main/scala/de/plugh/asciiprooftree/file/Block.scala create mode 100644 src/main/scala/de/plugh/asciiprooftree/file/Formatter.scala diff --git a/src/main/scala/de/plugh/asciiprooftree/Main.scala b/src/main/scala/de/plugh/asciiprooftree/Main.scala index 907f75e..1a5e91f 100644 --- a/src/main/scala/de/plugh/asciiprooftree/Main.scala +++ b/src/main/scala/de/plugh/asciiprooftree/Main.scala @@ -1,6 +1,8 @@ package de.plugh.asciiprooftree -import java.nio.file.Path +import de.plugh.asciiprooftree.file.Formatter + +import java.nio.file.{Files, Path} @main def main(args: String*): Unit = args match @@ -11,4 +13,12 @@ def main(args: String*): Unit = args match println("Usage: asciiprooftree [path] [marker]") System.exit(1) -def run(path: Path = Path.of(""), marker: String = "§"): Unit = println(s"$path $marker") +@main +def testMain(path: String): Unit = run(Path.of(path)) + +def run(path: Path = Path.of(""), marker: String = "§"): Unit = + println(s"Path: $path") + println(s"Marker: $marker") + val text = Files.readString(path) + val newText = Formatter.reformat(text, marker = marker) + Files.writeString(path, newText) diff --git a/src/main/scala/de/plugh/asciiprooftree/file/Block.scala b/src/main/scala/de/plugh/asciiprooftree/file/Block.scala new file mode 100644 index 0000000..7b39ed1 --- /dev/null +++ b/src/main/scala/de/plugh/asciiprooftree/file/Block.scala @@ -0,0 +1,23 @@ +package de.plugh.asciiprooftree.file + +case class Block(lines: Seq[(String, String)]): + require(lines.nonEmpty) + + def last: (String, String) = lines.last + def content: Seq[String] = lines.map((_, content) => content) + def toLines: Seq[String] = lines.map((prefix, content) => s"$prefix $content") + + def extend(prefix: String, content: String): Block = Block(lines :+ (prefix, content)) + + def resize(height: Int): Block = + require(height > 0) + if height < lines.length then return Block(lines.take(height)) + if height == lines.length then return this + Block(lines ++ Seq.fill(height - lines.length)(lines.last)) + + def replace(newContent: IndexedSeq[String]): Block = + require(newContent.nonEmpty) + Block(resize(newContent.length).lines.zip(newContent).map { case ((prefix, _), content) => (prefix, content) }) + +object Block: + def apply(prefix: String, content: String): Block = Block(Seq((prefix, content))) diff --git a/src/main/scala/de/plugh/asciiprooftree/file/Formatter.scala b/src/main/scala/de/plugh/asciiprooftree/file/Formatter.scala new file mode 100644 index 0000000..2897e3c --- /dev/null +++ b/src/main/scala/de/plugh/asciiprooftree/file/Formatter.scala @@ -0,0 +1,45 @@ +package de.plugh.asciiprooftree.file + +import de.plugh.asciiprooftree.tree.{Line, Parser} + +import scala.collection.mutable + +private class Formatter(marker: String): + private val lines: mutable.Buffer[String] = mutable.Buffer() + private var block: Option[Block] = None + + private def flushBlock(): Unit = for block <- this.block do + val newBlock = Parser(block.content).parse match + case Some(tree) => block.replace(tree.formatted.toString.linesIterator.toIndexedSeq) + case None => block + lines.appendAll(newBlock.toLines) + this.block = None + + private def pushBlockLine(prefix: String, content: String): Unit = this.block match + case Some(block) if Line(block.last._1).width == Line(prefix).width => + this.block = Some(block.extend(prefix, content)) + case _ => + flushBlock() + this.block = Some(Block(prefix, content)) + + private def pushPlainLine(line: String): Unit = + flushBlock() + lines.append(line) + + private def pushLine(line: String): Unit = + val i = line.indexOf(marker) + if i < 0 then pushPlainLine(line) + else + val prefix = line.slice(0, i + marker.length) + val content = line.slice(i + marker.length, line.length) + pushBlockLine(prefix, content) + + private def pushText(text: String): Unit = text.linesIterator.foreach(pushLine) + + override def toString: String = lines.map(l => s"$l\n").mkString + +object Formatter: + def reformat(text: String, marker: String = "§"): String = + val fmt = new Formatter(marker) + fmt.pushText(text) + fmt.toString diff --git a/src/main/scala/de/plugh/asciiprooftree/tree/Parser.scala b/src/main/scala/de/plugh/asciiprooftree/tree/Parser.scala index 62f50ea..30fddd1 100644 --- a/src/main/scala/de/plugh/asciiprooftree/tree/Parser.scala +++ b/src/main/scala/de/plugh/asciiprooftree/tree/Parser.scala @@ -65,7 +65,7 @@ case class Parser(lines: Lines): object Parser: def apply(lines: Seq[String]): Parser = - val trimmedLines = lines.map(Line(_).trim) - Parser(Lines(trimmedLines.toIndexedSeq)) + val trimmedLines = lines.reverseIterator.map(Line(_).trim).toIndexedSeq + Parser(Lines(trimmedLines)) - def apply(text: String): Parser = apply(text.linesIterator.toSeq.reverse) + def apply(text: String): Parser = apply(text.linesIterator.toSeq)