summaryrefslogtreecommitdiff
path: root/src/repl
diff options
context:
space:
mode:
Diffstat (limited to 'src/repl')
-rw-r--r--src/repl/scala/tools/nsc/interpreter/ConsoleReaderHelper.scala2
-rw-r--r--src/repl/scala/tools/nsc/interpreter/Delimited.scala2
-rw-r--r--src/repl/scala/tools/nsc/interpreter/ILoop.scala86
-rw-r--r--src/repl/scala/tools/nsc/interpreter/JLineReader.scala6
-rw-r--r--src/repl/scala/tools/nsc/interpreter/session/SimpleHistory.scala5
-rw-r--r--src/repl/scala/tools/nsc/interpreter/session/package.scala8
6 files changed, 100 insertions, 9 deletions
diff --git a/src/repl/scala/tools/nsc/interpreter/ConsoleReaderHelper.scala b/src/repl/scala/tools/nsc/interpreter/ConsoleReaderHelper.scala
index 48af261937..cf03ecb480 100644
--- a/src/repl/scala/tools/nsc/interpreter/ConsoleReaderHelper.scala
+++ b/src/repl/scala/tools/nsc/interpreter/ConsoleReaderHelper.scala
@@ -6,7 +6,7 @@
package scala.tools.nsc
package interpreter
-import scala.tools.jline.console.{ ConsoleReader, CursorBuffer }
+import jline.console.{ ConsoleReader, CursorBuffer }
trait ConsoleReaderHelper extends ConsoleReader {
def terminal = getTerminal()
diff --git a/src/repl/scala/tools/nsc/interpreter/Delimited.scala b/src/repl/scala/tools/nsc/interpreter/Delimited.scala
index e88a044931..b7f06f1d0a 100644
--- a/src/repl/scala/tools/nsc/interpreter/Delimited.scala
+++ b/src/repl/scala/tools/nsc/interpreter/Delimited.scala
@@ -6,7 +6,7 @@
package scala.tools.nsc
package interpreter
-import scala.tools.jline.console.completer.ArgumentCompleter.{ ArgumentDelimiter, ArgumentList }
+import jline.console.completer.ArgumentCompleter.{ ArgumentDelimiter, ArgumentList }
class JLineDelimiter extends ArgumentDelimiter {
def toJLine(args: List[String], cursor: Int) = args match {
diff --git a/src/repl/scala/tools/nsc/interpreter/ILoop.scala b/src/repl/scala/tools/nsc/interpreter/ILoop.scala
index e8265e55f4..dc5183fdf6 100644
--- a/src/repl/scala/tools/nsc/interpreter/ILoop.scala
+++ b/src/repl/scala/tools/nsc/interpreter/ILoop.scala
@@ -208,12 +208,14 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
/** Standard commands **/
lazy val standardCommands = List(
cmd("cp", "<path>", "add a jar or directory to the classpath", addClasspath),
+ cmd("edit", "<id>|<line>", "edit history", editCommand),
cmd("help", "[command]", "print this summary or command-specific help", helpCommand),
historyCommand,
cmd("h?", "<string>", "search the history", searchHistory),
cmd("imports", "[name name ...]", "show import history, identifying sources of names", importsCommand),
cmd("implicits", "[-v]", "show the implicits in scope", intp.implicitsCommand),
cmd("javap", "<path|class>", "disassemble a file or class name", javapCommand),
+ cmd("line", "<id>|<line>", "place line(s) at the end of history", lineCommand),
cmd("load", "<path>", "load and interpret a Scala file", loadCommand),
nullary("paste", "enter paste mode: all input up to ctrl-D compiled together", pasteCommand),
nullary("power", "enable power user mode", powerCmd),
@@ -486,6 +488,90 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
unleashAndSetPhase()
}
+ def lineCommand(what: String): Result = editCommand(what, None)
+
+ // :edit id or :edit line
+ def editCommand(what: String): Result = editCommand(what, Properties.envOrNone("EDITOR"))
+
+ def editCommand(what: String, editor: Option[String]): Result = {
+ def diagnose(code: String) = {
+ echo("The edited code is incomplete!\n")
+ val errless = intp compileSources new BatchSourceFile("<pastie>", s"object pastel {\n$code\n}")
+ if (errless) echo("The compiler reports no errors.")
+ }
+ def historicize(text: String) = history match {
+ case jlh: JLineHistory => text.lines foreach jlh.add ; jlh.moveToEnd() ; true
+ case _ => false
+ }
+ def edit(text: String): Result = editor match {
+ case Some(ed) =>
+ val tmp = File.makeTemp()
+ tmp.writeAll(text)
+ try {
+ val pr = new ProcessResult(s"$ed ${tmp.path}")
+ pr.exitCode match {
+ case 0 =>
+ tmp.safeSlurp() match {
+ case Some(edited) if edited.trim.isEmpty => echo("Edited text is empty.")
+ case Some(edited) =>
+ echo(edited.lines map ("+" + _) mkString "\n")
+ val res = intp interpret edited
+ if (res == IR.Incomplete) diagnose(edited)
+ else {
+ historicize(edited)
+ Result(lineToRecord = Some(edited), keepRunning = true)
+ }
+ case None => echo("Can't read edited text. Did you delete it?")
+ }
+ case x => echo(s"Error exit from $ed ($x), ignoring")
+ }
+ } finally {
+ tmp.delete()
+ }
+ case None =>
+ if (historicize(text)) echo("Placing text in recent history.")
+ else echo(f"No EDITOR defined and you can't change history, echoing your text:%n$text")
+ }
+
+ // if what is a number, use it as a line number or range in history
+ def isNum = what forall (c => c.isDigit || c == '-' || c == '+')
+ // except that "-" means last value
+ def isLast = (what == "-")
+ if (isLast || !isNum) {
+ val name = if (isLast) intp.mostRecentVar else what
+ val sym = intp.symbolOfIdent(name)
+ intp.prevRequestList collectFirst { case r if r.defines contains sym => r } match {
+ case Some(req) => edit(req.line)
+ case None => echo(s"No symbol in scope: $what")
+ }
+ } else try {
+ val s = what
+ // line 123, 120+3, -3, 120-123, 120-, note -3 is not 0-3 but (cur-3,cur)
+ val (start, len) =
+ if ((s indexOf '+') > 0) {
+ val (a,b) = s splitAt (s indexOf '+')
+ (a.toInt, b.drop(1).toInt)
+ } else {
+ (s indexOf '-') match {
+ case -1 => (s.toInt, 1)
+ case 0 => val n = s.drop(1).toInt ; (history.index - n, n)
+ case _ if s.last == '-' => val n = s.init.toInt ; (n, history.index - n)
+ case i => val n = s.take(i).toInt ; (n, s.drop(i+1).toInt - n)
+ }
+ }
+ import scala.collection.JavaConverters._
+ val index = (start - 1) max 0
+ val text = history match {
+ case jlh: JLineHistory => jlh.entries(index).asScala.take(len) map (_.value) mkString "\n"
+ case _ => history.asStrings.slice(index, index + len) mkString "\n"
+ }
+ edit(text)
+ } catch {
+ case _: NumberFormatException => echo(s"Bad range '$what'")
+ echo("Use line 123, 120+3, -3, 120-123, 120-, note -3 is not 0-3 but (cur-3,cur)")
+ }
+ }
+
/** fork a shell and run a command */
lazy val shCommand = new LoopCommand("sh", "run a shell command (result is implicitly => List[String])") {
override def usage = "<command line>"
diff --git a/src/repl/scala/tools/nsc/interpreter/JLineReader.scala b/src/repl/scala/tools/nsc/interpreter/JLineReader.scala
index 5d41f1bbb4..d8a876feb2 100644
--- a/src/repl/scala/tools/nsc/interpreter/JLineReader.scala
+++ b/src/repl/scala/tools/nsc/interpreter/JLineReader.scala
@@ -6,8 +6,8 @@
package scala.tools.nsc
package interpreter
-import scala.tools.jline.console.ConsoleReader
-import scala.tools.jline.console.completer._
+import jline.console.ConsoleReader
+import jline.console.completer._
import session._
import Completion._
@@ -42,7 +42,7 @@ class JLineReader(_completion: => Completion) extends InteractiveReader {
def readOneKey(prompt: String) = {
this.print(prompt)
this.flush()
- this.readVirtualKey()
+ this.readCharacter()
}
def eraseLine() = consoleReader.resetPromptLine("", "", 0)
def redrawLineAndFlush(): Unit = { flush() ; drawLine() ; flush() }
diff --git a/src/repl/scala/tools/nsc/interpreter/session/SimpleHistory.scala b/src/repl/scala/tools/nsc/interpreter/session/SimpleHistory.scala
index 89998e438a..7c49b91296 100644
--- a/src/repl/scala/tools/nsc/interpreter/session/SimpleHistory.scala
+++ b/src/repl/scala/tools/nsc/interpreter/session/SimpleHistory.scala
@@ -46,6 +46,11 @@ class SimpleHistory extends JLineHistory {
def entries(): JListIterator[JEntry] = toEntries().asJava.listIterator()
def iterator: JIterator[JEntry] = toEntries().iterator.asJava
+ def remove(idx: Int): CharSequence = buf remove idx
+ def removeFirst(): CharSequence = buf remove 0
+ def removeLast(): CharSequence = buf remove lastIndex
+ def set(idx: Int, to: CharSequence): Unit = buf(idx) = to
+
def current() = if (index >= 0 && index < buf.size) buf(index) else fail("current()")
def previous() = (index > 0) && minusOne
def next() = (index <= lastIndex) && plusOne
diff --git a/src/repl/scala/tools/nsc/interpreter/session/package.scala b/src/repl/scala/tools/nsc/interpreter/session/package.scala
index c62cf21151..a3d7312c98 100644
--- a/src/repl/scala/tools/nsc/interpreter/session/package.scala
+++ b/src/repl/scala/tools/nsc/interpreter/session/package.scala
@@ -14,10 +14,10 @@ package object session {
type JIterator[T] = java.util.Iterator[T]
type JListIterator[T] = java.util.ListIterator[T]
- type JEntry = scala.tools.jline.console.history.History.Entry
- type JHistory = scala.tools.jline.console.history.History
- type JMemoryHistory = scala.tools.jline.console.history.MemoryHistory
- type JPersistentHistory = scala.tools.jline.console.history.PersistentHistory
+ type JEntry = jline.console.history.History.Entry
+ type JHistory = jline.console.history.History
+ type JMemoryHistory = jline.console.history.MemoryHistory
+ type JPersistentHistory = jline.console.history.PersistentHistory
private[interpreter] implicit def charSequenceFix(x: CharSequence): String = x.toString
}