|
/** |
|
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE |
|
* Version 2, December 2004 |
|
* |
|
* Copyright (C) 2015 Lukáš Karas <lukas.karas@centrum.cz> |
|
* |
|
* Everyone is permitted to copy and distribute verbatim or modified |
|
* copies of this license document, and changing it is allowed as long |
|
* as the name is changed. |
|
* |
|
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE |
|
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION |
|
* |
|
* 0. You just DO WHAT THE FUCK YOU WANT TO. |
|
*/ |
|
|
|
import java.awt.event.{ActionEvent, ActionListener} |
|
import scala.tools.jline.console.ConsoleReader |
|
|
|
/** |
|
* JLine don't support skipping words on input by classic shortcut |
|
* (CTRL + Left / Right arrow). Terminal generates sequence of |
|
* virtual keys when CTRL + other char is pressed (49 59 53 ...). |
|
* So it is simple to write listener on these sequences. |
|
*/ |
|
object Console{ |
|
|
|
|
|
class HistoryInputStream(in: InputStream, bufferLen: Int) extends InputStream { |
|
var offset: Int = 0 |
|
val ringBuffer = new Array[Int](bufferLen) |
|
|
|
def history(histOff: Int): Int = { |
|
val off = histOff - 1 |
|
if (off > 0 || (bufferLen + off) < 0) 0 |
|
else ringBuffer((offset + bufferLen + off) % bufferLen) |
|
} |
|
|
|
override def read(): Int = { |
|
val i = in.read() |
|
ringBuffer(offset) = i |
|
offset = (offset + 1) % bufferLen |
|
i |
|
} |
|
} |
|
|
|
def apply(): ConsoleReader = { |
|
val characterInput = new HistoryInputStream(new FileInputStream(FileDescriptor.in), 8) |
|
val consoleReader = new ConsoleReader(characterInput, System.out, null, null) |
|
val terminal = consoleReader.getTerminal |
|
val cursorBuffer = consoleReader.getCursorBuffer() |
|
|
|
def skipWord(ch: () => Char, move: () => Boolean): Unit = { |
|
while (ch().isWhitespace && move()) {} |
|
while (!ch().isWhitespace && move()) {} |
|
} |
|
|
|
if (terminal.isSupported && terminal.isInstanceOf[UnixTerminal]) { |
|
consoleReader.addTriggeredAction(49, new ActionListener { |
|
|
|
override def actionPerformed(e: ActionEvent): Unit = { |
|
|
|
// This is little bit hack. Ctrl prefix is consumed by UnixTerminal, we have to look into history... |
|
if (characterInput.history(-2) != 27 /*ARROW_START*/ || characterInput.history(-1) != 91 /*ARROW_PREFIX*/ ) { |
|
consoleReader.putString(49.toChar.toString) // if Ctrl prefix not found in history, 49 is just character "1" |
|
} else { |
|
if (characterInput.read() == 59 && characterInput.read() == 53) { |
|
// Ctrl + ... |
|
characterInput.read() match { |
|
// Ctrl + Right Arrow |
|
case 67 => skipWord( |
|
() => cursorBuffer.charAtCursor(), |
|
() => consoleReader.moveCursor(+1) != 0) |
|
|
|
// Ctrl + Left Arrow |
|
case 68 => skipWord( |
|
() => cursorBuffer.charLeftOfCursor(), |
|
() => consoleReader.moveCursor(-1) != 0) |
|
|
|
case _ => {} |
|
} |
|
|
|
} |
|
} |
|
} |
|
}) |
|
} |
|
consoleReader |
|
} |
|
} |