blob: 1d4ff64572b818646c1b638de964ec1d54b20755 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2007 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
*******************************************************************************/
package org.eclipse.dltk.console.ui.internal;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.dltk.console.ScriptConsoleHistory;
import org.eclipse.dltk.console.ScriptConsolePrompt;
import org.eclipse.dltk.console.ui.IConsoleStyleProvider;
import org.eclipse.dltk.console.ui.IScriptConsoleViewer;
import org.eclipse.dltk.console.ui.ScriptConsole;
import org.eclipse.dltk.console.ui.ScriptConsolePartitioner;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentListener;
import org.eclipse.jface.text.IDocumentPartitioner;
import org.eclipse.jface.text.TextUtilities;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ST;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.custom.VerifyKeyListener;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.console.TextConsoleViewer;
public class ScriptConsoleViewer extends TextConsoleViewer implements
IScriptConsoleViewer {
public static class ConsoleDocumentListener implements IDocumentListener {
private ICommandHandler handler;
private ScriptConsolePrompt prompt;
private ScriptConsoleHistory history;
private int offset;
private IDocument doc;
private List viewerList = new ArrayList();
private void addViewer(ScriptConsoleViewer viewer) {
viewerList.add(viewer);
}
protected void connectListener() {
doc.addDocumentListener(this);
}
protected void disconnectListener() {
doc.removeDocumentListener(this);
}
public void clear() {
try {
disconnectListener();
doc.set(""); //$NON-NLS-1$
appendInvitation();
for (Iterator iter = viewerList.iterator(); iter.hasNext();) {
((ScriptConsoleViewer) iter.next()).setCaretPosition(doc
.getLength());
}
connectListener();
} catch (BadLocationException e) {
e.printStackTrace();
}
}
public ConsoleDocumentListener(ICommandHandler handler,
ScriptConsolePrompt prompt, ScriptConsoleHistory history) {
this.prompt = prompt;
this.handler = handler;
this.history = history;
this.offset = 0;
this.doc = null;
}
public void setDocument(IDocument doc) {
if (this.doc != null) {
disconnectListener();
}
this.doc = doc;
if (this.doc != null) {
connectListener();
}
}
public void documentAboutToBeChanged(DocumentEvent event) {
}
protected void handleCommandLine() throws BadLocationException,
IOException {
// viewer.getTextWidget().setEditable(false);
final String command = getCommandLine();
appendDelimeter();
processResult(handler.handleCommand(command));
}
protected void processResult(final String result)
throws BadLocationException {
if (result != null) {
int start = appendText(result);
ScriptConsoleViewer viewer;
for (Iterator iter = viewerList.iterator(); iter.hasNext();) {
viewer = (ScriptConsoleViewer) iter.next();
if (viewer.styleProvider != null) {
StyleRange[] styles = viewer.styleProvider
.createInterpreterOutputStyle(result, start);
if ((styles != null) && (styles.length > 0)) {
addToPartitioner(viewer, styles);
}
}
}
history.commit();
offset = getLastLineLength();
}
appendInvitation();
}
private void addToPartitioner(ScriptConsoleViewer viewer,
StyleRange[] styles) {
IDocumentPartitioner partitioner = viewer.getDocument()
.getDocumentPartitioner();
if (partitioner instanceof ScriptConsolePartitioner) {
ScriptConsolePartitioner scriptConsolePartitioner = (ScriptConsolePartitioner) partitioner;
scriptConsolePartitioner.addRanges(styles);
viewer.getTextWidget().redraw();
}
}
protected void proccessAddition(int offset, String text) {
try {
String delim = getDelimeter();
text = doc.get(offset, doc.getLength() - offset);
doc.replace(offset, text.length(), ""); //$NON-NLS-1$
text = text.replaceAll("\r\n|\n|\r", delim); //$NON-NLS-1$
int start = 0;
int index = -1;
while ((index = text.indexOf(delim, start)) != -1) {
String cmd = text.substring(start, index);
appendText(cmd);
ScriptConsoleViewer viewer;
for (Iterator iter = viewerList.iterator(); iter.hasNext();) {
viewer = (ScriptConsoleViewer) iter.next();
if (viewer.styleProvider != null) {
StyleRange[] styles = viewer.styleProvider
.createUserInputStyle(getCommandLine(),
getCommandLineOffset());
if ((styles != null) && (styles.length > 0)) {
addToPartitioner(viewer, styles);
}
}
}
history.update(getCommandLine());
start = index + delim.length();
handleCommandLine();
}
appendText(text.substring(start, text.length()));
history.update(getCommandLine());
} catch (BadLocationException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void documentChanged(DocumentEvent event) {
disconnectListener();
proccessAddition(event.getOffset(), event.getText());
connectListener();
}
protected int appendText(String text) throws BadLocationException {
int offset = doc.getLength();
doc.replace(doc.getLength(), 0, text);
return offset;
}
protected void appendInvitation() throws BadLocationException {
int start = doc.getLength();
appendText(prompt.toString());
ScriptConsoleViewer viewer;
for (Iterator iter = viewerList.iterator(); iter.hasNext();) {
viewer = (ScriptConsoleViewer) iter.next();
viewer.setCaretPosition(doc.getLength());
viewer.revealEndOfDocument();
if (viewer.styleProvider != null) {
StyleRange[] styles = viewer.styleProvider
.createPromptStyle(prompt, start);
if ((styles != null) && (styles.length > 0)) {
addToPartitioner(viewer, styles);
}
}
}
}
protected void appendDelimeter() throws BadLocationException {
appendText(getDelimeter());
}
protected String getDelimeter() {
return TextUtilities.getDefaultLineDelimiter(doc);
}
protected int getLastLineLength() throws BadLocationException {
int lastLine = doc.getNumberOfLines() - 1;
return doc.getLineLength(lastLine);
}
public int getLastLineReadOnlySize() {
return prompt.toString().length() + offset;
}
public int getCommandLineOffset() throws BadLocationException {
int lastLine = doc.getNumberOfLines() - 1;
return doc.getLineOffset(lastLine) + getLastLineReadOnlySize();
}
public int getCommandLineLength() throws BadLocationException {
int lastLine = doc.getNumberOfLines() - 1;
return doc.getLineLength(lastLine) - getLastLineReadOnlySize();
}
public String getCommandLine() throws BadLocationException {
return doc.get(getCommandLineOffset(), getCommandLineLength());
}
public void setCommandLine(String command) throws BadLocationException {
doc
.replace(getCommandLineOffset(), getCommandLineLength(),
command);
}
}
private class ScriptCnosoleStyledText extends StyledText {
public ScriptCnosoleStyledText(Composite parent, int style) {
super(parent, style);
}
public void invokeAction(int action) {
if (isCaretOnLastLine()) {
try {
switch (action) {
case ST.LINE_UP:
history.prev();
console.getDocumentListener().setCommandLine(
history.get());
setCaretOffset(getDocument().getLength());
return;
case ST.LINE_DOWN:
history.next();
console.getDocumentListener().setCommandLine(
history.get());
setCaretOffset(getDocument().getLength());
return;
case ST.DELETE_PREVIOUS:
if (getCaretOffset() <= getCommandLineOffset()) {
return;
}
break;
case ST.DELETE_NEXT:
if (getCaretOffset() < getCommandLineOffset()) {
return;
}
break;
case ST.DELETE_WORD_PREVIOUS:
return;
}
} catch (BadLocationException e) {
e.printStackTrace();
return;
}
super.invokeAction(action);
if (isCaretOnLastLine()
&& getCaretOffset() <= getCommandLineOffset()) {
setCaretOffset(getCommandLineOffset());
}
} else {
super.invokeAction(action);
}
}
public void paste() {
if (isCaretOnLastLine()) {
super.paste();
}
}
}
private ScriptConsoleHistory history;
private ScriptConsole console;
private IConsoleStyleProvider styleProvider;
public int getCaretPosition() {
return getTextWidget().getCaretOffset();
}
public void setCaretPosition(final int offset) {
getTextWidget().getDisplay().asyncExec(new Runnable() {
public void run() {
getTextWidget().setCaretOffset(offset);
}
});
}
public int beginLineOffset() throws BadLocationException {
IDocument doc = getDocument();
int offset = getCaretPosition();
int line = doc.getLineOfOffset(offset);
return offset - doc.getLineOffset(line);
}
protected boolean isCaretOnLastLine() {
try {
IDocument doc = getDocument();
int line = doc.getLineOfOffset(getCaretPosition());
return line == doc.getNumberOfLines() - 1;
} catch (BadLocationException e) {
e.printStackTrace();
return false;
}
}
protected StyledText createTextWidget(Composite parent, int styles) {
return new ScriptCnosoleStyledText(parent, styles);
}
public ScriptConsoleViewer(Composite parent, final ScriptConsole console,
final IScriptConsoleContentHandler contentHandler,
IConsoleStyleProvider styleProvider) {
super(parent, console);
this.console = console;
this.styleProvider = styleProvider;
this.history = console.getHistory();
console.getDocumentListener().addViewer(this);
final StyledText styledText = getTextWidget();
// styledText.setEditable(false);
// Correct keyboard actions
styledText.addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) {
setCaretPosition(getDocument().getLength());
styledText.removeFocusListener(this);
}
public void focusLost(FocusEvent e) {
}
});
styledText.addVerifyKeyListener(new VerifyKeyListener() {
public void verifyKey(VerifyEvent event) {
try {
if (event.character != '\0') {
// Printable character
// ssanders: Ensure selection is on last line
ConsoleDocumentListener listener = console
.getDocumentListener();
int selStart = getSelectedRange().x;
int selEnd = (getSelectedRange().x + getSelectedRange().y);
int clOffset = listener.getCommandLineOffset();
int clLength = listener.getCommandLineLength();
if (selStart < clOffset) {
int selLength;
if (selEnd < clOffset) {
selStart = (clOffset + clLength);
selLength = 0;
} else {
selStart = clOffset;
selLength = (selEnd - selStart);
}
setSelectedRange(selStart, selLength);
}
if (beginLineOffset() < console.getDocumentListener()
.getLastLineReadOnlySize()) {
event.doit = false;
return;
}
if (event.character == SWT.CR) {
getTextWidget().setCaretOffset(
getDocument().getLength());
return;
}
if (event.keyCode == 9) {
event.doit = false;
return;
}
if (event.keyCode == 32
&& (event.stateMask & SWT.CTRL) > 0) {
event.doit = false;
return;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
styledText.addKeyListener(new KeyListener() {
public void keyPressed(KeyEvent e) {
if (e.keyCode == 9) {
contentHandler.contentAssistRequired();
}
}
public void keyReleased(KeyEvent e) {
}
});
clear();
}
// IConsoleTextViewer
public String getCommandLine() {
try {
return console.getDocumentListener().getCommandLine();
} catch (BadLocationException e) {
return null;
}
}
public int getCommandLineOffset() {
try {
return console.getDocumentListener().getCommandLineOffset();
} catch (BadLocationException e) {
return -1;
}
}
public void clear() {
console.getDocumentListener().clear();
}
public void insertText(String text) {
getTextWidget().append(text);
}
public boolean canDoOperation(int operation) {
boolean canDoOperation = super.canDoOperation(operation);
if (canDoOperation) {
switch (operation) {
case CUT:
case DELETE:
case PASTE:
case SHIFT_LEFT:
case SHIFT_RIGHT:
case PREFIX:
case STRIP_PREFIX:
canDoOperation = isCaretOnLastLine();
}
}
return canDoOperation;
}
public void setStyleProvider(IConsoleStyleProvider provider) {
this.styleProvider = provider;
}
}