summaryrefslogtreecommitdiff
path: root/src/repl/scala/tools/nsc/interpreter/session/FileBackedHistory.scala
blob: dddfb1b8f646e02329a1d4f6be9a63743e27e7d6 (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
/* NSC -- new Scala compiler
 * Copyright 2005-2013 LAMP/EPFL
 * @author Paul Phillips
 */

package scala.tools.nsc
package interpreter
package session

import scala.tools.nsc.io._
import FileBackedHistory._

/** TODO: file locking.
 */
trait FileBackedHistory extends JLineHistory with JPersistentHistory {
  def maxSize: Int
  protected lazy val historyFile: File = defaultFile
  private var isPersistent = true

  locally {
    load()
  }

  def withoutSaving[T](op: => T): T = {
    val saved = isPersistent
    isPersistent = false
    try op
    finally isPersistent = saved
  }
  def addLineToFile(item: CharSequence): Unit = {
    if (isPersistent)
      append(item + "\n")
  }

  /** Overwrites the history file with the current memory. */
  protected def sync(): Unit = {
    val lines = asStrings map (_ + "\n")
    historyFile.writeAll(lines: _*)
  }
  /** Append one or more lines to the history file. */
  protected def append(lines: String*): Unit = {
    historyFile.appendAll(lines: _*)
  }

  def load(): Unit = {
    if (!historyFile.canRead)
      historyFile.createFile()

    val lines: IndexedSeq[String] = {
      try historyFile.lines().toIndexedSeq
      catch {
        // It seems that control characters in the history file combined
        // with the default codec can lead to nio spewing exceptions.  Rather
        // than abandon hope we'll try to read it as ISO-8859-1
        case _: Exception =>
          try historyFile.lines("ISO-8859-1").toIndexedSeq
          catch { case _: Exception => Vector() }
      }
    }

    repldbg("Loading " + lines.size + " into history.")

    // avoid writing to the history file
    withoutSaving(lines takeRight maxSize foreach add)
    // truncate the history file if it's too big.
    if (lines.size > maxSize) {
      repldbg("File exceeds maximum size: truncating to " + maxSize + " entries.")
      sync()
    }
    moveToEnd()
  }

  def flush(): Unit = ()
  def purge(): Unit = historyFile.truncate()
}

object FileBackedHistory {
  //   val ContinuationChar = '\003'
  //   val ContinuationNL: String = Array('\003', '\n').mkString
  import Properties.userHome

  def defaultFileName = ".scala_history"
  def defaultFile: File = File(Path(userHome) / defaultFileName)
}