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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
/* NSC -- new Scala compiler
* Copyright 2005-2013 LAMP/EPFL
* @author Stepan Koltsov
*/
package scala.tools.nsc
package interpreter
import java.io.IOException
import session.History
import InteractiveReader._
import Properties.isMac
/** Reads lines from an input stream */
trait InteractiveReader {
def postInit(): Unit = {}
val interactive: Boolean
def reset(): Unit
def history: History
def completion: Completion
def redrawLine(): Unit
def readYesOrNo(prompt: String, alt: => Boolean): Boolean = readOneKey(prompt) match {
case 'y' => true
case 'n' => false
case -1 => false // EOF
case _ => alt
}
protected def readOneLine(prompt: String): String
protected def readOneKey(prompt: String): Int
def readLine(prompt: String): String =
// hack necessary for OSX jvm suspension because read calls are not restarted after SIGTSTP
if (isMac) restartSysCalls(readOneLine(prompt), reset())
else readOneLine(prompt)
}
object InteractiveReader {
val msgEINTR = "Interrupted system call"
def restartSysCalls[R](body: => R, reset: => Unit): R =
try body catch {
case e: IOException if e.getMessage == msgEINTR => reset ; body
}
def apply(): InteractiveReader = SimpleReader()
@deprecated("Use `apply` instead.", "2.9.0")
def createDefault(): InteractiveReader = apply() // used by sbt
}
/** Collect one line of user input from the supplied reader.
* Runs on a new thread while the REPL is initializing on the main thread.
*
* The user can enter text or a `:paste` command.
*/
class SplashLoop(reader: InteractiveReader, prompt: String) extends Runnable {
import java.util.concurrent.SynchronousQueue
import scala.compat.Platform.EOL
private val result = new SynchronousQueue[Option[String]]
@volatile private var running: Boolean = _
private var thread: Thread = _
/** Read one line of input which can be retrieved with `line`. */
def run(): Unit = {
var line = ""
try
do {
line = reader.readLine(prompt)
if (line != null) {
line = process(line.trim)
}
} while (line != null && line.isEmpty && running)
finally {
result.put(Option(line))
}
}
/** Check for `:paste` command. */
private def process(line: String): String = {
def isPrefix(s: String, p: String, n: Int) = (
//s != null && p.inits.takeWhile(_.length >= n).exists(s == _)
s != null && s.length >= n && s.length <= p.length && s == p.take(s.length)
)
if (isPrefix(line, ":paste", 3)) {
// while collecting lines, check running flag
var help = f"// Entering paste mode (ctrl-D to finish)%n%n"
def readWhile(cond: String => Boolean) = {
Iterator continually reader.readLine(help) takeWhile { x =>
help = ""
x != null && cond(x)
}
}
val text = (readWhile(_ => running) mkString EOL).trim
val next =
if (text.isEmpty) "// Nothing pasted, nothing gained."
else "// Exiting paste mode, now interpreting."
Console println f"%n${next}%n"
text
} else {
line
}
}
def start(): Unit = result.synchronized {
require(thread == null, "Already started")
thread = new Thread(this)
running = true
thread.start()
}
def stop(): Unit = result.synchronized {
running = false
if (thread != null) thread.interrupt()
thread = null
}
/** Block for the result line, or null on ctl-D. */
def line: String = result.take getOrElse null
}
object SplashLoop {
def apply(reader: SplashReader, prompt: String): SplashLoop = new SplashLoop(reader, prompt)
}
/** Reader during splash. Handles splash-completion with a stub, otherwise delegates. */
class SplashReader(reader: InteractiveReader, postIniter: InteractiveReader => Unit) extends InteractiveReader {
/** Invoke the postInit action with the underlying reader. */
override def postInit(): Unit = postIniter(reader)
override val interactive: Boolean = reader.interactive
override def reset(): Unit = reader.reset()
override def history: History = reader.history
override val completion: Completion = NoCompletion
override def redrawLine(): Unit = reader.redrawLine()
override protected[interpreter] def readOneLine(prompt: String): String = ??? // unused
override protected[interpreter] def readOneKey(prompt: String): Int = ??? // unused
override def readLine(prompt: String): String = reader.readLine(prompt)
}
object SplashReader {
def apply(reader: InteractiveReader)(postIniter: InteractiveReader => Unit) =
new SplashReader(reader, postIniter)
}
|