org.crsh.telnet.term.console.ConsoleTerm Maven / Gradle / Ivy
The newest version!
/*
* Copyright (C) 2012 eXo Platform SAS.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.crsh.telnet.term.console;
import org.crsh.telnet.term.CodeType;
import org.crsh.telnet.term.Term;
import org.crsh.telnet.term.TermEvent;
import org.crsh.telnet.term.spi.TermIO;
import org.crsh.text.Screenable;
import org.crsh.text.Style;
import java.io.IOException;
import java.util.LinkedList;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Implements the {@link Term interface}.
*/
public class ConsoleTerm implements Term {
/** . */
private final Logger log = Logger.getLogger(ConsoleTerm.class.getName());
/** . */
private final LinkedList history;
/** . */
private CharSequence historyBuffer;
/** . */
private int historyCursor;
/** . */
private final TermIO io;
/** . */
private final TermIOBuffer buffer;
/** . */
private final TermIOWriter writer;
public ConsoleTerm(final TermIO io) {
this.history = new LinkedList();
this.historyBuffer = null;
this.historyCursor = -1;
this.io = io;
this.buffer = new TermIOBuffer(io);
this.writer = new TermIOWriter(io);
}
public int getWidth() {
return io.getWidth();
}
public int getHeight() {
return io.getHeight();
}
public String getProperty(String name) {
return io.getProperty(name);
}
public void setEcho(boolean echo) {
buffer.setEchoing(echo);
}
public boolean takeAlternateBuffer() throws IOException {
return io.takeAlternateBuffer();
}
public boolean releaseAlternateBuffer() throws IOException {
return io.releaseAlternateBuffer();
}
public TermEvent read() throws IOException {
//
while (true) {
int code = io.read();
CodeType type = io.decode(code);
switch (type) {
case CLOSE:
return TermEvent.close();
case BACKSPACE:
buffer.del();
break;
case UP:
case DOWN:
int nextHistoryCursor = historyCursor + (type == CodeType.UP ? + 1 : -1);
if (nextHistoryCursor >= -1 && nextHistoryCursor < history.size()) {
CharSequence s = nextHistoryCursor == -1 ? historyBuffer : history.get(nextHistoryCursor);
while (buffer.moveRight()) {
// Do nothing
}
CharSequence t = buffer.replace(s);
if (historyCursor == -1) {
historyBuffer = t;
}
if (nextHistoryCursor == -1) {
historyBuffer = null;
}
historyCursor = nextHistoryCursor;
}
break;
case RIGHT:
buffer.moveRight();
break;
case LEFT:
buffer.moveLeft();
break;
case BREAK:
log.log(Level.FINE, "Want to cancel evaluation");
buffer.clear();
return TermEvent.brk();
case CHAR:
if (code >= 0 && code < 128) {
buffer.append((char)code);
} else {
log.log(Level.FINE, "Unhandled char " + code);
}
break;
case TAB:
log.log(Level.FINE, "Tab");
return TermEvent.complete(buffer.getBufferToCursor());
case BACKWARD_WORD: {
int cursor = buffer.getCursor();
int pos = cursor;
// Skip any white char first
while (pos > 0 && buffer.charAt(pos - 1) == ' ') {
pos--;
}
// Skip until next white char
while (pos > 0 && buffer.charAt(pos - 1) != ' ') {
pos--;
}
if (pos < cursor) {
buffer.moveLeft(cursor - pos);
}
break;
}
case FORWARD_WORD: {
int size = buffer.getSize();
int cursor = buffer.getCursor();
int pos = cursor;
// Skip any white char first
while (pos < size && buffer.charAt(pos) == ' ') {
pos++;
}
// Skip until next white char
while (pos < size && buffer.charAt(pos) != ' ') {
pos++;
}
if (pos > cursor) {
buffer.moveRight(pos - cursor);
}
break;
}
case BEGINNING_OF_LINE: {
int cursor = buffer.getCursor();
if (cursor > 0) {
buffer.moveLeft(cursor);
}
break;
}
case END_OF_LINE: {
int cursor = buffer.getSize() - buffer.getCursor();
if (cursor > 0) {
buffer.moveRight (cursor);
}
break;
}
}
//
if (buffer.hasNext()) {
historyCursor = -1;
historyBuffer = null;
CharSequence input = buffer.next();
return TermEvent.readLine(input);
}
}
}
public Appendable getDirectBuffer() {
return buffer;
}
public void addToHistory(CharSequence line) {
history.addFirst(line);
}
public CharSequence getBuffer() {
return buffer.getBufferToCursor();
}
public void flush() {
try {
io.flush();
}
catch (IOException e) {
log.log(Level.FINE, "Exception thrown during term flush()", e);
}
}
public void close() {
try {
log.log(Level.FINE, "Closing connection");
io.flush();
io.close();
} catch (IOException e) {
log.log(Level.FINE, "Exception thrown during term close()", e);
}
}
@Override
public Screenable append(CharSequence s) throws IOException {
writer.write(s);
return this;
}
@Override
public Appendable append(char c) throws IOException {
writer.write(c);
return this;
}
@Override
public Appendable append(CharSequence csq, int start, int end) throws IOException {
writer.write(csq.subSequence(start, end));
return this;
}
@Override
public Screenable append(Style style) throws IOException {
io.write((style));
return this;
}
@Override
public Screenable cls() throws IOException {
io.cls();
return this;
}
}