|  | 
|  | 1 | +package scriptWrapper | 
|  | 2 | + | 
|  | 3 | +import dotty.tools.dotc.* | 
|  | 4 | +import core.* | 
|  | 5 | +import Contexts.Context | 
|  | 6 | +import Contexts.ctx | 
|  | 7 | +import plugins.* | 
|  | 8 | +import ast.tpd | 
|  | 9 | +import util.SourceFile | 
|  | 10 | + | 
|  | 11 | +class LineNumberPlugin extends StandardPlugin { | 
|  | 12 | +  val name: String = "linenumbers" | 
|  | 13 | +  val description: String = "adjusts line numbers of script files" | 
|  | 14 | + | 
|  | 15 | +  override def initialize(options: List[String])(using Context): List[PluginPhase] = FixLineNumbers() :: Nil | 
|  | 16 | +} | 
|  | 17 | + | 
|  | 18 | +// Loosely follows Mill linenumbers plugin (scan for marker with "original" source, adjust line numbers to match) | 
|  | 19 | +class FixLineNumbers extends PluginPhase { | 
|  | 20 | + | 
|  | 21 | +  val codeMarker = "//USER_CODE_HERE" | 
|  | 22 | + | 
|  | 23 | +  def phaseName: String = "fixLineNumbers" | 
|  | 24 | +  override def runsAfter: Set[String] = Set("posttyper") | 
|  | 25 | +  override def runsBefore: Set[String] = Set("pickler") | 
|  | 26 | + | 
|  | 27 | +  override def transformUnit(tree: tpd.Tree)(using Context): tpd.Tree = { | 
|  | 28 | +    val sourceContent = ctx.source.content() | 
|  | 29 | +    val lines = new String(sourceContent).linesWithSeparators.toVector | 
|  | 30 | +    val codeMarkerLine = lines.indexWhere(_.startsWith(codeMarker)) | 
|  | 31 | + | 
|  | 32 | +    if codeMarkerLine < 0 then | 
|  | 33 | +      tree | 
|  | 34 | +    else | 
|  | 35 | +      val adjustedFile = lines.collectFirst { | 
|  | 36 | +        case s"//USER_SRC_FILE:./$file" => file.trim | 
|  | 37 | +      }.getOrElse("<unknown>") | 
|  | 38 | + | 
|  | 39 | +      val adjustedSrc = ctx.source.file.container.lookupName(adjustedFile, directory = false) match | 
|  | 40 | +        case null => | 
|  | 41 | +          report.error(s"could not find file $adjustedFile", tree.sourcePos) | 
|  | 42 | +          return tree | 
|  | 43 | +        case file => | 
|  | 44 | +          SourceFile(file, scala.io.Codec.UTF8) | 
|  | 45 | + | 
|  | 46 | +      val userCodeOffset = ctx.source.lineToOffset(codeMarkerLine + 1) // lines.take(codeMarkerLine).map(_.length).sum | 
|  | 47 | +      val lineMapper = LineMapper(codeMarkerLine, userCodeOffset, adjustedSrc) | 
|  | 48 | +      lineMapper.transform(tree) | 
|  | 49 | +  } | 
|  | 50 | + | 
|  | 51 | +} | 
|  | 52 | + | 
|  | 53 | +class LineMapper(markerLine: Int, userCodeOffset: Int, adjustedSrc: SourceFile) extends tpd.TreeMapWithPreciseStatContexts() { | 
|  | 54 | + | 
|  | 55 | +  override def transform(tree: tpd.Tree)(using Context): tpd.Tree = { | 
|  | 56 | +    val tree0 = super.transform(tree) | 
|  | 57 | +    val pos = tree0.sourcePos | 
|  | 58 | +    if pos.exists && pos.start >= userCodeOffset then | 
|  | 59 | +      val tree1 = tree0.cloneIn(adjustedSrc).withSpan(pos.span.shift(-userCodeOffset)) | 
|  | 60 | +      // if tree1.show.toString == "???" then | 
|  | 61 | +      //   val pos1 = tree1.sourcePos | 
|  | 62 | +      //   sys.error(s"rewrote ??? at ${pos1.source}:${pos1.line + 1}:${pos1.column + 1} (sourced from ${markerLine + 2})") | 
|  | 63 | +      tree1 | 
|  | 64 | +    else | 
|  | 65 | +      tree0 | 
|  | 66 | +  } | 
|  | 67 | + | 
|  | 68 | +} | 
0 commit comments