/** This method should be called after all the lines received were processed. */ private void onAfterAllLinesHandled( final String finalText, final boolean finalAddedParen, final int finalStart, final int finalOffset, final boolean finalAddedCloseParen, final String finalIndentString, final int finalNewDeltaCaretPosition) { boolean shiftsCaret = true; String newText = finalText.substring(finalStart, finalText.length()); if (finalAddedParen) { String cmdLine = getCommandLine(); Document parenDoc = new Document(cmdLine + newText); int currentOffset = cmdLine.length() + 1; DocCmd docCmd = new DocCmd(currentOffset, 0, "("); docCmd.shiftsCaret = true; try { strategy.customizeParenthesis(parenDoc, docCmd); } catch (BadLocationException e) { Log.log(e); } newText = docCmd.text + newText.substring(1); if (!docCmd.shiftsCaret) { shiftsCaret = false; setCaretOffset(finalOffset + (docCmd.caretOffset - currentOffset)); } } else if (finalAddedCloseParen) { String cmdLine = getCommandLine(); String existingDoc = cmdLine + finalText.substring(1); int cmdLineOffset = cmdLine.length(); if (existingDoc.length() > cmdLineOffset) { Document parenDoc = new Document(existingDoc); DocCmd docCmd = new DocCmd(cmdLineOffset, 0, ")"); docCmd.shiftsCaret = true; boolean canSkipOpenParenthesis; try { canSkipOpenParenthesis = strategy.canSkipCloseParenthesis(parenDoc, docCmd); } catch (BadLocationException e) { canSkipOpenParenthesis = false; Log.log(e); } if (canSkipOpenParenthesis) { shiftsCaret = false; setCaretOffset(finalOffset + 1); newText = newText.substring(1); } } } // and now add the last line (without actually handling it). String cmd = finalIndentString + newText; cmd = convertTabs(cmd); applyStyleToUserAddedText(cmd, doc.getLength()); appendText(cmd); if (shiftsCaret) { setCaretOffset(doc.getLength() - finalNewDeltaCaretPosition); } history.update(getCommandLine()); }
/** * Here is where we run things not using the UI thread. It's a recursive function. In summary, * it'll run each line in the commands received in a new thread, and as each finishes, it calls * itself again for the next command. The last command will reconnect to the document. * * <p>Exceptions had to be locally handled, because they're not well tolerated under this scenario * (if on of the callbacks fail, the others won't be executed and we'd get into a situation where * the shell becomes unusable). */ private void execCommand( final boolean addedNewLine, final String delim, final String[] finalIndentString, final String cmd, final List<String> commands, final int currentCommand, final String text, final boolean addedParen, final int start, final boolean addedCloseParen, final int newDeltaCaretPosition) { applyStyleToUserAddedText(cmd, doc.getLength()); // the cmd could be something as '\n' appendText(cmd); // and the command line the actual contents to be executed at this time final String commandLine = getCommandLine(); history.update(commandLine); // handle the command line: // When the user presses a return and goes to a new line, the contents of the current line are // sent to // the interpreter (and its results properly handled). appendText(getDelimeter()); final boolean finalAddedNewLine = addedNewLine; final String finalDelim = delim; final ICallback<Object, InterpreterResponse> onResponseReceived = new ICallback<Object, InterpreterResponse>() { public Object call(final InterpreterResponse arg) { // When we receive the response, we must handle it in the UI thread. Runnable runnable = new Runnable() { public void run() { try { processResult(arg); if (finalAddedNewLine) { IDocument historyDoc = history.getAsDoc(); int currHistoryLen = historyDoc.getLength(); if (currHistoryLen > 0) { DocCmd docCmd = new DocCmd(currHistoryLen - 1, 0, finalDelim); strategy.customizeNewLine(historyDoc, docCmd); finalIndentString[0] = docCmd.text.replaceAll( "\\r\\n|\\n|\\r", ""); // remove any new line added! if (currHistoryLen != historyDoc.getLength()) { Log.log( "Error: the document passed to the customizeNewLine should not be changed!"); } } } } catch (Throwable e) { // Yeap, it can never fail! Log.log(e); } if (currentCommand + 1 < commands.size()) { execCommand( finalAddedNewLine, finalDelim, finalIndentString, commands.get(currentCommand + 1), commands, currentCommand + 1, text, addedParen, start, addedCloseParen, newDeltaCaretPosition); } else { // last one try { onAfterAllLinesHandled( text, addedParen, start, offset, addedCloseParen, finalIndentString[0], newDeltaCaretPosition); } finally { // We must disconnect stopDisconnected(); // reconnect with the document } } } }; RunInUiThread.async(runnable); return null; } }; final ICallback<Object, Tuple<String, String>> onContentsReceived = new ICallback<Object, Tuple<String, String>>() { public Object call(final Tuple<String, String> result) { Runnable runnable = new Runnable() { public void run() { if (result != null) { addToConsoleView(result.o1, true); addToConsoleView(result.o2, false); revealEndOfDocument(); } } }; RunInUiThread.async(runnable); return null; } }; // Handle the command in a thread that doesn't block the U/I. new Thread() { public void run() { handler.handleCommand(commandLine, onResponseReceived, onContentsReceived); } }.start(); }