summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/interactive/Picklers.scala
blob: 45134fca6da6a26f043ccd33b56b46d8edcabe43 (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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package scala.tools.nsc
package interactive

import util.{SourceFile, BatchSourceFile}
import io.{AbstractFile, PlainFile}

import util.{Position, RangePosition, NoPosition, OffsetPosition, TransparentPosition}
import io.{Pickler, CondPickler}
import io.Pickler._
import collection.mutable

trait Picklers { self: Global =>

  lazy val freshRunReq = singletonPickler(FreshRunReq)
  lazy val shutdownReq = singletonPickler(ShutdownReq)

  def defaultThrowable[T <: Throwable]: CondPickler[T] = javaInstancePickler[T] cond { _ => true }

  implicit lazy val throwable: Pickler[Throwable] =
    freshRunReq | shutdownReq | defaultThrowable

  implicit def abstractFile: Pickler[AbstractFile] =
    pkl[String]
      .wrapped[AbstractFile] { new PlainFile(_) } { _.path }
      .asClass (classOf[PlainFile])

  private val sourceFilesSeen = new mutable.HashMap[AbstractFile, Array[Char]] {
    override def default(key: AbstractFile) = Array()
  }

  type Diff = (Int /*start*/, Int /*end*/, String /*replacement*/)

  def delta(f: AbstractFile, cs: Array[Char]): Diff = {
    val bs = sourceFilesSeen(f)
    var start = 0
    while (start < bs.length && start < cs.length && bs(start) == cs(start)) start += 1
    var end = bs.length
    var end2 = cs.length
    while (end > start && end2 > start && bs(end - 1) == cs(end2 - 1)) { end -= 1; end2 -= 1 }
    sourceFilesSeen(f) = cs
    (start, end, cs.slice(start, end2).mkString(""))
  }

  def patch(f: AbstractFile, d: Diff): Array[Char] = {
    val (start, end, replacement) = d
    val patched = sourceFilesSeen(f).patch(start, replacement, end - start)
    sourceFilesSeen(f) = patched
    patched
  }

  implicit lazy val sourceFile: Pickler[SourceFile] =
    (pkl[AbstractFile] ~ pkl[Diff]).wrapped[SourceFile] {
      case f ~ d => new BatchSourceFile(f, patch(f, d))
    } {
      f => f.file ~ delta(f.file, f.content)
    }.asClass (classOf[BatchSourceFile])

  lazy val offsetPosition: CondPickler[OffsetPosition] =
    (pkl[SourceFile] ~ pkl[Int])
      .wrapped { case x ~ y => new OffsetPosition(x, y) } { p => p.source ~ p.point }
      .asClass (classOf[OffsetPosition])

  lazy val rangePosition: CondPickler[RangePosition] =
    (pkl[SourceFile] ~ pkl[Int] ~ pkl[Int] ~ pkl[Int])
      .wrapped { case source ~ start ~ point ~ end => new RangePosition(source, start, point, end) } { p => p.source ~ p.start ~ p.point ~ p.end }
      .asClass (classOf[RangePosition])

  lazy val transparentPosition: CondPickler[TransparentPosition] =
    (pkl[SourceFile] ~ pkl[Int] ~ pkl[Int] ~ pkl[Int])
      .wrapped { case source ~ start ~ point ~ end => new TransparentPosition(source, start, point, end) } { p => p.source ~ p.start ~ p.point ~ p.end }
      .asClass (classOf[TransparentPosition])

  lazy val noPosition = singletonPickler(NoPosition)

  implicit lazy val position: Pickler[Position] = transparentPosition | rangePosition | offsetPosition | noPosition

  implicit def reloadItem: CondPickler[ReloadItem] =
    pkl[List[SourceFile]]
      .wrapped { ReloadItem(_, new Response) } { _.sources }
      .asClass (classOf[ReloadItem])

  implicit def askTypeAtItem: CondPickler[AskTypeAtItem] =
    pkl[Position]
      .wrapped { new AskTypeAtItem(_, new Response) } { _.pos }
      .asClass (classOf[AskTypeAtItem])

  implicit def askTypeItem: CondPickler[AskTypeItem] =
    (pkl[SourceFile] ~ pkl[Boolean])
      .wrapped { case source ~ forceReload => new AskTypeItem(source, forceReload, new Response) } { w => w.source ~ w.forceReload }
      .asClass (classOf[AskTypeItem])

  implicit def askLastTypeItem: CondPickler[AskLastTypeItem] =
    pkl[SourceFile]
      .wrapped { new AskLastTypeItem(_, new Response) } { _.source }
      .asClass (classOf[AskLastTypeItem])

  implicit def askTypeCompletionItem: CondPickler[AskTypeCompletionItem] =
    pkl[Position]
      .wrapped { new AskTypeCompletionItem(_, new Response) } { _.pos }
      .asClass (classOf[AskTypeCompletionItem])

  implicit def askScopeCompletionItem: CondPickler[AskScopeCompletionItem] =
    pkl[Position]
      .wrapped { new AskScopeCompletionItem(_, new Response) } { _.pos }
      .asClass (classOf[AskScopeCompletionItem])

  implicit def askToDoFirstItem: CondPickler[AskToDoFirstItem] =
    pkl[SourceFile]
      .wrapped { new AskToDoFirstItem(_) } { _.source }
      .asClass (classOf[AskToDoFirstItem])

  implicit def action: Pickler[() => Unit] =
    reloadItem | askTypeAtItem | askTypeItem | askLastTypeItem | askTypeCompletionItem | askScopeCompletionItem | askToDoFirstItem
}