2012-08-08 7 views
9

C'è un tasto di scelta rapida per arrestare/uscire da Scala REPL?Tasto di scelta rapida per interrompere REPL?

Esempio: avvio il REPL di Scala da SBT con il comando console, quindi faccio qualcosa di stupido come un ciclo infinito e voglio terminare il REPL senza chiudere la shell. Qualcosa di simile Ctrl +C, Ctrl +D o Ctrl +Z (che tutti non funzionano).

Aggiornamento: SO utilizzato: Windows 7 64 bit.

Ctrl + D esiste SBT e la REPL, ma Ctrl + D non esce il REPL quando sono in un ciclo infinito come

while(true) prinln("test") 

C'è un modo per uscire dal ciclo infinito con un tasto di scelta rapida senza chiudere il guscio? O questo non è possibile perché REPL non reagirà ai tasti di scelta rapida fino a quando il ciclo non sarà completato (cosa che, ovviamente, non si verificherà in questo caso)?

+0

hm quale sistema operativo stai utilizzando? Perché ctrl + c sembra fare il trucco per me (sotto MacOS 10.6) –

+0

stai avviando da sbt, perché dici 'console'? –

+0

@MateuszDymczyk Oh, capisco, questo sembra essere un problema specifico del sistema operativo. Io uso Windows 7 64 Bit Edition. Ctrl + C non funziona per me. –

risposta

2

Quanto segue funziona con Scala 2.10.0-M6, ma in 2.9.2 è possibile ottenere qualcosa di simile utilizzando :wrap in modalità di alimentazione REPL.

Si supponga che REPL venga avviato da sbt tramite sbt console — senza perdita di generalità (altrimenti si potrebbe semplicemente mettere la classe ReplUtil sul percorso classe di scala). Supponiamo che la seguente classe si trovi sul percorso della classe, ad es. sua sorgente è a src/main/scala/ReplUtil.scala:

import java.util.concurrent.{Executors, ExecutorService, TimeoutException, TimeUnit} 
import concurrent._ 

object ReplUtil { 
    @volatile private var exec: ExecutorService = _ 
    @volatile private var threads = Set.empty[ Thread ] 
    private def freshPool() { exec = Executors.newCachedThreadPool() } 
    freshPool() 

    private implicit def context = ExecutionContext.fromExecutorService(exec) 

    def panic() { 
    (new Thread { 
     override def run() { 
     try { 
      exec.shutdownNow() 
      exec.awaitTermination(1, TimeUnit.SECONDS) 
     } finally { 
      val th = threads 
      threads = Set.empty 
      th.foreach(_.stop) 
      freshPool() 
     } 
     } 
    }).start() 
    }  

    def spawn[T](t: => T) = { 
    var futPrint = false 
    val fut = future { 
     val th = Thread.currentThread() 
     threads += th 
     val res = try { t } finally { threads -= th } 
     if(futPrint) println("<calculation done>\n" + res) 
     t 
    } 
    try { 
     Await.result(fut, util.Duration(4, TimeUnit.SECONDS)).toString 
    } catch { 
     case e: TimeoutException => 
     futPrint = true 
     "<ongoing calculation>" 
    } 
    } 
} 

Poi il seguente attiverà il REPL semi-asincrono:

$ sbt console 
... 
Welcome to Scala version 2.10.0-M6 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_33). 
... 
scala> import ReplUtil.panic 
import ReplUtil.panic 

scala> :power 
** Power User mode enabled - BEEP WHIR GYVE ** 
... 

scala> power.intp.setExecutionWrapper("ReplUtil.spawn") 

scala> 2+2 
res1: Int = 4 

scala> Thread.sleep(6000); 33 
<ongoing calculation> 

scala> <calculation done> 
res2: Int = 33 

scala> while(true) { Thread.sleep(2000); println("Zzz")} 
Zzz 
Zzz 
<ongoing calculation> 
scala> panic 

scala> [error] (pool-5-thread-1) java.lang.ExceptionInInitializerError 
java.lang.ExceptionInInitializerError 
... 
Caused by: java.lang.InterruptedException: sleep interrupted 
... 
+0

Come può un Q essere +6 mentre A è +0? Comunque, data la fine di: wrap, REPL ha bisogno di un template generico, con built-in per "cronometrato", "interrompibile", ecc. –

0

relative all'argomento è un utile spostamento + D chiave di associazione per uscire non terminare le valutazioni di un programma quando si trova all'interno di un foglio di scala di eclissi.