001 /* 002 * Copyright (C) 2012 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 package org.crsh.console; 020 021 import org.crsh.cli.impl.line.LineParser; 022 import org.crsh.cli.impl.line.MultiLineVisitor; 023 import org.crsh.text.Style; 024 025 import java.io.IOException; 026 import java.util.ArrayList; 027 import java.util.LinkedList; 028 029 /** 030 * An editor state machine. 031 * 032 * todo: 033 * - undo 034 * - optimize operation with an improvement of {@link org.crsh.console.EditorBuffer} 035 * 036 * @author Julien Viet 037 */ 038 class Editor extends Plugin { 039 040 /** . */ 041 final Console console; 042 043 /** . */ 044 final EditorBuffer buffer; 045 046 /** . */ 047 final MultiLineVisitor visitor; 048 049 /** The line parser : updated on enter key. */ 050 final LineParser lineParser; 051 052 /** . */ 053 final LinkedList<String> history; 054 055 /** . */ 056 private Mode mode; 057 058 /** . */ 059 int historyCursor; 060 061 /** . */ 062 String historyBuffer; 063 064 /** The buffer that holds what we kill. */ 065 final StringBuilder killBuffer; 066 067 /** . */ 068 private final ArrayList<Runnable> modeListeners; 069 070 Editor(Console console) { 071 this(console, true); 072 } 073 074 Editor(Console console, boolean echo) { 075 076 077 // 078 EditorBuffer buffer = new EditorBuffer(echo ? console.driver : NULL); 079 080 // 081 this.console = console; 082 this.buffer = buffer; 083 this.visitor = new MultiLineVisitor(); 084 this.lineParser = new LineParser(visitor); 085 this.history = new LinkedList<String>(); 086 this.historyCursor = -1; 087 this.historyBuffer = null; 088 this.killBuffer = new StringBuilder(); 089 this.mode = Mode.EMACS; 090 this.modeListeners = new ArrayList<Runnable>(); 091 } 092 093 Mode getMode() { 094 return mode; 095 } 096 097 void setMode(Mode mode) { 098 this.mode = mode; 099 for (Runnable listener : modeListeners) { 100 listener.run(); 101 } 102 } 103 104 void addModeListener(Runnable runnable) { 105 modeListeners.add(runnable); 106 } 107 108 void addToHistory(String line) { 109 history.addFirst(line); 110 } 111 112 /** 113 * Returns the right cursor bound depending on the current mode. 114 * 115 * @return the current bound 116 */ 117 int getCursorBound() { 118 if (console.getMode() == Mode.EMACS) { 119 return buffer.getSize(); 120 } else { 121 return Math.max(0, buffer.getSize() - 1); 122 } 123 } 124 125 String getKillBuffer() { 126 return killBuffer.toString(); 127 } 128 129 void setKillBuffer(CharSequence s) { 130 if (s == null) { 131 throw new NullPointerException("No null buffer content"); 132 } 133 killBuffer.setLength(0); 134 killBuffer.append(s); 135 } 136 137 boolean isEmpty() { 138 return buffer.getSize() == 0 && buffer.getLines().size() == 1; 139 } 140 141 String getCurrentLine() { 142 return buffer.getLine(); 143 } 144 145 int getCurrentPosition() { 146 return buffer.getCursor(); 147 } 148 149 String append(EditorAction action, int[] sequence) { 150 try { 151 return action.execute(this, buffer, sequence, true); 152 } 153 catch (IOException e) { 154 AssertionError ae = new AssertionError("Not yet supported"); 155 ae.initCause(e); 156 throw ae; 157 } 158 } 159 160 void reset() { 161 lineParser.reset(); 162 buffer.reset(); 163 historyCursor = -1; 164 } 165 166 // Null impl for echo 167 private static final ConsoleDriver NULL = new ConsoleDriver() { 168 @Override public int getWidth() { return 80; } 169 @Override public int getHeight() { return 40; } 170 @Override public String getProperty(String name) { return null; } 171 @Override public boolean takeAlternateBuffer() throws IOException { return false; } 172 @Override public boolean releaseAlternateBuffer() throws IOException { return false; } 173 @Override public void flush() throws IOException { } 174 @Override public void write(CharSequence s) throws IOException { } 175 @Override public void write(CharSequence s, int start, int end) throws IOException { } 176 @Override public void write(char c) throws IOException { } 177 @Override public void write(Style d) throws IOException { } 178 @Override public void writeDel() throws IOException { } 179 @Override public void writeCRLF() throws IOException { } 180 @Override public void cls() throws IOException { } 181 @Override public boolean moveRight(char c) throws IOException { return true; } 182 @Override public boolean moveLeft() throws IOException { return true; } 183 @Override public void close() throws IOException { } 184 }; 185 }