|
|||||||||||||||||||
| Source file | Conditionals | Statements | Methods | TOTAL | |||||||||||||||
| InteractionsDocument.java | 25% | 63.4% | 70.6% | 60.6% |
|
||||||||||||||
| 1 | /*BEGIN_COPYRIGHT_BLOCK | |
| 2 | * | |
| 3 | * Copyright (c) 2001-2010, JavaPLT group at Rice University (drjava@rice.edu) | |
| 4 | * All rights reserved. | |
| 5 | * | |
| 6 | * Redistribution and use in source and binary forms, with or without | |
| 7 | * modification, are permitted provided that the following conditions are met: | |
| 8 | * * Redistributions of source code must retain the above copyright | |
| 9 | * notice, this list of conditions and the following disclaimer. | |
| 10 | * * Redistributions in binary form must reproduce the above copyright | |
| 11 | * notice, this list of conditions and the following disclaimer in the | |
| 12 | * documentation and/or other materials provided with the distribution. | |
| 13 | * * Neither the names of DrJava, the JavaPLT group, Rice University, nor the | |
| 14 | * names of its contributors may be used to endorse or promote products | |
| 15 | * derived from this software without specific prior written permission. | |
| 16 | * | |
| 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 18 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 19 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 20 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | |
| 21 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
| 22 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
| 23 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
| 24 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
| 25 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
| 26 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
| 27 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 28 | * | |
| 29 | * This software is Open Source Initiative approved Open Source Software. | |
| 30 | * Open Source Initative Approved is a trademark of the Open Source Initiative. | |
| 31 | * | |
| 32 | * This file is part of DrJava. Download the current version of this project | |
| 33 | * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/ | |
| 34 | * | |
| 35 | * END_COPYRIGHT_BLOCK*/ | |
| 36 | ||
| 37 | package edu.rice.cs.drjava.model.repl; | |
| 38 | ||
| 39 | import java.io.*; | |
| 40 | import java.awt.print.*; | |
| 41 | ||
| 42 | import edu.rice.cs.drjava.model.print.DrJavaBook; | |
| 43 | ||
| 44 | import edu.rice.cs.drjava.model.FileSaveSelector; | |
| 45 | import edu.rice.cs.util.UnexpectedException; | |
| 46 | import edu.rice.cs.util.OperationCanceledException; | |
| 47 | import edu.rice.cs.util.text.ConsoleDocumentInterface; | |
| 48 | import edu.rice.cs.util.text.EditDocumentException; | |
| 49 | import edu.rice.cs.util.text.ConsoleDocument; | |
| 50 | import edu.rice.cs.drjava.config.OptionListener; | |
| 51 | ||
| 52 | /** A GUI toolkit-agnostic document that supports console-like interaction with a Java interpreter. | |
| 53 | * This class assumes that the embedded document supports readers/writers locking and uses that locking | |
| 54 | * protocol to ensure the integrity of the data added in this class | |
| 55 | * @version $Id: InteractionsDocument.java 5202 2010-03-29 04:00:48Z mgricken $ | |
| 56 | */ | |
| 57 | public class InteractionsDocument extends ConsoleDocument { | |
| 58 | ||
| 59 | /** Default prompt. */ | |
| 60 | public static final String DEFAULT_PROMPT = "> "; | |
| 61 | ||
| 62 | /** Style for error messages */ | |
| 63 | public static final String ERROR_STYLE = "error"; | |
| 64 | ||
| 65 | /** Style for debugger messages */ | |
| 66 | public static final String DEBUGGER_STYLE = "debugger"; | |
| 67 | ||
| 68 | public static final String OBJECT_RETURN_STYLE = "object.return.style"; | |
| 69 | ||
| 70 | public static final String STRING_RETURN_STYLE = "string.return.style"; | |
| 71 | ||
| 72 | public static final String CHARACTER_RETURN_STYLE = "character.return.style"; | |
| 73 | ||
| 74 | public static final String NUMBER_RETURN_STYLE = "number.return.style"; | |
| 75 | ||
| 76 | /** Command-line history. It's not reset when the interpreter is reset. */ | |
| 77 | private final History _history; | |
| 78 | ||
| 79 | /* Constructors */ | |
| 80 | ||
| 81 | /** Reset the document on startUp. Uses a history with configurable size. | |
| 82 | * @param document the edit document to use for the model | |
| 83 | */ | |
| 84 | 5 | public InteractionsDocument(ConsoleDocumentInterface document) { |
| 85 | 5 | this(document, new History()); |
| 86 | } | |
| 87 | ||
| 88 | /** Reset the document on startUp. Uses a history with the given maximum size. This history will not use the config | |
| 89 | * framework. | |
| 90 | * @param document EditDocumentInterface to use for the model | |
| 91 | * @param maxHistorySize Number of commands to remember in the history | |
| 92 | */ | |
| 93 | 188 | public InteractionsDocument(ConsoleDocumentInterface document, int maxHistorySize) { |
| 94 | 188 | this(document, new History(maxHistorySize)); |
| 95 | } | |
| 96 | ||
| 97 | /** Creates and resets the interactions document on DrJava startUp. Uses the given history. | |
| 98 | * @param document EditDocumentInterface to use for the model | |
| 99 | * @param history History of commands | |
| 100 | */ | |
| 101 | 193 | public InteractionsDocument(ConsoleDocumentInterface document, History history) { |
| 102 | 193 | super(document); // initializes _document = document; |
| 103 | 193 | _history = history; |
| 104 | 193 | _document.setHasPrompt(true); |
| 105 | 193 | _prompt = DEFAULT_PROMPT; |
| 106 | } | |
| 107 | ||
| 108 | /** Lets this document know whether an interaction is in progress. | |
| 109 | * @param inProgress whether an interaction is in progress | |
| 110 | */ | |
| 111 | 201 | public void setInProgress(boolean inProgress) { _document.setHasPrompt(! inProgress); } |
| 112 | ||
| 113 | /** Returns whether an interaction is currently in progress. */ | |
| 114 | 47 | public boolean inProgress() { return ! _document.hasPrompt(); } |
| 115 | ||
| 116 | /** Sets the banner in an empty docuemnt. */ | |
| 117 | 193 | public void setBanner(String banner) { |
| 118 | 193 | try { |
| 119 | 193 | setPromptPos(0); |
| 120 | 193 | insertText(0, banner, OBJECT_RETURN_STYLE); |
| 121 | 193 | insertPrompt(); |
| 122 | 193 | _history.moveEnd(); |
| 123 | } | |
| 124 | 0 | catch (EditDocumentException e) { throw new UnexpectedException(e); } |
| 125 | } | |
| 126 | ||
| 127 | /** Resets the document to a clean state. Does not reset the history. */ | |
| 128 | 32 | public void reset(String banner) { |
| 129 | 32 | try { |
| 130 | // System.err.println("Resetting the interactions document with banner '" + banner + "'"); | |
| 131 | // Clear interactions document | |
| 132 | 32 | setHasPrompt(false); |
| 133 | 32 | setPromptPos(0); |
| 134 | 32 | removeText(0, _document.getLength()); |
| 135 | 32 | insertText(0, banner, OBJECT_RETURN_STYLE); |
| 136 | // System.err.println("Inserting prompt in cleared interactions pane"); | |
| 137 | 32 | insertPrompt(); |
| 138 | 32 | _history.moveEnd(); |
| 139 | 32 | setInProgress(false); // redundant? also done in InteractionsDocument.interpreterReady(...) |
| 140 | } | |
| 141 | 0 | catch (EditDocumentException e) { throw new UnexpectedException(e); } |
| 142 | } | |
| 143 | ||
| 144 | /** Replaces any text entered past the prompt with the current item in the history. Only runs in event thread. */ | |
| 145 | 2 | private void _replaceCurrentLineFromHistory() { |
| 146 | 2 | try { |
| 147 | 2 | _clearCurrentInputText(); |
| 148 | 2 | append(_history.getCurrent(), DEFAULT_STYLE); |
| 149 | } | |
| 150 | 0 | catch (EditDocumentException ble) { throw new UnexpectedException(ble); } |
| 151 | } | |
| 152 | ||
| 153 | /** Accessor method for the history of commands. */ | |
| 154 | 157 | public OptionListener<Integer> getHistoryOptionListener() { return _history.getHistoryOptionListener(); } |
| 155 | ||
| 156 | /** Adds the given text to the history of commands. */ | |
| 157 | 45 | public void addToHistory(String text) { _history.add(text); } |
| 158 | ||
| 159 | /** Returns the last history item and then removes it, or returns null if the history is empty. */ | |
| 160 | 0 | public String removeLastFromHistory() { return _history.removeLast(); } |
| 161 | ||
| 162 | /** Saves the unedited version of the current history to a file | |
| 163 | * @param selector File to save to | |
| 164 | */ | |
| 165 | 1 | public void saveHistory(FileSaveSelector selector) throws IOException { _history.writeToFile(selector); } |
| 166 | ||
| 167 | /** Saves the edited version of the current history to a file | |
| 168 | * @param selector File to save to | |
| 169 | * @param editedVersion Edited version of the history which will be | |
| 170 | * saved to file instead of the lines saved in the history. The saved | |
| 171 | * file will still include any tags needed to recognize it as a saved | |
| 172 | * interactions file. | |
| 173 | */ | |
| 174 | 0 | public void saveHistory(FileSaveSelector selector, String editedVersion) throws IOException { |
| 175 | 0 | History.writeToFile(selector, editedVersion); |
| 176 | } | |
| 177 | ||
| 178 | /** Returns the entire history as a single string. Commands should be separated by semicolons. If an entire | |
| 179 | * command does not end in a semicolon, one is added. | |
| 180 | */ | |
| 181 | 1 | public String getHistoryAsStringWithSemicolons() { |
| 182 | 1 | return _history.getHistoryAsStringWithSemicolons(); |
| 183 | } | |
| 184 | ||
| 185 | /** Returns the entire history as a single string. Commands should be separated by semicolons. */ | |
| 186 | 2 | public String getHistoryAsString() { |
| 187 | 2 | return _history.getHistoryAsString(); |
| 188 | } | |
| 189 | ||
| 190 | /** Clears the history */ | |
| 191 | 1 | public void clearHistory() { _history.clear(); } |
| 192 | ||
| 193 | 0 | public String lastEntry() { return _history.lastEntry(); } |
| 194 | /** Puts the previous line from the history on the current line and moves the history back one line. | |
| 195 | * @param entry the current entry (perhaps edited from what is in history) | |
| 196 | */ | |
| 197 | 1 | public void moveHistoryPrevious(String entry) { |
| 198 | 1 | _history.movePrevious(entry); |
| 199 | 1 | _replaceCurrentLineFromHistory(); |
| 200 | } | |
| 201 | ||
| 202 | /** Puts the next line from the history on the current line and moves the history forward one line. | |
| 203 | * @param entry the current entry (perhaps edited from what is in history) | |
| 204 | */ | |
| 205 | 1 | public void moveHistoryNext(String entry) { |
| 206 | 1 | _history.moveNext(entry); |
| 207 | 1 | _replaceCurrentLineFromHistory(); |
| 208 | } | |
| 209 | ||
| 210 | /** Returns whether there is a previous command in the history. Only runs in event thread. */ | |
| 211 | 2 | private boolean hasHistoryPrevious() { return _history.hasPrevious(); } |
| 212 | ||
| 213 | /** Returns whether there is a next command in the history. Only runs in event thread. */ | |
| 214 | 2 | public boolean hasHistoryNext() { return _history.hasNext(); } |
| 215 | ||
| 216 | /** Reverse searches the history for the given string. | |
| 217 | * @param searchString the string to search for | |
| 218 | */ | |
| 219 | 0 | public void reverseHistorySearch(String searchString) { |
| 220 | 0 | _history.reverseSearch(searchString); |
| 221 | 0 | _replaceCurrentLineFromHistory(); |
| 222 | } | |
| 223 | ||
| 224 | /** Forward searches the history for the given string. | |
| 225 | * @param searchString the string to search for | |
| 226 | */ | |
| 227 | 0 | public void forwardHistorySearch(String searchString) { |
| 228 | 0 | _history.forwardSearch(searchString); |
| 229 | 0 | _replaceCurrentLineFromHistory(); |
| 230 | } | |
| 231 | ||
| 232 | /** Gets the previous interaction in the history and replaces whatever is on the current interactions input | |
| 233 | * line with this interaction. Only runs in event thread. | |
| 234 | */ | |
| 235 | 2 | public boolean recallPreviousInteractionInHistory() { |
| 236 | 2 | if (hasHistoryPrevious()) { |
| 237 | 1 | moveHistoryPrevious(getCurrentInteraction()); |
| 238 | 1 | return true; |
| 239 | } | |
| 240 | 1 | _beep.run(); |
| 241 | 1 | return false; |
| 242 | } | |
| 243 | ||
| 244 | /** Gets the next interaction in the history and replaces whatever is on the current interactions input line | |
| 245 | * with this interaction. | |
| 246 | */ | |
| 247 | 2 | public boolean recallNextInteractionInHistory() { |
| 248 | 2 | if (hasHistoryNext()) { |
| 249 | 1 | moveHistoryNext(getCurrentInteraction()); |
| 250 | 1 | return true; |
| 251 | } | |
| 252 | 1 | _beep.run(); |
| 253 | 1 | return false; |
| 254 | } | |
| 255 | ||
| 256 | ||
| 257 | /** Reverse searches the history for interactions that started with the current interaction. */ | |
| 258 | 0 | public void reverseSearchInteractionsInHistory() { |
| 259 | 0 | if (hasHistoryPrevious()) reverseHistorySearch(getCurrentInteraction()); |
| 260 | 0 | else _beep.run(); |
| 261 | } | |
| 262 | ||
| 263 | /** Forward searches the history for interactions that started with the current interaction. */ | |
| 264 | 0 | public void forwardSearchInteractionsInHistory() { |
| 265 | 0 | if (hasHistoryNext()) forwardHistorySearch(getCurrentInteraction()); |
| 266 | 0 | else _beep.run(); |
| 267 | } | |
| 268 | ||
| 269 | /** Inserts the given exception data into the document with the given style. | |
| 270 | * @param message Message contained in the exception | |
| 271 | * @param styleName name of the style for formatting the exception | |
| 272 | */ | |
| 273 | 1 | public void appendExceptionResult(String message, String styleName) { |
| 274 | // Note that there is similar code in InteractionsDJDocument. Something should be refactored. | |
| 275 | ||
| 276 | // TODO: should probably log this error, or figure out what causes it (mgricken) | |
| 277 | // it does not seem to affect the program negatively, though | |
| 278 | // I'm commenting out, just to see when it appears | |
| 279 | // if (message != null && (message.equals("Connection refused to host: 127.0.0.1; nested exception is: \n" + | |
| 280 | // "\tjava.net.ConnectException: Connection refused: connect"))) return; | |
| 281 | 1 | try { append(message + "\n", styleName); } |
| 282 | 0 | catch (EditDocumentException ble) { throw new UnexpectedException(ble); } |
| 283 | } | |
| 284 | ||
| 285 | 0 | public void appendSyntaxErrorResult(String message, String interaction, int startRow, int startCol, |
| 286 | int endRow, int endCol, String styleName) { | |
| 287 | 0 | try { |
| 288 | 0 | if (null == message || "null".equals(message)) message = ""; |
| 289 | ||
| 290 | 0 | if (message.indexOf("Lexical error") != -1) { |
| 291 | 0 | int i = message.lastIndexOf(':'); |
| 292 | 0 | if (i != -1) message = "Syntax Error:" + message.substring(i+2, message.length()); |
| 293 | } | |
| 294 | ||
| 295 | 0 | if (message.indexOf("Error") == -1) message = "Error: " + message; |
| 296 | ||
| 297 | 0 | append(message + "\n" , styleName); |
| 298 | } | |
| 299 | 0 | catch (EditDocumentException ble) { throw new UnexpectedException(ble); } |
| 300 | } | |
| 301 | ||
| 302 | /** Clears the current input text and then moves to the end of the command history. */ | |
| 303 | 12 | public void clearCurrentInteraction() { |
| 304 | 12 | super.clearCurrentInput(); |
| 305 | 12 | _history.moveEnd(); |
| 306 | } | |
| 307 | ||
| 308 | /** Returns the string that the user has entered at the current prompt. Forwards to getCurrentInput(). */ | |
| 309 | 60 | public String getCurrentInteraction() { return getCurrentInput(); } |
| 310 | ||
| 311 | 0 | public String getDefaultStyle() { return InteractionsDocument.DEFAULT_STYLE; } |
| 312 | ||
| 313 | /** This method tells the document to prepare all the DrJavaBook and PagePrinter objects. */ | |
| 314 | 0 | public void preparePrintJob() { |
| 315 | 0 | _book = new DrJavaBook(getDocText(0, getLength()), "Interactions", new PageFormat()); |
| 316 | } | |
| 317 | ||
| 318 | /* Only used for testing. */ | |
| 319 | 1 | protected History getHistory() { return _history; } |
| 320 | } |
|
||||||||||