summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/scratchpad/SourceInserter.scala
blob: 42a35dc642dbdd0901f4d767f0507e51b7326ebf (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
package scala.tools.nsc
package scratchpad

import java.io.Writer
import scala.reflect.internal.util.SourceFile

import reflect.internal.Chars._

object SourceInserter {
  def stripRight(cs: Array[Char]): Array[Char] = {
    val lines =
      new String(cs) split "\n"
    def leftPart(str: String) =
      (str split """//>|//\|""").head
    def isContinuation(str: String) =
      ((str contains "//>") || (str contains "//|")) && (leftPart(str) forall isWhitespace)
    def stripTrailingWS(str: String) =
      str take (str lastIndexWhere (!isWhitespace(_))) + 1
    val prefixes =
      lines filterNot isContinuation map leftPart map stripTrailingWS
    (prefixes mkString "\n").toArray
  }
}
class SourceInserter(contents: Array[Char], start: Int = 0, tabInc: Int = 8) extends Writer {

  private var buf = contents
  private var offset = start
  private var hilen = contents.length

  def length = offset + hilen

  private def currentColumn: Int = {
    var i = offset
    while (i > 0 && !isLineBreakChar(buf(i - 1))) i -= 1
    var col = 0
    while (i < offset) {
      col = if (buf(i) == '\t') (col + tabInc) / tabInc * tabInc else col + 1
      i += 1
    }
    col
  }

  private var col = currentColumn

  def column = synchronized { col }

  private def addCapacity(n: Int) = {
    val newlength = length + n
    while (newlength > buf.length) {
      val buf1 = Array.ofDim[Char](buf.length * 2)
      Array.copy(buf, 0, buf1, 0, offset)
      Array.copy(buf, buf.length - hilen, buf1, buf1.length - hilen, hilen)
      buf = buf1
    }
  }

  private def insertChar(ch: Char) = {
//  Console.err.print("["+ch+"]")
    buf(offset) = ch
    offset += 1
    ch match {
      case LF => col = 0
      case '\t' => col = (col + tabInc) / tabInc * tabInc
      case _ => col += 1
    }
  }

  override def write(ch: Int) = synchronized {
    addCapacity(1)
    insertChar(ch.toChar)
  }

  override def write(chs: Array[Char], off: Int, len: Int) = synchronized {
    addCapacity(len)
    for (i <- off until off + len) insertChar(chs(i))
  }

  override def close() {
  }

  override def flush() {
    // signal buffer change
  }

  def currentContents = synchronized {
    if (length == buf.length) buf
    else {
      val res = Array.ofDim[Char](length)
      Array.copy(buf, 0, res, 0, offset)
      Array.copy(buf, buf.length - hilen, res, offset, hilen)
      res
    }
  }

  def backspace() = synchronized {
    offset -= 1
    if (offset > 0 && buf(offset) == LF && buf(offset - 1) == CR) offset -=1
  }

  def currentChar = synchronized {
    buf(buf.length - hilen)
  }

  def skip(len: Int) = synchronized {
    for (i <- 0 until len) {
      val ch = currentChar
      hilen -= 1
      insertChar(ch)
    }
  }
}