|
|||||||||||||||||||
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 | } |
|