summaryrefslogtreecommitdiff
path: root/contrib/bsp/src/mill/contrib/bsp/BspLoggedReporter.scala
blob: 4bc94b416204f814ee60476471a6d14bf4b12fd5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
package mill.contrib.bsp

import java.io.File

import ch.epfl.scala.{bsp4j => bsp}
import sbt.internal.inc.ManagedLoggedReporter
import sbt.internal.inc.schema.Position
import sbt.internal.util.ManagedLogger
import xsbti.{Problem, Severity}

import scala.collection.JavaConverters._
import scala.compat.java8.OptionConverters._
import scala.io.Source

class BspLoggedReporter(client: bsp.BuildClient,
                        targetId: bsp.BuildTargetIdentifier,
                        compilationOriginId: Option[String],
                        maxErrors: Int,
                        logger: ManagedLogger) extends ManagedLoggedReporter(maxErrors, logger) {

  override def logError(problem: Problem): Unit = {
    client.onBuildPublishDiagnostics(getDiagnostics(problem, targetId, compilationOriginId))
    super.logError(problem)
  }

  override def logInfo(problem: Problem): Unit = {
    client.onBuildPublishDiagnostics(getDiagnostics(problem, targetId, compilationOriginId))
    super.logInfo(problem)
  }

  override def logWarning(problem: Problem): Unit = {
    client.onBuildPublishDiagnostics(getDiagnostics(problem, targetId, compilationOriginId))
    super.logWarning(problem)
  }

  def getDiagnostics(problem: Problem, targetId: bsp.BuildTargetIdentifier, originId: Option[String]):
                                                                                bsp.PublishDiagnosticsParams = {
      val sourceFile = problem.position().sourceFile().asScala
      val start = new bsp.Position(
        problem.position.startLine.asScala.getOrElse(0),
        problem.position.startOffset.asScala.getOrElse(0))
      val end = new bsp.Position(
        problem.position.endLine.asScala.getOrElse(0),
        problem.position.endOffset.asScala.getOrElse(0))
      val diagnostic = new bsp.Diagnostic(new bsp.Range(start, end), problem.message)
      diagnostic.setCode(problem.position.lineContent)
      diagnostic.setSource("compiler from mill")
      diagnostic.setSeverity( problem.severity match  {
        case Severity.Info => bsp.DiagnosticSeverity.INFORMATION
        case Severity.Error => bsp.DiagnosticSeverity.ERROR
        case Severity.Warn => bsp.DiagnosticSeverity.WARNING
      }
      )

      val params = new bsp.PublishDiagnosticsParams(
          new bsp.TextDocumentIdentifier(sourceFile.getOrElse(new File(targetId.getUri)).toPath.toAbsolutePath.toUri.toString),
                                          targetId, List(diagnostic).asJava, true)

      if (originId.nonEmpty) { params.setOriginId(originId.get) }
      params
    }

  private[this] def getErrorCode(file: Option[File], start: bsp.Position, end: bsp.Position, position: xsbti.Position): String = {
    file match {
      case None => position.lineContent
      case f: Option[File] =>
        val source = Source.fromFile(f.get)
        source.close()
        val lines = source.getLines.toSeq
        val code = lines(start.getLine).substring(start.getCharacter) +
          lines.take(start.getLine - 1).takeRight(lines.length - end.getLine - 1).mkString("\n") +
          lines(end.getLine).substring(0, end.getCharacter + 1)
        code
    }

  }

}