Added initial support for hyperlinking.
diff --git a/com.google.eclipse.tm.terminal/META-INF/MANIFEST.MF b/com.google.eclipse.tm.terminal/META-INF/MANIFEST.MF
index 80445a7..b2cd922 100644
--- a/com.google.eclipse.tm.terminal/META-INF/MANIFEST.MF
+++ b/com.google.eclipse.tm.terminal/META-INF/MANIFEST.MF
@@ -7,7 +7,8 @@
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
 Require-Bundle: org.eclipse.core.runtime,
- org.eclipse.ui
+ org.eclipse.ui,
+ org.eclipse.jface.text
 Bundle-ActivationPolicy: lazy
 Eclipse-LazyStart: true
 Bundle-RequiredExecutionEnvironment: JavaSE-1.6
diff --git a/com.google.eclipse.tm.terminal/src/com/google/eclipse/terminal/ui/hyperlink/HttpHyperlinkFactory.java b/com.google.eclipse.tm.terminal/src/com/google/eclipse/terminal/ui/hyperlink/HttpHyperlinkFactory.java
new file mode 100644
index 0000000..0a6a04b
--- /dev/null
+++ b/com.google.eclipse.tm.terminal/src/com/google/eclipse/terminal/ui/hyperlink/HttpHyperlinkFactory.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2012 Google Inc.
+ *
+ * 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 com.google.eclipse.terminal.ui.hyperlink;
+
+import java.util.*;
+import java.util.regex.*;
+
+import org.eclipse.jface.text.*;
+import org.eclipse.jface.text.hyperlink.IHyperlink;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class HttpHyperlinkFactory implements IHyperlinkFactory {
+  private static Pattern URL_PATTERN = Pattern.compile("http(s)?:\\/{2}[\\d\\w-]+(\\.[\\d\\w-]+)*(?:(?:\\/[^\\s/]*))*(\\:[\\d]+)?"); //$NON-NLS-1$
+
+  @Override public List<IHyperlink> hyperlinksIn(int column, String text) {
+    if (text == null) {
+      return NO_HYPERLINKS;
+    }
+    List<IHyperlink> hyperlinks = new ArrayList<IHyperlink>();
+    Matcher matcher = URL_PATTERN.matcher(text);
+    int start = 0;
+    while (matcher.find(start)) {
+      String url = matcher.group().trim();
+      if (url.isEmpty()) {
+        continue;
+      }
+      IRegion region = new Region(column + matcher.start(), url.length());
+      hyperlinks.add(new UrlHyperlink(region, url));
+      start = matcher.end();
+    }
+    return hyperlinks.isEmpty() ? NO_HYPERLINKS : hyperlinks;
+  }
+}
diff --git a/com.google.eclipse.tm.terminal/src/com/google/eclipse/terminal/ui/hyperlink/IHyperlinkFactory.java b/com.google.eclipse.tm.terminal/src/com/google/eclipse/terminal/ui/hyperlink/IHyperlinkFactory.java
new file mode 100644
index 0000000..cb9688a
--- /dev/null
+++ b/com.google.eclipse.tm.terminal/src/com/google/eclipse/terminal/ui/hyperlink/IHyperlinkFactory.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2012 Google Inc.
+ *
+ * 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 com.google.eclipse.terminal.ui.hyperlink;
+
+import static java.util.Collections.emptyList;
+
+import java.util.List;
+
+import org.eclipse.jface.text.hyperlink.IHyperlink;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public interface IHyperlinkFactory {
+  List<IHyperlink> NO_HYPERLINKS = emptyList();
+
+  List<IHyperlink> hyperlinksIn(int column, String text);
+}
diff --git a/com.google.eclipse.tm.terminal/src/com/google/eclipse/terminal/ui/hyperlink/UrlHyperlink.java b/com.google.eclipse.tm.terminal/src/com/google/eclipse/terminal/ui/hyperlink/UrlHyperlink.java
new file mode 100644
index 0000000..ba63446
--- /dev/null
+++ b/com.google.eclipse.tm.terminal/src/com/google/eclipse/terminal/ui/hyperlink/UrlHyperlink.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2012 Google Inc.
+ *
+ * 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 com.google.eclipse.terminal.ui.hyperlink;
+
+import java.net.*;
+
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.hyperlink.URLHyperlink;
+import org.eclipse.tm.internal.terminal.control.impl.TerminalPlugin;
+import org.eclipse.ui.*;
+import org.eclipse.ui.browser.*;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class UrlHyperlink extends URLHyperlink {
+  public UrlHyperlink(IRegion region, String urlString) {
+    super(region, urlString);
+  }
+
+  @Override public void open() {
+    // Create the browser
+    IWorkbenchBrowserSupport support= PlatformUI.getWorkbench().getBrowserSupport();
+    IWebBrowser browser;
+    try {
+      browser= support.createBrowser(null);
+    } catch (PartInitException e) {
+      logErrorOpeningUrl(e);
+      return;
+    }
+    URL url = null;
+    try {
+      url = new URL(getURLString());
+      browser.openURL(url);
+    } catch (PartInitException e) {
+      openInExternalBrowser(url);
+    } catch (MalformedURLException e) {
+      logErrorOpeningUrl(e);
+    }
+  }
+
+  private void openInExternalBrowser(URL url) {
+    try {
+      PlatformUI.getWorkbench().getBrowserSupport().getExternalBrowser().openURL(url);
+    } catch (Exception e) {
+      logErrorOpeningUrl(e);
+    }
+  }
+
+  private void logErrorOpeningUrl(Exception e) {
+    e.printStackTrace();
+    String format = "Unable to open URL '%s'"; //$NON-NLS-1$
+    TerminalPlugin.log(String.format(format, getURLString()), e);
+  }
+}
diff --git a/com.google.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/control/impl/TerminalPlugin.java b/com.google.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/control/impl/TerminalPlugin.java
index d768582..ce5940b 100644
--- a/com.google.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/control/impl/TerminalPlugin.java
+++ b/com.google.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/control/impl/TerminalPlugin.java
@@ -17,10 +17,12 @@
  *******************************************************************************/
 package org.eclipse.tm.internal.terminal.control.impl;
 
+import static org.eclipse.core.runtime.IStatus.ERROR;
+
 import java.net.MalformedURLException;
 import java.net.URL;
 
-import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.*;
 import org.eclipse.jface.resource.ImageDescriptor;
 import org.eclipse.jface.resource.ImageRegistry;
 import org.eclipse.tm.internal.terminal.control.actions.ImageConsts;
@@ -81,4 +83,8 @@
 		ImageDescriptor imageDescriptor = ImageDescriptor.createFromURL(url);
 		imageRegistry.put(strKey, imageDescriptor);
 	}
+	
+	public static void log(String message, Exception error) {
+	  getDefault().getLog().log(new Status(ERROR, PLUGIN_ID, message, error));
+	}
 }
diff --git a/com.google.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/IVT100EmulatorBackend.java b/com.google.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/IVT100EmulatorBackend.java
index 362aa26..2944b40 100644
--- a/com.google.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/IVT100EmulatorBackend.java
+++ b/com.google.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/IVT100EmulatorBackend.java
@@ -10,6 +10,9 @@
  *******************************************************************************/
 package org.eclipse.tm.internal.terminal.emulator;
 
+import java.util.List;
+
+import org.eclipse.jface.text.hyperlink.IHyperlink;
 import org.eclipse.tm.terminal.model.Style;
 
 public interface IVT100EmulatorBackend {
@@ -169,4 +172,5 @@
 
 	int getColumns();
 
+	List<IHyperlink> hyperlinksAt(int line);
 }
\ No newline at end of file
diff --git a/com.google.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/VT100BackendTraceDecorator.java b/com.google.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/VT100BackendTraceDecorator.java
index c4d57ab..4140843 100644
--- a/com.google.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/VT100BackendTraceDecorator.java
+++ b/com.google.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/VT100BackendTraceDecorator.java
@@ -11,7 +11,9 @@
 package org.eclipse.tm.internal.terminal.emulator;
 
 import java.io.PrintStream;
+import java.util.List;
 
+import org.eclipse.jface.text.hyperlink.IHyperlink;
 import org.eclipse.tm.terminal.model.Style;
 
 public class VT100BackendTraceDecorator implements IVT100EmulatorBackend {
@@ -141,4 +143,8 @@
 		fBackend.setStyle(style);
 	}
 
+  @Override
+  public List<IHyperlink> hyperlinksAt(int line) {
+    return fBackend.hyperlinksAt(line);
+  }
 }
diff --git a/com.google.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/VT100Emulator.java b/com.google.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/VT100Emulator.java
index 65ef50c..c82c6b0 100644
--- a/com.google.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/VT100Emulator.java
+++ b/com.google.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/VT100Emulator.java
@@ -20,18 +20,14 @@
  *******************************************************************************/
 package org.eclipse.tm.internal.terminal.emulator;
 
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.Reader;
+import java.io.*;
+import java.util.List;
 
-import org.eclipse.swt.events.ControlEvent;
-import org.eclipse.swt.events.ControlListener;
-import org.eclipse.tm.internal.terminal.control.impl.ITerminalControlForText;
-import org.eclipse.tm.internal.terminal.control.impl.TerminalPlugin;
-import org.eclipse.tm.internal.terminal.provisional.api.ITerminalConnector;
-import org.eclipse.tm.internal.terminal.provisional.api.Logger;
-import org.eclipse.tm.terminal.model.ITerminalTextData;
-import org.eclipse.tm.terminal.model.Style;
+import org.eclipse.jface.text.hyperlink.IHyperlink;
+import org.eclipse.swt.events.*;
+import org.eclipse.tm.internal.terminal.control.impl.*;
+import org.eclipse.tm.internal.terminal.provisional.api.*;
+import org.eclipse.tm.terminal.model.*;
 
 /**
  * This class processes character data received from the remote host and
@@ -133,10 +129,11 @@
 			ansiParameters[i] = new StringBuffer();
 		}
 		setInputStreamReader(reader);
-		if(TerminalPlugin.isOptionEnabled("org.eclipse.tm.terminal/debug/log/VT100Backend")) //$NON-NLS-1$
-			text=new VT100BackendTraceDecorator(new VT100EmulatorBackend(data),System.out);
-		else
-			text=new VT100EmulatorBackend(data);
+		if(TerminalPlugin.isOptionEnabled("org.eclipse.tm.terminal/debug/log/VT100Backend")) {
+      text=new VT100BackendTraceDecorator(new VT100EmulatorBackend(data),System.out);
+    } else {
+      text=new VT100EmulatorBackend(data);
+    }
 
 //		text.setDimensions(24, 80);
 		Style  style=Style.getStyle("BLACK", "WHITE"); //$NON-NLS-1$ //$NON-NLS-2$
@@ -182,7 +179,8 @@
 	 * This method is required by interface ControlListener. It allows us to
 	 * know when the StyledText widget is moved.
 	 */
-	public void controlMoved(ControlEvent event) {
+	@Override
+  public void controlMoved(ControlEvent event) {
 		Logger.log("entered"); //$NON-NLS-1$
 		// Empty.
 	}
@@ -191,7 +189,8 @@
 	 * This method is required by interface ControlListener. It allows us to
 	 * know when the StyledText widget is resized.
 	 */
-	public void controlResized(ControlEvent event) {
+	@Override
+  public void controlResized(ControlEvent event) {
 		Logger.log("entered"); //$NON-NLS-1$
 		adjustTerminalDimensions();
 	}
@@ -212,8 +211,9 @@
 	public void fontChanged() {
 		Logger.log("entered"); //$NON-NLS-1$
 
-		if (text != null)
-			adjustTerminalDimensions();
+		if (text != null) {
+      adjustTerminalDimensions();
+    }
 	}
 //	/**
 //	 * This method executes in the Display thread to process data received from
@@ -289,7 +289,9 @@
 				case '\n':
 					processNewline(); // Newline (Control-J)
 					if(fCrAfterNewLine)
-						processCarriageReturn(); // Carriage Return (Control-M)
+           {
+            processCarriageReturn(); // Carriage Return (Control-M)
+          }
 					break;
 
 				case '\r':
@@ -607,8 +609,9 @@
 	private void processAnsiCommand_G() {
 		int targetColumn = 1;
 
-		if (ansiParameters[0].length() > 0)
-			targetColumn = getAnsiParameter(0) - 1;
+		if (ansiParameters[0].length() > 0) {
+      targetColumn = getAnsiParameter(0) - 1;
+    }
 
 		moveCursor(relativeCursorLine(), targetColumn);
 	}
@@ -628,10 +631,11 @@
 	private void processAnsiCommand_J() {
 		int ansiParameter;
 
-		if (ansiParameters[0].length() == 0)
-			ansiParameter = 0;
-		else
-			ansiParameter = getAnsiParameter(0);
+		if (ansiParameters[0].length() == 0) {
+      ansiParameter = 0;
+    } else {
+      ansiParameter = getAnsiParameter(0);
+    }
 
 		switch (ansiParameter) {
 		case 0:
@@ -848,8 +852,9 @@
 		// Do nothing if the numeric parameter was not 6 (which means report cursor
 		// position).
 
-		if (getAnsiParameter(0) != 6)
-			return;
+		if (getAnsiParameter(0) != 6) {
+      return;
+    }
 
 		// Send the ANSI cursor position (which is 1-based) to the remote endpoint.
 
@@ -890,8 +895,9 @@
 
 		String parameter = ansiParameters[parameterIndex].toString();
 
-		if (parameter.length() == 0)
-			return 1;
+		if (parameter.length() == 0) {
+      return 1;
+    }
 
 		int parameterValue = 1;
 
@@ -918,8 +924,9 @@
 		if (ch == ';') {
 			++nextAnsiParameter;
 		} else {
-			if (nextAnsiParameter < ansiParameters.length)
-				ansiParameters[nextAnsiParameter].append(ch);
+			if (nextAnsiParameter < ansiParameters.length) {
+        ansiParameters[nextAnsiParameter].append(ch);
+      }
 		}
 	}
 	/**
@@ -1061,8 +1068,9 @@
 	}
 
 	private ITerminalConnector getConnector() {
-		if(terminal.getTerminalConnector()!=null)
-			return terminal.getTerminalConnector();
+		if(terminal.getTerminalConnector()!=null) {
+      return terminal.getTerminalConnector();
+    }
 		return null;
 	}
 
@@ -1150,14 +1158,16 @@
 			c = fReader.read();
 		}
 		// TODO: better end of file handling
-		if(c==-1)
-			c=0;
+		if(c==-1) {
+      c=0;
+    }
 		return (char)c;
 	}
 
 	private boolean hasNextChar() throws IOException  {
-		if(fNextChar>=0)
-			return true;
+		if(fNextChar>=0) {
+      return true;
+    }
 		return fReader.ready();
 	}
 
@@ -1180,4 +1190,8 @@
 	public void setCrAfterNewLine(boolean crAfterNewLine) {
 		fCrAfterNewLine = crAfterNewLine;
 	}
+
+  public List<IHyperlink> hyperlinksAt(int line) {
+    return text.hyperlinksAt(line);
+  }
 }
diff --git a/com.google.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/VT100EmulatorBackend.java b/com.google.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/VT100EmulatorBackend.java
index 3941862..a31ab2a 100644
--- a/com.google.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/VT100EmulatorBackend.java
+++ b/com.google.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/VT100EmulatorBackend.java
@@ -1,18 +1,25 @@
 /*******************************************************************************
  * Copyright (c) 2007, 2011 Wind River Systems, Inc. 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 
- * 
- * Contributors: 
+ * 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
+ *
+ * Contributors:
  * Michael Scharf (Wind River) - initial API and implementation
  * Anton Leherbauer (Wind River) - [206329] Changing terminal size right after connect does not scroll properly
  *******************************************************************************/
 package org.eclipse.tm.internal.terminal.emulator;
 
-import org.eclipse.tm.terminal.model.ITerminalTextData;
-import org.eclipse.tm.terminal.model.Style;
+import static java.util.Collections.emptyList;
+
+import java.util.*;
+
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.hyperlink.IHyperlink;
+import org.eclipse.tm.terminal.model.*;
+
+import com.google.eclipse.terminal.ui.hyperlink.*;
 
 /**
  *
@@ -26,7 +33,7 @@
 	 * {@link #widthInColumns} - 1. We track the cursor column using this field
 	 * to avoid having to recompute it repeatly using StyledText method calls.
 	 * <p>
-	 * 
+	 *
 	 * The StyledText widget that displays text has a vertical bar (called the
 	 * "caret") that appears _between_ character cells, but ANSI terminals have
 	 * the concept of a cursor that appears _in_ a character cell, so we need a
@@ -35,7 +42,7 @@
 	 * class is that the cursor is logically in column N when the caret is
 	 * physically positioned immediately to the _left_ of column N.
 	 * <p>
-	 * 
+	 *
 	 * When fCursorColumn is N, the next character output to the terminal appears
 	 * in column N. When a character is output to the rightmost column on a
 	 * given line (column widthInColumns - 1), the cursor moves to column 0 on
@@ -52,14 +59,18 @@
 	int fLines;
 	int fColumns;
 	final private ITerminalTextData fTerminal;
+
+	private final IHyperlinkFactory urlHyperlinkFactory = new HttpHyperlinkFactory();
+	private final Map<Integer, List<IHyperlink>> hyperlinks = new HashMap<Integer, List<IHyperlink>>();
+
 	public VT100EmulatorBackend(ITerminalTextData terminal) {
 		fTerminal=terminal;
 	}
-	
+
 	/* (non-Javadoc)
 	 * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#clearAll()
 	 */
-	public void clearAll() {
+  public void clearAll() {
 		synchronized (fTerminal) {
 			// clear the history
 			int n=fTerminal.getHeight();
@@ -74,10 +85,12 @@
 	/* (non-Javadoc)
 	 * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#setDimensions(int, int)
 	 */
-	public void setDimensions(int lines, int cols) {
+  public void setDimensions(int lines, int cols) {
 		synchronized (fTerminal) {
 			if(lines==fLines && cols==fColumns)
-				return; // nothing to do
+       {
+        return; // nothing to do
+      }
 			// relative cursor line
 			int cl=getCursorLine();
 			int cc=getCursorColumn();
@@ -102,7 +115,7 @@
 			setCursor(cl, cc);
 		}
 	}
-	
+
 	int toAbsoluteLine(int line) {
 		synchronized (fTerminal) {
 			return fTerminal.getHeight()-fLines+line;
@@ -111,7 +124,7 @@
 	/* (non-Javadoc)
 	 * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#insertCharacters(int)
 	 */
-	public void insertCharacters(int charactersToInsert) {
+  public void insertCharacters(int charactersToInsert) {
 		synchronized (fTerminal) {
 			int line=toAbsoluteLine(fCursorLine);
 			int n=charactersToInsert;
@@ -130,19 +143,19 @@
 	/* (non-Javadoc)
 	 * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#eraseToEndOfScreen()
 	 */
-	public void eraseToEndOfScreen() {
+  public void eraseToEndOfScreen() {
 		synchronized (fTerminal) {
 			eraseLineToEnd();
 			for (int line = toAbsoluteLine(fCursorLine+1); line < toAbsoluteLine(fLines); line++) {
 				fTerminal.cleanLine(line);
 			}
 		}
-		
+
 	}
 	/* (non-Javadoc)
 	 * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#eraseToCursor()
 	 */
-	public void eraseToCursor() {
+  public void eraseToCursor() {
 		synchronized (fTerminal) {
 			for (int line = toAbsoluteLine(0); line < toAbsoluteLine(fCursorLine); line++) {
 				fTerminal.cleanLine(line);
@@ -153,7 +166,7 @@
 	/* (non-Javadoc)
 	 * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#eraseAll()
 	 */
-	public void eraseAll() {
+  public void eraseAll() {
 		synchronized (fTerminal) {
 			for (int line = toAbsoluteLine(0); line < toAbsoluteLine(fLines); line++) {
 				fTerminal.cleanLine(line);
@@ -163,7 +176,7 @@
 	/* (non-Javadoc)
 	 * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#eraseLine()
 	 */
-	public void eraseLine() {
+  public void eraseLine() {
 		synchronized (fTerminal) {
 			fTerminal.cleanLine(toAbsoluteLine(fCursorLine));
 		}
@@ -171,33 +184,36 @@
 	/* (non-Javadoc)
 	 * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#eraseLineToEnd()
 	 */
-	public void eraseLineToEnd() {
+  public void eraseLineToEnd() {
 		synchronized (fTerminal) {
 			int line=toAbsoluteLine(fCursorLine);
 			for (int col = fCursorColumn; col < fColumns; col++) {
 				fTerminal.setChar(line, col, '\000', null);
 			}
 		}
-	}	
+	}
 	/* (non-Javadoc)
 	 * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#eraseLineToCursor()
 	 */
-	public void eraseLineToCursor() {
+	@Override
+  public void eraseLineToCursor() {
 		synchronized (fTerminal) {
 			int line=toAbsoluteLine(fCursorLine);
 			for (int col = 0; col <= fCursorColumn; col++) {
 				fTerminal.setChar(line, col, '\000', null);
 			}
 		}
-	}	
+	}
 
 	/* (non-Javadoc)
 	 * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#insertLines(int)
 	 */
-	public void insertLines(int n) {
+	@Override
+  public void insertLines(int n) {
 		synchronized (fTerminal) {
-			if(!isCusorInScrollingRegion())
-				return;
+			if(!isCusorInScrollingRegion()) {
+        return;
+      }
 			assert n>0;
 			int line=toAbsoluteLine(fCursorLine);
 			int nLines=fTerminal.getHeight()-line;
@@ -207,7 +223,7 @@
 	/* (non-Javadoc)
 	 * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#deleteCharacters(int)
 	 */
-	public void deleteCharacters(int n) {
+  public void deleteCharacters(int n) {
 		synchronized (fTerminal) {
 			int line=toAbsoluteLine(fCursorLine);
 			for (int col = fCursorColumn+n; col < fColumns; col++) {
@@ -224,10 +240,12 @@
 	/* (non-Javadoc)
 	 * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#deleteLines(int)
 	 */
-	public void deleteLines(int n) {
+	@Override
+  public void deleteLines(int n) {
 		synchronized (fTerminal) {
-			if(!isCusorInScrollingRegion())
-				return;
+			if(!isCusorInScrollingRegion()) {
+        return;
+      }
 			assert n>0;
 			int line=toAbsoluteLine(fCursorLine);
 			int nLines=fTerminal.getHeight()-line;
@@ -242,7 +260,7 @@
 	/* (non-Javadoc)
 	 * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#getDefaultStyle()
 	 */
-	public Style getDefaultStyle() {
+  public Style getDefaultStyle() {
 		synchronized (fTerminal) {
 			return fDefaultStyle;
 		}
@@ -251,7 +269,7 @@
 	/* (non-Javadoc)
 	 * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#setDefaultStyle(org.eclipse.tm.terminal.model.Style)
 	 */
-	public void setDefaultStyle(Style defaultStyle) {
+  public void setDefaultStyle(Style defaultStyle) {
 		synchronized (fTerminal) {
 			fDefaultStyle = defaultStyle;
 		}
@@ -260,17 +278,18 @@
 	/* (non-Javadoc)
 	 * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#getStyle()
 	 */
-	public Style getStyle() {
+  public Style getStyle() {
 		synchronized (fTerminal) {
-			if(fStyle==null)
-				return fDefaultStyle;
+			if(fStyle==null) {
+        return fDefaultStyle;
+      }
 			return fStyle;
 		}
 	}
 	/* (non-Javadoc)
 	 * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#setStyle(org.eclipse.tm.terminal.model.Style)
 	 */
-	public void setStyle(Style style) {
+  public void setStyle(Style style) {
 		synchronized (fTerminal) {
 			fStyle=style;
 		}
@@ -278,10 +297,16 @@
 	/* (non-Javadoc)
 	 * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#appendString(java.lang.String)
 	 */
-	public void appendString(String buffer) {
+  public void appendString(String buffer) {
 		synchronized (fTerminal) {
 			char[] chars=buffer.toCharArray();
 			int line=toAbsoluteLine(fCursorLine);
+			int originalLine = line;
+			List<IHyperlink> found = emptyList();
+			if (buffer != null) {
+			  found = urlHyperlinkFactory.hyperlinksIn(fCursorColumn, buffer);
+		    hyperlinks.put(new Integer(line), found);
+      }
 			int i=0;
 			while (i < chars.length) {
 				int n=Math.min(fColumns-fCursorColumn,chars.length-i);
@@ -297,9 +322,25 @@
 					setCursorColumn(col);
 				}
 			}
+			drawHyperlinks(found, originalLine);
 		}
 	}
 
+	private void drawHyperlinks(List<IHyperlink> hyperlinks, int line) {
+    for (IHyperlink hyperlink : hyperlinks) {
+      IRegion region = hyperlink.getHyperlinkRegion();
+      int start = region.getOffset();
+      int end = start + region.getLength();
+      for (int column = start; column < end; column++) {
+        Style style = fTerminal.getStyle(line, column);
+        if (style != null) {
+          style = style.setUnderline(true);
+          fTerminal.setChar(line, column, fTerminal.getChar(line, column), style);
+        }
+      }
+    }
+	}
+
 	/**
 	 * MUST be called from a synchronized block!
 	 */
@@ -307,8 +348,9 @@
 		if(fCursorLine+1>=fLines) {
 			int h=fTerminal.getHeight();
 			fTerminal.addLine();
-			if(h!=fTerminal.getHeight())
-				setCursorLine(fCursorLine+1);
+			if(h!=fTerminal.getHeight()) {
+        setCursorLine(fCursorLine+1);
+      }
 		} else {
 			setCursorLine(fCursorLine+1);
 		}
@@ -316,7 +358,7 @@
 	/* (non-Javadoc)
 	 * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#processNewline()
 	 */
-	public void processNewline() {
+  public void processNewline() {
 		synchronized (fTerminal) {
 			doNewline();
 		}
@@ -324,7 +366,7 @@
 	/* (non-Javadoc)
 	 * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#getCursorLine()
 	 */
-	public int getCursorLine() {
+  public int getCursorLine() {
 		synchronized (fTerminal) {
 			return fCursorLine;
 		}
@@ -332,7 +374,7 @@
 	/* (non-Javadoc)
 	 * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#getCursorColumn()
 	 */
-	public int getCursorColumn() {
+  public int getCursorColumn() {
 		synchronized (fTerminal) {
 			return fCursorColumn;
 		}
@@ -340,7 +382,7 @@
 	/* (non-Javadoc)
 	 * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#setCursor(int, int)
 	 */
-	public void setCursor(int targetLine, int targetColumn) {
+  public void setCursor(int targetLine, int targetColumn) {
 		synchronized (fTerminal) {
 			setCursorLine(targetLine);
 			setCursorColumn(targetColumn);
@@ -350,12 +392,13 @@
 	/* (non-Javadoc)
 	 * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#setCursorColumn(int)
 	 */
-	public void setCursorColumn(int targetColumn) {
+  public void setCursorColumn(int targetColumn) {
 		synchronized (fTerminal) {
-			if(targetColumn<0)
-				targetColumn=0;
-			else if(targetColumn>=fColumns)
-				targetColumn=fColumns-1;
+			if(targetColumn<0) {
+        targetColumn=0;
+      } else if(targetColumn>=fColumns) {
+        targetColumn=fColumns-1;
+      }
 			fCursorColumn=targetColumn;
 			// We make the assumption that nobody is changing the
 			// terminal cursor except this class!
@@ -367,12 +410,13 @@
 	/* (non-Javadoc)
 	 * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#setCursorLine(int)
 	 */
-	public void setCursorLine(int targetLine) {
+  public void setCursorLine(int targetLine) {
 		synchronized (fTerminal) {
-			if(targetLine<0)
-				targetLine=0;
-			else if(targetLine>=fLines)
-				targetLine=fLines-1;
+			if(targetLine<0) {
+        targetLine=0;
+      } else if(targetLine>=fLines) {
+        targetLine=fLines-1;
+      }
 			fCursorLine=targetLine;
 			// We make the assumption that nobody is changing the
 			// terminal cursor except this class!
@@ -384,7 +428,7 @@
 	/* (non-Javadoc)
 	 * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#getLines()
 	 */
-	public int getLines() {
+  public int getLines() {
 		synchronized (fTerminal) {
 			return fLines;
 		}
@@ -393,9 +437,17 @@
 	/* (non-Javadoc)
 	 * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#getColumns()
 	 */
-	public int getColumns() {
+  public int getColumns() {
 		synchronized (fTerminal) {
 			return fColumns;
 		}
 	}
+  
+  public List<IHyperlink> hyperlinksAt(int line) {
+    List<IHyperlink> found = hyperlinks.get(new Integer(line));
+    if (found == null) {
+      return emptyList();
+    }
+    return found;
+  }
 }
diff --git a/com.google.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/VT100TerminalControl.java b/com.google.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/VT100TerminalControl.java
index a69e07a..b8a70ca 100644
--- a/com.google.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/VT100TerminalControl.java
+++ b/com.google.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/VT100TerminalControl.java
@@ -35,10 +35,13 @@
 
 import java.io.*;
 import java.net.SocketException;
+import java.util.List;
 
 import org.eclipse.core.runtime.*;
 import org.eclipse.core.runtime.jobs.Job;
 import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.hyperlink.IHyperlink;
 import org.eclipse.osgi.util.NLS;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.dnd.*;
@@ -572,7 +575,24 @@
 		snapshot.updateSnapshot(false);
 		ITextCanvasModel canvasModel=new PollingTextCanvasModel(snapshot);
 		fCtlText=new TextCanvas(fWndParent,canvasModel,SWT.NONE,new TextLineRenderer(fCtlText,canvasModel));
-
+		fCtlText.addMouseListener(new MouseAdapter() {
+      @Override
+      public void mouseUp(MouseEvent e) {
+        Point p = fCtlText.screenPointToCell(e.x, e.y);
+        if (p == null) {
+          return;
+        }
+        List<IHyperlink> hyperlinks = fTerminalText.hyperlinksAt(p.y);
+        for (IHyperlink hyperlink : hyperlinks) {
+          IRegion region = hyperlink.getHyperlinkRegion();
+          int start = region.getOffset();
+          int end = start + region.getLength() - 1;
+          if (p.x >= start && p.x <= end) {
+            hyperlink.open();
+          }
+        }
+      }
+    });
 
 		fCtlText.setLayoutData(new GridData(GridData.FILL_BOTH));
 		fCtlText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
diff --git a/com.google.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/textcanvas/TextCanvas.java b/com.google.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/textcanvas/TextCanvas.java
index 181604c..7b60217 100644
--- a/com.google.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/textcanvas/TextCanvas.java
+++ b/com.google.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/textcanvas/TextCanvas.java
@@ -429,5 +429,9 @@
     fCellRenderer.setFont(font);
     redraw();
   }
+
+  @Override public Point screenPointToCell(int x, int y) {
+    return super.screenPointToCell(x, y);
+  }
 }