summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala
blob: d09567eadfcb9956db89d0615d7bd8b3939ae3fe (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
/* NSC -- new Scala compiler
 * Copyright 2005-2011 LAMP/EPFL
 * @author Stepan Koltsov
 */

package scala.tools.nsc
package interpreter

import java.io.File
import java.util.{ List => JList }
import scala.tools.jline.console.ConsoleReader
import scala.tools.jline.console.completer._
import scala.tools.jline.console.history._
import scala.tools.jline.console.history.{ FileHistory, PersistentHistory, History => JHistory }
import scala.tools.jline.console.history.History.{ Entry => JEntry }
import scala.tools.jline.console.ConsoleReader
import scala.collection.JavaConverters._
import Properties.userHome

/** A wrapper for JLine's History.
 */
class JLineHistory(val jhistory: JHistory) extends History {
  def asJavaList = jhistory.entries()
  def asStrings = asList map (_.value.toString)
  def asList: List[JEntry] = asJavaList.asScala.toList
  def index = jhistory.index()
  def size = jhistory.size()

  def grep(s: String) = asStrings filter (_ contains s)
  def flush() = jhistory match {
    case x: PersistentHistory => x.flush()
    case _                    => ()
  }
}

object JLineHistory {
  val ScalaHistoryFile = ".scala_history"

  def apply() = new JLineHistory(
    try newFile()
    catch { case x : Exception =>
      Console.println("Error creating file history: memory history only. " + x)
      newMemory()
    }
  )

  def newMemory() = new MemoryHistory()
  def newFile() = new FileHistory(new File(userHome, ScalaHistoryFile)) {
    // flush after every add to avoid installing a shutdown hook.
    // (The shutdown hook approach also loses history when they aren't run.)
    override def add(item: CharSequence): Unit = {
      super.add(item)
      flush()
    }
  }
}

/** Reads from the console using JLine */
class JLineReader(val completion: Completion) extends InteractiveReader {
  lazy val history = JLineHistory()

  def reset() = consoleReader.getTerminal().reset()
  def init()  = consoleReader.getTerminal().init()

  override def redrawLine()    = {
    consoleReader.flush()
    consoleReader.drawLine()
    consoleReader.flush()
  }

  def argCompletor: ArgumentCompleter = {
    val wrapped = new Completer {
      val cc = completion.completer()
      def complete(buffer: String, cursor: Int, candidates: JList[CharSequence]): Int =
        cc.complete(buffer, cursor, candidates)
    }
    val c = new ArgumentCompleter(new JLineDelimiter, wrapped)
    c setStrict false
    c
  }

  val consoleReader = {
    val r = new ConsoleReader()
    r setBellEnabled false
    if (history ne History.Empty)
      r setHistory history.jhistory

    if (completion ne Completion.Empty) {
      r addCompleter argCompletor
      r setAutoprintThreshold 400 // max completion candidates without warning
    }

    r
  }

  override def currentLine: String = consoleReader.getCursorBuffer.buffer.toString
  def readOneLine(prompt: String) = consoleReader readLine prompt
  val interactive = true
}

object JLineReader {
  def apply(intp: IMain): InteractiveReader = apply(new JLineCompletion(intp))
  def apply(comp: Completion): InteractiveReader = {
    try new JLineReader(comp)
    catch { case e @ (_: Exception | _: NoClassDefFoundError) => new SimpleReader }
  }
}