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(int c) throws IOException { }
176 @Override public void write(Style d) throws IOException { }
177 @Override public void writeDel() throws IOException { }
178 @Override public void writeCRLF() throws IOException { }
179 @Override public void cls() throws IOException { }
180 @Override public boolean moveRight(char c) throws IOException { return true; }
181 @Override public boolean moveLeft() throws IOException { return true; }
182 @Override public void close() throws IOException { }
183 };
184 }