001 /* 002 * Copyright (C) 2010 eXo Platform SAS. 003 * 004 * This is free software; you can redistribute it and/or modify it 005 * under the terms of the GNU Lesser General Public License as 006 * published by the Free Software Foundation; either version 2.1 of 007 * the License, or (at your option) any later version. 008 * 009 * This software is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * You should have received a copy of the GNU Lesser General Public 015 * License along with this software; if not, write to the Free 016 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 017 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 018 */ 019 020 package org.crsh.term; 021 022 import org.crsh.term.console.Console; 023 import org.crsh.term.console.ViewWriter; 024 import org.crsh.term.spi.TermIO; 025 import org.slf4j.Logger; 026 import org.slf4j.LoggerFactory; 027 028 import java.io.IOException; 029 import java.util.LinkedList; 030 031 /** 032 * @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a> 033 * @version $Revision$ 034 */ 035 public class BaseTerm implements Term { 036 037 /** . */ 038 private final Logger log = LoggerFactory.getLogger(BaseTerm.class); 039 040 /** . */ 041 private final LinkedList<CharSequence> history; 042 043 /** . */ 044 private CharSequence historyBuffer; 045 046 /** . */ 047 private int historyCursor; 048 049 /** . */ 050 private final TermIO io; 051 052 /** . */ 053 private final Console console; 054 055 public BaseTerm(final TermIO io) { 056 this.history = new LinkedList<CharSequence>(); 057 this.historyBuffer = null; 058 this.historyCursor = -1; 059 this.io = io; 060 this.console = new Console(new ViewWriter() { 061 062 @Override 063 protected void flush() throws IOException { 064 io.flush(); 065 } 066 067 @Override 068 protected void writeCRLF() throws IOException { 069 io.writeCRLF(); 070 } 071 072 @Override 073 protected void write(CharSequence s) throws IOException { 074 io.write(s.toString()); 075 } 076 077 @Override 078 protected void write(char c) throws IOException { 079 io.write(c); 080 } 081 082 @Override 083 protected void writeDel() throws IOException { 084 io.writeDel(); 085 } 086 087 @Override 088 protected boolean writeMoveLeft() throws IOException { 089 return io.moveLeft(); 090 } 091 092 @Override 093 protected boolean writeMoveRight(char c) throws IOException { 094 return io.moveRight(c); 095 } 096 }); 097 } 098 099 public int getWidth() { 100 return io.getWidth(); 101 } 102 103 public String getProperty(String name) { 104 return io.getProperty(name); 105 } 106 107 public void setEcho(boolean echo) { 108 console.setEchoing(echo); 109 } 110 111 public TermEvent read() throws IOException { 112 113 // 114 while (true) { 115 int code = io.read(); 116 CodeType type = io.decode(code); 117 switch (type) { 118 case CLOSE: 119 return TermEvent.close(); 120 case BACKSPACE: 121 console.getViewReader().del(); 122 break; 123 case UP: 124 case DOWN: 125 int nextHistoryCursor = historyCursor + (type == CodeType.UP ? + 1 : -1); 126 if (nextHistoryCursor >= -1 && nextHistoryCursor < history.size()) { 127 CharSequence s = nextHistoryCursor == -1 ? historyBuffer : history.get(nextHistoryCursor); 128 while (console.getViewReader().moveRight()) { 129 // Do nothing 130 } 131 CharSequence t = console.getViewReader().replace(s); 132 if (historyCursor == -1) { 133 historyBuffer = t; 134 } 135 if (nextHistoryCursor == -1) { 136 historyBuffer = null; 137 } 138 historyCursor = nextHistoryCursor; 139 } 140 break; 141 case RIGHT: 142 console.getViewReader().moveRight(); 143 break; 144 case LEFT: 145 console.getViewReader().moveLeft(); 146 break; 147 case BREAK: 148 log.debug("Want to cancel evaluation"); 149 console.clearBuffer(); 150 return TermEvent.brk(); 151 case CHAR: 152 if (code >= 0 && code < 128) { 153 console.getViewReader().append((char)code); 154 } else { 155 log.debug("Unhandled char " + code); 156 } 157 break; 158 case TAB: 159 log.debug("Tab"); 160 return TermEvent.complete(console.getBufferToCursor()); 161 } 162 163 // 164 if (console.getReader().hasNext()) { 165 historyCursor = -1; 166 historyBuffer = null; 167 CharSequence input = console.getReader().next(); 168 return TermEvent.readLine(input); 169 } 170 } 171 } 172 173 public Appendable getInsertBuffer() { 174 return console.getViewReader(); 175 } 176 177 public void addToHistory(CharSequence line) { 178 history.addFirst(line); 179 } 180 181 public CharSequence getBuffer() { 182 return console.getBufferToCursor(); 183 } 184 185 public void close() { 186 try { 187 log.debug("Closing connection"); 188 io.flush(); 189 io.close(); 190 } catch (IOException e) { 191 log.debug("Exception thrown during term close()", e); 192 } 193 } 194 195 public void write(CharSequence msg) throws IOException { 196 console.getWriter().write(msg); 197 } 198 }