package org.jftclient.terminal; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.InterruptedIOException; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.StringUtils; import com.google.common.base.Strings; import javafx.application.Platform; import javafx.scene.control.TextArea; /** * @author sergei.malafeev */ public class TerminalWatcher implements Runnable { private static final Logger logger = LoggerFactory.getLogger(TerminalWatcher.class); private InputStream outFromChannel; private TextArea textArea; public TerminalWatcher(InputStream outFromChannel, TextArea textArea) { this.outFromChannel = outFromChannel; this.textArea = textArea; } public void run() { InputStreamReader isr = new InputStreamReader(outFromChannel); try { char[] buff = new char[1024]; int read; while ((read = isr.read(buff)) != -1) { String s = new String(buff, 0, read); Pattern pattern = Pattern.compile("^(\b+)(.*)"); Matcher mathcher = pattern.matcher(s); if (mathcher.find()) { String firstBacks = mathcher.group(1); s = mathcher.group(2); moveCursorLeft(firstBacks.length(), !Strings.isNullOrEmpty(s)); } boolean eraseLine = false; if (s.contains("\u001B[K")) { eraseLine = true; } boolean middleErase = false; int numBacks = 0; if (s.contains("\u001B[P")) { middleErase = true; numBacks = StringUtils.countOccurrencesOf(s, "\b"); } if (s.equals("\u001B[C")) { moveCursorRight(1); } String res = removeEscapes(s); if (!res.isEmpty()) { final boolean finalMiddleErase = middleErase; final int finalNumBacks = numBacks; Platform.runLater(() -> { if (finalMiddleErase) { textArea.insertText(textArea.getCaretPosition(), res); textArea.positionCaret(textArea.getCaretPosition() - finalNumBacks); } else { textArea.appendText(res); } }); } else if (eraseLine) { Platform.runLater(() -> { textArea.deleteText(textArea.getCaretPosition(), textArea.getLength()); }); } } } catch (InterruptedIOException e) { //ignore } catch (IOException e) { logger.warn("failed to read from ssh", e); } } private String removeEscapes(String source) { String target = source.replaceAll("\u001B[\\(\\)][AB012]", ""); target = target.replaceAll("\u001B\\[\\?*\\d*;*\\d*[a-zA-Z]", ""); target = target.replaceAll("\u001B[><=A-Z]", ""); target = target.replaceAll("\\[\\d*;*\\d*m", ""); target = target.replaceAll("\u000F", ""); target = target.replaceAll("\u0007", ""); target = target.replaceAll("\b", ""); return target; } private void moveCursorRight(int count) { Platform.runLater(() -> textArea.positionCaret(textArea.getCaretPosition() + count)); } private void moveCursorLeft(int count, boolean delete) { Platform.runLater(() -> { textArea.positionCaret(textArea.getCaretPosition() - count); if (delete) { textArea.deleteText(textArea.getCaretPosition(), textArea.getLength()); } }); } }