From e9b8153b43eb1ea3e83e965cea18ba7bfd7fdd17 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Mon, 3 Oct 2022 16:39:22 +0200 Subject: [PATCH] bugfix: Remove usage of some internal scalameta methods These methods are not checked by mima, so it's best to remove any usage of it. There is still some internal methods, which we might want to move out from internal package in scalameta in the future, but theys are much less problematic --- .../mdoc/internal/cli/CliEnrichments.scala | 30 ++++++--- .../mdoc/internal/cli/InternalInput.scala | 62 +++++++++++++++++++ .../internal/markdown/MarkdownCompiler.scala | 1 - .../internal/markdown/MarkdownCompiler.scala | 1 - .../mdoc/internal/markdown/Markdown.scala | 1 - .../mdoc/internal/pos/PositionSyntax.scala | 1 - 6 files changed, 85 insertions(+), 11 deletions(-) create mode 100644 cli/src/main/scala/mdoc/internal/cli/InternalInput.scala diff --git a/cli/src/main/scala/mdoc/internal/cli/CliEnrichments.scala b/cli/src/main/scala/mdoc/internal/cli/CliEnrichments.scala index fd2205476..680aa3988 100644 --- a/cli/src/main/scala/mdoc/internal/cli/CliEnrichments.scala +++ b/cli/src/main/scala/mdoc/internal/cli/CliEnrichments.scala @@ -1,20 +1,20 @@ package mdoc.internal.cli +import coursierapi.Dependency + +import java.io.PrintStream import java.nio.charset.StandardCharsets import java.nio.file.Files import java.nio.file.Paths import java.nio.file.StandardCopyOption import scala.meta.Input import scala.meta.Position +import scala.meta.internal.io.FileIO +import scala.meta.internal.io.PathIO import scala.meta.io.AbsolutePath import scala.meta.io.RelativePath -import scala.meta.internal.io.PathIO -import scala.util.control.NonFatal -import coursierapi.Dependency -import scala.meta.internal.io.FileIO -import scala.meta.internal.inputs._ -import java.io.PrintStream import scala.util.Try +import scala.util.control.NonFatal trait CliEnrichments { implicit class XtensionInputMdoc(input: Input) { @@ -26,6 +26,12 @@ trait CliEnrichments { Try(AbsolutePath(Paths.get(v.path)).filename).getOrElse(v.path) case _ => input.syntax } + def syntax: String = input match { + case Input.None => "" + case Input.File(path, _) => path.toString + case Input.VirtualFile(path, _) => path + case _ => "" + } def relativeFilename(sourceroot: AbsolutePath): RelativePath = input match { case s: Input.Slice => @@ -64,7 +70,17 @@ trait CliEnrichments { } } - implicit class XtensionPositionMdoc(pos: Position) { + implicit class XtensionPositionMdoc(pos: Position) extends InternalInput(pos.input) { + def lineContent: String = { + val input = pos.input + val start = lineToOffset(pos.startLine) + val notEof = start < input.chars.length + val end = if (notEof) lineToOffset(pos.startLine + 1) else start + new String(input.chars, start, end - start).stripLineEnd + } + def lineCaret: String = { + " " * pos.startColumn + "^" + } def addStart(offset: Int): Position = pos match { case Position.Range(i, start, end) => diff --git a/cli/src/main/scala/mdoc/internal/cli/InternalInput.scala b/cli/src/main/scala/mdoc/internal/cli/InternalInput.scala new file mode 100644 index 000000000..b596ccb6e --- /dev/null +++ b/cli/src/main/scala/mdoc/internal/cli/InternalInput.scala @@ -0,0 +1,62 @@ +package mdoc.internal.cli + +import scala.collection.mutable +import scala.meta.inputs._ +import scala.meta.Dialect +import scala.meta.tokens.Tokens +import scala.meta.internal.tokenizers.Compat + +// Copied over from scalameta/scalameta +abstract class InternalInput(input: Input) { + + // NOTE: It's regrettable that we need to taint the pure abstraction of Input. + // However, as #334 shows, we just can't redo offset -> line conversions over and over again. + // This means that we gotta cache, and this instance is really the only place versatile enough. + private lazy val cachedLineIndices: Array[Int] = { + val chars = input.chars + val buf = new mutable.ArrayBuffer[Int] + buf += 0 + var i = 0 + while (i < chars.length) { + if (chars(i) == '\n') buf += (i + 1) + i += 1 + } + if (buf.last != chars.length) buf += chars.length // sentinel value used for binary search + buf.toArray + } + + def lineToOffset(line: Int): Int = { + // NOTE: The length-1 part is not a typo, it's to accommodate the sentinel value. + if (!(0 <= line && line <= cachedLineIndices.length - 1)) { + val message = + s"$line is not a valid line number, allowed [0..${cachedLineIndices.length - 1}]" + throw new IllegalArgumentException(message) + } + cachedLineIndices(line) + } + + def offsetToLine(offset: Int): Int = { + val chars = input.chars + val a = cachedLineIndices + // NOTE: We allow chars.length, because it's a valid value for an offset. + if (!(0 <= offset && offset <= chars.length)) { + val message = s"$offset is not a valid offset, allowed [0..${chars.length}]" + throw new IllegalArgumentException(message) + } + // NOTE: chars.length requires a really ugly special case. + // If the file doesn't end with \n, then it's simply last_line:last_col+1. + // But if the file does end with \n, then it's last_line+1:0. + if (offset == chars.length && (0 < chars.length && chars(offset - 1) == '\n')) { + return a.length - 1 + } + var lo = 0 + var hi = a.length - 1 + while (hi - lo > 1) { + val mid = (hi + lo) / 2 + if (offset < a(mid)) hi = mid + else if (a(mid) == offset) return mid + else /* if (a(mid) < offset */ lo = mid + } + lo + } +} diff --git a/mdoc/src/main/scala-2/mdoc/internal/markdown/MarkdownCompiler.scala b/mdoc/src/main/scala-2/mdoc/internal/markdown/MarkdownCompiler.scala index 7c6b3384c..ad8663e0e 100644 --- a/mdoc/src/main/scala-2/mdoc/internal/markdown/MarkdownCompiler.scala +++ b/mdoc/src/main/scala-2/mdoc/internal/markdown/MarkdownCompiler.scala @@ -29,7 +29,6 @@ import scala.tools.nsc.io.VirtualDirectory import scala.annotation.implicitNotFound import mdoc.internal.CompatClassloader import mdoc.internal.worksheets.Compat._ -import scala.meta.internal.inputs._ class MarkdownCompiler( classpath: String, diff --git a/mdoc/src/main/scala-3/mdoc/internal/markdown/MarkdownCompiler.scala b/mdoc/src/main/scala-3/mdoc/internal/markdown/MarkdownCompiler.scala index 7f0920e95..39c744bb8 100644 --- a/mdoc/src/main/scala-3/mdoc/internal/markdown/MarkdownCompiler.scala +++ b/mdoc/src/main/scala-3/mdoc/internal/markdown/MarkdownCompiler.scala @@ -27,7 +27,6 @@ import scala.meta.Classpath import scala.meta.AbsolutePath import scala.meta.inputs.Input import scala.meta.inputs.Position -import scala.meta.internal.inputs.XtensionInputSyntaxStructure import dotty.tools.dotc.interactive.InteractiveDriver import dotty.tools.dotc.interactive.Interactive diff --git a/mdoc/src/main/scala/mdoc/internal/markdown/Markdown.scala b/mdoc/src/main/scala/mdoc/internal/markdown/Markdown.scala index 1e085676e..26e334edc 100644 --- a/mdoc/src/main/scala/mdoc/internal/markdown/Markdown.scala +++ b/mdoc/src/main/scala/mdoc/internal/markdown/Markdown.scala @@ -1,6 +1,5 @@ package mdoc.internal.markdown -import scala.meta.internal.inputs._ import com.vladsch.flexmark.ext.yaml.front.matter.YamlFrontMatterBlock import com.vladsch.flexmark.formatter.Formatter import com.vladsch.flexmark.html.HtmlRenderer diff --git a/mdoc/src/main/scala/mdoc/internal/pos/PositionSyntax.scala b/mdoc/src/main/scala/mdoc/internal/pos/PositionSyntax.scala index 83064c83e..f5a0dd7ae 100644 --- a/mdoc/src/main/scala/mdoc/internal/pos/PositionSyntax.scala +++ b/mdoc/src/main/scala/mdoc/internal/pos/PositionSyntax.scala @@ -16,7 +16,6 @@ import scala.meta.internal.io.PathIO import scala.util.control.NonFatal import coursierapi.Dependency import scala.meta.internal.io.FileIO -import scala.meta.internal.inputs._ object PositionSyntax extends CliEnrichments with CollectionEnrichments { implicit class XtensionRangePositionMdoc(pos: RangePosition) {