changeset 16632:ace0f60672ec

Merge in Adam's changes
author Jordi Gutiérrez Hermoso <jordigh@octave.org>
date Wed, 08 May 2013 14:57:45 -0400
parents c979e6db619b (current diff) cbaf19edc4ee (diff)
children 8d32a887754a
files
diffstat 39 files changed, 1358 insertions(+), 378 deletions(-) [+]
line wrap: on
line diff
--- a/libgui/qterminal/libqterminal/QTerminal.cc	Wed May 08 14:57:33 2013 -0400
+++ b/libgui/qterminal/libqterminal/QTerminal.cc	Wed May 08 14:57:45 2013 -0400
@@ -41,4 +41,33 @@
     setCursorType(QTerminalInterface::BlockCursor, cursorBlinking);
   else if (cursorType == "underline")
     setCursorType(QTerminalInterface::UnderlineCursor, cursorBlinking);
+
+  bool cursorUseForegroundColor
+    = settings->value ("terminal/cursorUseForegroundColor",true).toBool ();
+
+  // FIXME -- we shouldn't duplicate this information here and in the
+  // resource manager.
+  QList<QColor> default_colors;
+
+  default_colors << QColor(0,0,0)
+                 << QColor(255,255,255)
+                 << QColor(192,192,192)
+                 << QColor(128,128,128);
+
+  setForegroundColor
+    (settings->value ("terminal/color_f",
+                      QVariant (default_colors.at (0))).value<QColor> ());
+
+  setBackgroundColor
+    (settings->value ("terminal/color_b",
+                      QVariant (default_colors.at (1))).value<QColor> ());
+
+  setSelectionColor
+    (settings->value ("terminal/color_s",
+                      QVariant (default_colors.at (2))).value<QColor> ());
+
+  setCursorColor
+    (cursorUseForegroundColor,
+     settings->value ("terminal/color_c",
+                      QVariant (default_colors.at (3))).value<QColor> ());
 }
--- a/libgui/qterminal/libqterminal/QTerminalInterface.h	Wed May 08 14:57:33 2013 -0400
+++ b/libgui/qterminal/libqterminal/QTerminalInterface.h	Wed May 08 14:57:45 2013 -0400
@@ -24,6 +24,7 @@
 #define QTERMINALINTERFACE_H
 
 #include <QWidget>
+#include <QColor>
 #include <QMenu>
 
 class QTerminalInterface : public QWidget
@@ -61,7 +62,13 @@
         Q_UNUSED(blinking);
     }
 
-public slots:
+    virtual void setBackgroundColor (const QColor& color) = 0;
+    virtual void setForegroundColor (const QColor& color) = 0;
+    virtual void setSelectionColor (const QColor& color) = 0;
+    virtual void setCursorColor (bool useForegroundColor,
+                                 const QColor& color) = 0;
+
+ public slots:
     virtual void copyClipboard() = 0;
     virtual void pasteClipboard() = 0;
 
--- a/libgui/qterminal/libqterminal/unix/QUnixTerminalImpl.cpp	Wed May 08 14:57:33 2013 -0400
+++ b/libgui/qterminal/libqterminal/unix/QUnixTerminalImpl.cpp	Wed May 08 14:57:45 2013 -0400
@@ -135,6 +135,18 @@
     m_terminalView->setBlinkingCursor(blinking);
 }
 
+// FIXME -- not sure how to make these work properly given the way the
+// Unix terminal handles colors.
+void QUnixTerminalImpl::setBackgroundColor (const QColor& color) { }
+void QUnixTerminalImpl::setForegroundColor (const QColor& color) { }
+void QUnixTerminalImpl::setSelectionColor (const QColor& color) { }
+
+void QUnixTerminalImpl::setCursorColor (bool useForegroundColor,
+                                        const QColor& color)
+{
+  m_terminalView->setKeyboardCursorColor (useForegroundColor, color);
+}
+
 void QUnixTerminalImpl::showEvent(QShowEvent *)
 {
     m_terminalView->updateImage();
--- a/libgui/qterminal/libqterminal/unix/QUnixTerminalImpl.h	Wed May 08 14:57:33 2013 -0400
+++ b/libgui/qterminal/libqterminal/unix/QUnixTerminalImpl.h	Wed May 08 14:57:45 2013 -0400
@@ -43,6 +43,11 @@
 
     void setCursorType(CursorType type, bool blinking);
 
+    void setBackgroundColor (const QColor& color);
+    void setForegroundColor (const QColor& color);
+    void setSelectionColor (const QColor& color);
+    void setCursorColor (bool useForegroundColor, const QColor& color);
+
 public slots:
     void copyClipboard();
     void pasteClipboard();
--- a/libgui/qterminal/libqterminal/win32/QWinTerminalImpl.cpp	Wed May 08 14:57:33 2013 -0400
+++ b/libgui/qterminal/libqterminal/win32/QWinTerminalImpl.cpp	Wed May 08 14:57:45 2013 -0400
@@ -20,6 +20,7 @@
 */
 
 #include <QApplication>
+#include <QClipboard>
 #include <QColor>
 #include <QFont>
 #include <QHBoxLayout>
@@ -30,6 +31,9 @@
 #include <QtDebug>
 #include <QThread>
 #include <QTimer>
+#include <QToolTip>
+#include <QCursor>
+#include <QMessageBox>
 
 #include <fcntl.h>
 #include <io.h>
@@ -39,6 +43,7 @@
 #define _WIN32_WINNT 0x0500 
 #include <windows.h>
 #include <cstring>
+#include <limits>
 
 #include "QWinTerminalImpl.h"
 #include "QTerminalColors.h"
@@ -119,13 +124,37 @@
   void setupStandardIO (DWORD stdHandleId, int fd, const char* name,
                         const char* devName);
 
+  QPoint posToCell (const QPoint& pt);
+  QString getSelection (void);
+  void updateSelection (void);
+  void clearSelection (void);
+
+  QColor backgroundColor (void) const;
+  QColor foregroundColor (void) const;
+  QColor selectionColor (void) const;
+  QColor cursorColor (void) const;
+
+  void setBackgroundColor (const QColor& color);
+  void setForegroundColor (const QColor& color);
+  void setSelectionColor (const QColor& color);
+  void setCursorColor (bool useForegroundColor, const QColor& color);
+
+  void drawTextBackground (QPainter& p, int cx1, int cy1, int cx2, int cy2,
+                           int cw, int ch);
+
+  void drawSelection (QPainter& p, int cx1, int cy1, int cx2, int cy2,
+                      int cw, int ch);
+
+  void drawCursor (QPainter& p);
+
+  void drawText (QPainter& p, int cx1, int cy1, int cx2, int cy2,
+                 int cw, int ch);
+
 private:
   QWinTerminalImpl* q;
 
 private:
   QFont m_font;
-  QColor m_backgroundColor;
-  QColor m_foregroundColor;
   QString m_command;
   QConsoleColors m_colors;
   bool m_inWheelEvent;
@@ -140,6 +169,12 @@
   QTimer *m_blinkCursorTimer;
   KeyboardCursorType m_cursorType;
 
+  QPoint m_beginSelection;
+  QPoint m_endSelection;
+
+  QColor m_selectionColor;
+  QColor m_cursorColor;
+
   HANDLE m_stdOut;
   HWND m_consoleWindow;
   CHAR_INFO* m_buffer;
@@ -155,11 +190,19 @@
   static const int BLINK_DELAY = 500;
 };
 
+static void maybeSwapPoints (QPoint& begin, QPoint& end)
+{
+  if (end.y () < begin.y ()
+      || (end.y () == begin.y () && end.x () < begin.x ()))
+    qSwap (begin, end);
+}
+
 //////////////////////////////////////////////////////////////////////////////
 
 QConsolePrivate::QConsolePrivate (QWinTerminalImpl* parent, const QString& cmd)
   : q (parent), m_command (cmd), m_hasBlinkingCursor (true),
-    m_cursorType (BlockCursor), m_process (NULL), m_inWheelEvent (false)
+    m_cursorType (BlockCursor), m_beginSelection (0, 0),
+    m_endSelection (0, 0), m_process (NULL), m_inWheelEvent (false)
 {
   log (NULL);
 
@@ -242,10 +285,6 @@
   GetConsoleTitleW (titleBuf, sizeof (titleBuf));
   q->setWindowTitle (QString::fromWCharArray (titleBuf));
 
-  m_backgroundColor = Qt::white;
-  m_foregroundColor = Qt::black;
-  SetConsoleTextAttribute (m_stdOut, 0xF0);
-
   m_font.setFamily ("Lucida Console");
   m_font.setPointSize (9);
   m_font.setStyleHint (QFont::TypeWriter);
@@ -261,8 +300,26 @@
   l->addWidget (m_consoleView, 1);
   l->addWidget (m_scrollBar, 0);
 
-  m_consoleView->setPalette (QPalette (m_backgroundColor));
+  // Choose 15 (0xF) as index into the Windows console color map for the
+  // background and 0 (0x0) as the index for the foreground.  This
+  // selection corresponds to the indices used in the foregroundColor,
+  // setForegroundColor, backgroundColor, and SetBackgroundColor
+  // functions.
+
+  SetConsoleTextAttribute (m_stdOut, 0xF0);
+
+  // Defaults.
+  setBackgroundColor (Qt::white);
+  setForegroundColor (Qt::black);
+  setSelectionColor (Qt::lightGray);
+  setCursorColor (false, Qt::darkGray);
+
+  // FIXME -- should we set the palette?
+  QPalette palette (backgroundColor ());
+  m_consoleView->setPalette (palette);
+
   m_consoleView->setAutoFillBackground (true);
+
   m_consoleView->setFont (m_font);
   parent->setFocusPolicy (Qt::StrongFocus);
   parent->winId ();
@@ -340,7 +397,372 @@
     log ("Failed to open %s: errno=%d.\n", devName, errno);
 }
 
-//////////////////////////////////////////////////////////////////////////////
+QPoint QConsolePrivate::posToCell (const QPoint& p)
+{
+  return QPoint (m_consoleRect.left () + p.x () / m_charSize.width (),
+                 m_consoleRect.top () + p.y () / m_charSize.height ());
+}
+
+QString QConsolePrivate::getSelection (void)
+{
+  QString selection;
+
+  QPoint begin = m_beginSelection;
+  QPoint end = m_endSelection;
+
+  maybeSwapPoints (begin, end);
+
+  if (begin != end)
+    {
+      CHAR_INFO* buf;
+      COORD bufSize, bufCoord;
+      SMALL_RECT bufRect;
+      int nr;
+
+      nr = end.y () - begin.y () + 1;
+      buf =  new CHAR_INFO[m_bufferSize.width () * nr];
+      bufSize.X = m_bufferSize.width ();
+      bufSize.Y = nr;
+      bufCoord.X = 0;
+      bufCoord.Y = 0;
+
+      bufRect.Left = 0;
+      bufRect.Right = m_bufferSize.width ();
+      bufRect.Top = begin.y ();
+      bufRect.Bottom = end.y ();
+
+      if (ReadConsoleOutput (m_stdOut, buf, bufSize, bufCoord, &bufRect))
+        {
+          int start_pos = begin.x ();
+          int end_pos = (nr - 1) * m_bufferSize.width () + end.x ();
+          int lastNonSpace = -1;
+
+          for (int i = start_pos; i <= end_pos; i++)
+            {
+              if (i && (i % m_bufferSize.width ()) == 0)
+                {
+                  if (lastNonSpace >= 0)
+                    selection.truncate (lastNonSpace);
+                  selection.append ('\n');
+                  lastNonSpace = selection.length ();
+                }
+
+              QChar c (buf[i].Char.UnicodeChar);
+
+              selection.append (c);
+              if (! c.isSpace ())
+                lastNonSpace = selection.length ();
+            }
+
+          if (lastNonSpace >= 0)
+            selection.truncate (lastNonSpace);
+        }
+    }
+
+  return selection;
+}
+
+void QConsolePrivate::updateSelection (void)
+{
+  QPoint begin = m_beginSelection;
+  QPoint end = m_endSelection;
+
+  maybeSwapPoints (begin, end);
+
+  begin.rx () = 0;
+  end.rx () = m_consoleRect.width ();
+
+  m_consoleView->update ();
+}
+
+void QConsolePrivate::clearSelection (void)
+{
+  m_beginSelection = m_endSelection = QPoint ();
+
+  m_consoleView->update ();
+}
+
+QColor QConsolePrivate::backgroundColor (void) const
+{
+  return m_colors[15];
+}
+
+QColor QConsolePrivate::foregroundColor (void) const
+{
+  return m_colors[0];
+}
+
+QColor QConsolePrivate::selectionColor (void) const
+{
+  return m_selectionColor;
+}
+
+QColor QConsolePrivate::cursorColor (void) const
+{
+  return m_cursorColor.isValid () ? m_cursorColor : foregroundColor ();
+}
+
+void QConsolePrivate::setBackgroundColor (const QColor& color)
+{
+  m_colors[15] = color;
+}
+
+void QConsolePrivate::setForegroundColor (const QColor& color)
+{
+  m_colors[0] = color;
+}
+
+void QConsolePrivate::setSelectionColor (const QColor& color)
+{
+  m_selectionColor = color;
+}
+
+void QConsolePrivate::setCursorColor (bool useForegroundColor,
+                                      const QColor& color)
+{
+  m_cursorColor = useForegroundColor ? QColor () : color;
+}
+
+void QConsolePrivate::drawTextBackground (QPainter& p, int cx1, int cy1,
+                                          int cx2, int cy2, int cw, int ch)
+{
+  p.save ();
+
+  int ascent = p.fontMetrics ().ascent ();
+  int stride = m_consoleRect.width ();
+  int y = ascent + cy1 * ch;;
+
+  for (int j = cy1; j <= cy2; j++, y += ch)
+    {
+      int len = 0;
+      bool hasChar = false;
+      int x = cx1 * cw;
+      WORD attr = 0;
+
+      for (int i = cx1; i <= cx2; i++)
+        {
+          CHAR_INFO* ci = &(m_buffer[stride*j+i]);
+
+          if ((ci->Attributes & 0x00ff) != attr)
+            {
+              // Character attributes changed
+              if (len != 0)
+                {
+                  // String buffer not empty -> draw it
+                  if (hasChar || (attr & 0x00f0))
+                    {
+                      if (attr & 0x00f0)
+                        p.fillRect (x, y-ascent, len * cw, ch, p.brush ());
+                    }
+
+                  x += (len * cw);
+                  len = 0;
+                  hasChar = false;
+                }
+              // Update current brush and store current attributes
+              attr = (ci->Attributes & 0x00ff);
+              p.setBrush (m_colors[(attr >> 4) & 0x000f]);
+            }
+
+          // Append current character to the string buffer
+          len++;
+          if (ci->Char.UnicodeChar != L' ')
+            hasChar = true;
+        }
+
+      if (len != 0 && (hasChar || (attr & 0x00f0)))
+        {
+          // Line end reached, but string buffer not empty -> draw it
+          // No need to update s or x, they will be reset on the next
+          // for-loop iteration
+
+          if (attr & 0x00f0)
+            p.fillRect (x, y-ascent, len * cw, ch, p.brush ());
+        }
+    }
+
+  p.restore ();
+}
+
+void QConsolePrivate::drawSelection (QPainter& p, int cx1, int cy1,
+                                     int cx2, int cy2, int cw, int ch)
+{
+  p.save ();
+
+  QPoint begin = m_beginSelection;
+  QPoint end = m_endSelection;
+
+  bool haveSelection = (begin != end);
+
+  if (haveSelection)
+    maybeSwapPoints (begin, end);
+
+  int scrollOffset = m_consoleRect.top ();
+
+  begin.ry () -= scrollOffset;
+  end.ry () -= scrollOffset;
+
+  int ascent = p.fontMetrics ().ascent ();
+  int stride = m_consoleRect.width ();
+
+  int y = ascent + cy1 * ch;;
+  for (int j = cy1; j <= cy2; j++, y += ch)
+    {
+      int charsThisLine = 0;
+      int len = 0;
+      bool hasChar = false;
+      WORD attr = 0;
+
+      for (int i = cx1; i <= cx2; i++)
+        {
+          CHAR_INFO* ci = &(m_buffer[stride*j+i]);
+
+          if ((ci->Attributes & 0x00ff) != attr)
+            {
+              // Character attributes changed
+              if (len != 0)
+                {
+                  charsThisLine += len;
+                  len = 0;
+                  hasChar = false;
+                }
+
+              // Store current attributes
+              attr = (ci->Attributes & 0x00ff);
+            }
+
+          // Append current character to the string buffer
+          len++;
+          if (ci->Char.UnicodeChar != L' ')
+            hasChar = true;
+        }
+
+      if (len != 0 && (hasChar || (attr & 0x00f0)))
+        charsThisLine += len;
+
+      if (haveSelection && j >= begin.y () && j <= end.y ())
+        {
+          int selectionBegin = j == begin.y () ? begin.x (): 0;
+
+          int len = ((j == end.y () && end.x () < charsThisLine)
+                     ? end.x () - selectionBegin + 1
+                     : stride - selectionBegin);
+
+          p.fillRect (selectionBegin * cw, y-ascent, len * cw, ch,
+                      selectionColor ());
+        }
+    }
+
+  p.restore ();
+}
+
+void QConsolePrivate::drawCursor (QPainter& p)
+{
+  if (! m_cursorBlinking)
+    {
+      p.save ();
+
+      QRect rect = cursorRect ();
+      QColor color = cursorColor ();
+
+      p.setPen (color);
+
+      if (m_cursorType == QConsolePrivate::BlockCursor)
+        {
+          if (q->hasFocus ())
+            p.fillRect (rect, color);
+          else
+            {
+              // draw the cursor outline, adjusting the area so that
+              // it is draw entirely inside 'rect'
+ 
+              int penWidth = qMax (1, p.pen().width());
+ 
+              p.drawRect (rect.adjusted (penWidth/2, penWidth/2,
+                                         - penWidth/2 - penWidth%2,
+                                         - penWidth/2 - penWidth%2));
+            }
+        }
+      else if (m_cursorType == QConsolePrivate::UnderlineCursor)
+        {
+          p.drawLine (rect.left (), rect.bottom (),
+                      rect.right (), rect.bottom ());
+        }
+      else if (m_cursorType == QConsolePrivate::IBeamCursor)
+        {
+          p.drawLine (rect.left (), rect.top (),
+                      rect.left (), rect.bottom ());
+        }
+
+      p.restore ();
+    }
+}
+
+void QConsolePrivate::drawText (QPainter& p, int cx1, int cy1,
+                                int cx2, int cy2, int cw, int ch)
+{
+  p.save ();
+
+  p.setFont (m_font);
+  p.setPen (foregroundColor ());
+
+  QString s;
+  s.reserve (cx2 - cx1 + 1);
+
+  int ascent = p.fontMetrics ().ascent ();
+  int stride = m_consoleRect.width ();
+
+  int y = ascent + cy1 * ch;;
+  for (int j = cy1; j <= cy2; j++, y += ch)
+    {
+      // Reset string buffer and starting X coordinate
+      s.clear ();
+      bool hasChar = false;
+      int x = cx1 * cw;
+      WORD attr = 0;
+
+      for (int i = cx1; i <= cx2; i++)
+        {
+          CHAR_INFO* ci = &(m_buffer[stride*j+i]);
+
+          if ((ci->Attributes & 0x00ff) != attr)
+            {
+              // Character attributes changed
+              if (! s.isEmpty ())
+                {
+                  // String buffer not empty -> draw it
+                  if (hasChar || (attr & 0x00f0))
+                    p.drawText (x, y, s);
+
+                  x += (s.length () * cw);
+                  s.clear ();
+                  hasChar = false;
+                }
+              // Update current pen and store current attributes
+              attr = (ci->Attributes & 0x00ff);
+              p.setPen (m_colors[attr & 0x000f]);
+            }
+
+          // Append current character to the string buffer
+          s.append (ci->Char.UnicodeChar);
+          if (ci->Char.UnicodeChar != L' ')
+            hasChar = true;
+        }
+
+      if (! s.isEmpty () && (hasChar || (attr & 0x00f0)))
+        {
+          // Line end reached, but string buffer not empty -> draw it
+          // No need to update s or x, they will be reset on the next
+          // for-loop iteration
+
+          p.drawText (x, y, s);
+        }
+    }
+
+  p.restore ();
+}
+
+/////////////////////////////////////////////////////////////////////////////
 
 void QConsolePrivate::closeStandardIO (int fd, DWORD stdHandleId,
                                        const char* name)
@@ -384,10 +806,10 @@
   QFontMetrics fm (m_font);
   QSize winSize = m_consoleView->size ();
 
-  m_charSize.rwidth () = fm.maxWidth ();
+  m_charSize.rwidth () = fm.averageCharWidth ();
   m_charSize.rheight () = fm.lineSpacing ();
 
-  m_consoleRect.setWidth (winSize.width () / fm.maxWidth ());
+  m_consoleRect.setWidth (winSize.width () / fm.averageCharWidth ());
   m_consoleRect.setHeight (winSize.height () / fm.lineSpacing ());
 
   m_bufferSize.rwidth () = m_consoleRect.width ();
@@ -753,6 +1175,29 @@
   delete d;
 }
 
+void QWinTerminalImpl::mouseMoveEvent (QMouseEvent *event)
+{
+  d->m_endSelection = d->posToCell (event->pos ());
+
+  updateSelection ();
+}
+
+void QWinTerminalImpl::mousePressEvent (QMouseEvent *event)
+{
+  if (event->button () == Qt::LeftButton)
+    d->m_beginSelection = d->posToCell (event->pos ());
+}
+
+void QWinTerminalImpl::mouseReleaseEvent (QMouseEvent *event)
+{
+  if (event->button () == Qt::LeftButton)
+    {
+      d->m_endSelection = d->posToCell (event->pos ());
+
+      updateSelection ();
+    }
+}
+
 //////////////////////////////////////////////////////////////////////////////
 
 void QWinTerminalImpl::viewResizeEvent (QConsoleView*, QResizeEvent*)
@@ -766,124 +1211,25 @@
 void QWinTerminalImpl::viewPaintEvent (QConsoleView* w, QPaintEvent* event)
 {
   QPainter p (w);
-  int cw = d->m_charSize.width (), ch = d->m_charSize.height ();
-  int ascent, stride, cx1, cy1, cx2, cy2, x, y;
-  WORD attr = 0;
-  QString s;
-  bool hasChar = false;
+
+  int cw = d->m_charSize.width ();
+  int ch = d->m_charSize.height ();
 
   QRect updateRect = event->rect ();
 
-  cx1 = updateRect.left () / cw;
-  cy1 = updateRect.top () / ch;
-  cx2 = qMin (d->m_consoleRect.width () - 1, updateRect.right () / cw);
-  cy2 = qMin (d->m_consoleRect.height () - 1, updateRect.bottom () / ch);
+  int cx1 = updateRect.left () / cw;
+  int cy1 = updateRect.top () / ch;
+  int cx2 = qMin (d->m_consoleRect.width () - 1, updateRect.right () / cw);
+  int cy2 = qMin (d->m_consoleRect.height () - 1, updateRect.bottom () / ch);
 
   if (cx1 > d->m_consoleRect.width () - 1
       || cy1 > d->m_consoleRect.height () - 1)
     return;
 
-  p.setFont (d->m_font);
-  p.setPen (d->m_foregroundColor);
-
-  ascent = p.fontMetrics ().ascent ();
-  stride = d->m_consoleRect.width ();
-
-  s.reserve (cx2 - cx1 + 1);
-  y = ascent + cy1 * ch;;
-
-  for (int j = cy1; j <= cy2; j++, y += ch)
-    {
-      // Reset string buffer and starting X coordinate
-      s.clear ();
-      hasChar = false;
-      x = cx1 * cw;
-
-      for (int i = cx1; i <= cx2; i++)
-        {
-          CHAR_INFO* ci = &(d->m_buffer[stride*j+i]);
-
-          if ((ci->Attributes & 0x00ff) != attr)
-            {
-              // Character attributes changed
-              if (! s.isEmpty ())
-                {
-                  // String buffer not empty -> draw it
-                  if (hasChar || (attr & 0x00f0))
-                    {
-                      if (attr & 0x00f0)
-                        p.fillRect (x, y-ascent, s.length () * cw, ch,
-                                    p.brush ());
-                      p.drawText (x, y, s);
-                    }
-                  x += (s.length () * cw);
-                  s.clear ();
-                  hasChar = false;
-                }
-              // Update current pen and store current attributes
-              // FIXME: what about background?
-              attr = (ci->Attributes & 0x00ff);
-              p.setPen (d->m_colors[attr & 0x000f]);
-              p.setBrush (d->m_colors[(attr >> 4) & 0x000f]);
-            }
-
-          // Append current character to the string buffer
-          s.append (ci->Char.UnicodeChar);
-          if (ci->Char.UnicodeChar != L' ')
-            hasChar = true;
-        }
-
-      if (! s.isEmpty () && (hasChar || (attr & 0x00f0)))
-        {
-          // Line end reached, but string buffer not empty -> draw it
-          // No need to update s or x, they will be reset on the next
-          // for-loop iteration
-          if (attr & 0x00f0)
-            p.fillRect (x, y-ascent, s.length () * cw, ch, p.brush ());
-          p.drawText (x, y, s);
-        }
-    }
-
-  if (! d->m_cursorBlinking)
-    {
-      QColor cursorColor = d->m_colors[7];
-      QRect cursorRect = d->cursorRect ();
-
-      p.setPen (d->m_foregroundColor);
-
-      if (d->m_cursorType == QConsolePrivate::BlockCursor)
-        {
-          if (hasFocus ())
-            {
-              p.setCompositionMode (QPainter::RasterOp_SourceXorDestination);
-
-              p.fillRect (cursorRect, cursorColor);
-            }
-          else
-            {
-              // draw the cursor outline, adjusting the area so that
-              // it is draw entirely inside 'rect'
- 
-              int penWidth = qMax (1, p.pen().width());
- 
-              p.setBrush (Qt::NoBrush);
-
-              p.drawRect (cursorRect.adjusted (penWidth/2, penWidth/2,
-                                               - penWidth/2 - penWidth%2,
-                                               - penWidth/2 - penWidth%2));
-            }
-        }
-      else if (d->m_cursorType == QConsolePrivate::UnderlineCursor)
-        {
-          p.drawLine (cursorRect.left (), cursorRect.bottom (),
-                      cursorRect.right (), cursorRect.bottom ());
-        }
-      else if (d->m_cursorType == QConsolePrivate::IBeamCursor)
-        {
-          p.drawLine (cursorRect.left (), cursorRect.top (),
-                      cursorRect.left (), cursorRect.bottom ());
-        }
-    }
+  d->drawTextBackground (p, cx1, cy1, cx2, cy2, cw, ch);
+  d->drawSelection (p, cx1, cy1, cx2, cy2, cw, ch);
+  d->drawCursor (p);
+  d->drawText (p, cx1, cy1, cx2, cy2, cw, ch);
 }
 
 void QWinTerminalImpl::blinkCursorEvent (void)
@@ -965,6 +1311,11 @@
   d->monitorConsole ();
 }
 
+void QWinTerminalImpl::updateSelection (void)
+{
+  d->updateSelection ();
+}
+
 //////////////////////////////////////////////////////////////////////////////
 
 void QWinTerminalImpl::focusInEvent (QFocusEvent* event)
@@ -1031,6 +1382,27 @@
   setBlinkingCursor (blinking);
 }
 
+void QWinTerminalImpl::setBackgroundColor (const QColor& color)
+{
+  d->setBackgroundColor (color);
+}
+
+void QWinTerminalImpl::setForegroundColor (const QColor& color)
+{
+  d->setForegroundColor (color);
+}
+
+void QWinTerminalImpl::setSelectionColor (const QColor& color)
+{
+  d->setSelectionColor (color);
+}
+
+void QWinTerminalImpl::setCursorColor (bool useForegroundColor,
+                                       const QColor& color)
+{
+  d->setCursorColor (useForegroundColor, color);
+}
+
 //////////////////////////////////////////////////////////////////////////////
 
 void QWinTerminalImpl::setTerminalFont (const QFont& f)
@@ -1052,10 +1424,17 @@
 
 void QWinTerminalImpl::copyClipboard (void)
 {
+  QClipboard *clipboard = QApplication::clipboard ();
+
+  clipboard->setText (d->getSelection ());
 }
 
 //////////////////////////////////////////////////////////////////////////////
 
 void QWinTerminalImpl::pasteClipboard (void)
 {
+  QString text = QApplication::clipboard()->text (QClipboard::Clipboard);
+
+  if (! text.isEmpty ())
+    sendText (text);
 }
--- a/libgui/qterminal/libqterminal/win32/QWinTerminalImpl.h	Wed May 08 14:57:33 2013 -0400
+++ b/libgui/qterminal/libqterminal/win32/QWinTerminalImpl.h	Wed May 08 14:57:45 2013 -0400
@@ -30,6 +30,7 @@
 class QPaintEvent;
 class QResizeEvent;
 class QWheelEvent;
+class QPoint;
 
 class QConsolePrivate;
 class QConsoleThread;
@@ -54,6 +55,11 @@
   void sendText (const QString& s);
   void setCursorType (CursorType type, bool blinking);
 
+  void setBackgroundColor (const QColor& color);
+  void setForegroundColor (const QColor& color);
+  void setSelectionColor (const QColor& color);
+  void setCursorColor (bool useForegoundColor, const QColor& color);
+
 public slots:
   void copyClipboard (void);
   void pasteClipboard (void);
@@ -74,10 +80,14 @@
   void keyPressEvent (QKeyEvent*);
   bool winEvent (MSG*, long*);
   virtual void start (void);
+  void mouseMoveEvent (QMouseEvent *event);
+  void mousePressEvent (QMouseEvent *event);
+  void mouseReleaseEvent (QMouseEvent *event);
 
 private slots:
   void scrollValueChanged (int value);
   void monitorConsole (void);
+  void updateSelection (void);
 
 private:
   QConsolePrivate* d;
--- a/libgui/src/color-picker.cc	Wed May 08 14:57:33 2013 -0400
+++ b/libgui/src/color-picker.cc	Wed May 08 14:57:45 2013 -0400
@@ -49,8 +49,17 @@
 // draw the button with the actual color (using a stylesheet)
 void color_picker::update_button ()
 {
-  QString css = QString("background-color: %1; border: none;" )
-                        .arg(_color.name());
+  // Is this the right place to look for a "foreground" color that would
+  // provide a reasonable border for the color swatches?
+  QWidget *p = parentWidget ();
+
+  QString bordercolor
+    = p ? p->palette().text().color().name() : QString ("#000000");
+
+  QString css = QString("background-color: %1; border: 1px solid %2;")
+                        .arg(_color.name())
+                        .arg(bordercolor);
+
   setStyleSheet(css);
   repaint ();
 }
--- a/libgui/src/dialog.cc	Wed May 08 14:57:33 2013 -0400
+++ b/libgui/src/dialog.cc	Wed May 08 14:57:45 2013 -0400
@@ -163,7 +163,7 @@
           // Make the last button the button pressed when <esc> key activated.
           if (i == N-1)
             {
-#define ACTIVE_ESCAPE true
+#define ACTIVE_ESCAPE 1
 #if ACTIVE_ESCAPE
               setEscapeButton (pbutton);
 #else
@@ -231,7 +231,7 @@
       for (int j = 0; j < prompt.length (); j++)
         {
           if (j > 0)
-#define RICH_TEXT true
+#define RICH_TEXT 1
 #if RICH_TEXT
             prompt_string.append ("<br>");
 #else
@@ -327,7 +327,7 @@
   : QDialog ()
 {
 
-#define LINE_EDIT_FOLLOWS_PROMPT false
+#define LINE_EDIT_FOLLOWS_PROMPT 0
 
 #if LINE_EDIT_FOLLOWS_PROMPT
     // Prompt on left followed by input on right.
--- a/libgui/src/files-dock-widget.cc	Wed May 08 14:57:33 2013 -0400
+++ b/libgui/src/files-dock-widget.cc	Wed May 08 14:57:45 2013 -0400
@@ -28,9 +28,9 @@
 #include "files-dock-widget.h"
 
 #include <QApplication>
+#include <QClipboard>
 #include <QFileInfo>
 #include <QCompleter>
-#include <QSettings>
 #include <QProcess>
 #include <QDebug>
 #include <QHeaderView>
@@ -42,9 +42,23 @@
 #include <QToolButton>
 #include <QUrl>
 #include <QDesktopServices>
+#include <QFileDialog>
 
 #include "load-save.h"
 
+class FileTreeViewer : public QTreeView
+{
+public:
+
+  FileTreeViewer (QWidget *p) : QTreeView (p) { }
+
+  void mousePressEvent (QMouseEvent *e)
+  {
+    if (e->button () != Qt::RightButton)
+      QTreeView::mousePressEvent (e);
+  }
+};
+
 files_dock_widget::files_dock_widget (QWidget *p)
   : octave_dock_widget (p)
 {
@@ -63,9 +77,6 @@
   connect (this, SIGNAL (displayed_directory_changed (const QString&)),
            parent (), SLOT (set_current_working_directory (const QString&)));
 
-  connect (parent (), SIGNAL (settings_changed (const QSettings *)),
-           this, SLOT (notice_settings (const QSettings *)));
-
   // Create a toolbar
   _navigation_tool_bar = new QToolBar ("", container);
   _navigation_tool_bar->setAllowedAreas (Qt::TopToolBarArea);
@@ -104,6 +115,10 @@
   popdown_button->setDefaultAction(new QAction(QIcon(":/actions/icons/gear.png"),"", _navigation_tool_bar));
 
   popdown_menu->addSeparator();
+  popdown_menu->addAction (QIcon (":/actions/icons/search.png"),
+                           tr ("Search directory"),
+                           this, SLOT (popdownmenu_search_dir (bool)));
+  popdown_menu->addSeparator();
   popdown_menu->addAction(QIcon(":/actions/icons/filenew.png"),
                           tr ("New File"),
                           this, SLOT(popdownmenu_newfile(bool)));
@@ -130,7 +145,8 @@
                                                   curr_dir.absolutePath ());
 
   // Attach the model to the QTreeView and set the root index
-  _file_tree_view = new QTreeView (container);
+  _file_tree_view = new FileTreeViewer (container);
+  _file_tree_view->setSelectionMode (QAbstractItemView::ExtendedSelection);
   _file_tree_view->setModel (_file_system_model);
   _file_tree_view->setRootIndex (rootPathIndex);
   _file_tree_view->setSortingEnabled (true);
@@ -327,6 +343,9 @@
       menu.addAction (tr("Open in Default Application"),
                       this, SLOT (contextmenu_open_in_app (bool)));
 
+      menu.addAction (tr("Copy Selection to Clipboard"),
+                      this, SLOT (contextmenu_copy_selection (bool)));
+
       if (info.isFile () && info.suffix () == "m")
         menu.addAction (QIcon (":/actions/icons/artsbuilderexecute.png"),
                         tr("Run"), this, SLOT(contextmenu_run(bool)));
@@ -387,6 +406,26 @@
 }
 
 void
+files_dock_widget::contextmenu_copy_selection (bool)
+{
+  QItemSelectionModel *m = _file_tree_view->selectionModel ();
+  QModelIndexList rows = m->selectedRows ();
+
+  QStringList selection;
+
+  for (QModelIndexList::iterator it = rows.begin (); it != rows.end (); it++)
+    {
+      QFileInfo info = _file_system_model->fileInfo (*it);
+
+      selection << info.fileName ();
+    }
+
+  QClipboard *clipboard = QApplication::clipboard ();
+
+  clipboard->setText (selection.join ("\n"));
+}
+
+void
 files_dock_widget::contextmenu_load (bool)
 {
   QItemSelectionModel *m = _file_tree_view->selectionModel ();
@@ -573,6 +612,14 @@
 }
 
 void
+files_dock_widget::popdownmenu_search_dir (bool)
+{
+  QString dir
+    = QFileDialog::getExistingDirectory (this, tr ("Set directory of file browser"));
+  process_set_current_dir (dir);
+}
+
+void
 files_dock_widget::popdownmenu_newdir (bool)
 {
       process_new_dir(_file_system_model->rootPath());
--- a/libgui/src/files-dock-widget.h	Wed May 08 14:57:33 2013 -0400
+++ b/libgui/src/files-dock-widget.h	Wed May 08 14:57:45 2013 -0400
@@ -34,7 +34,7 @@
 #include <QVBoxLayout>
 #include <QAction>
 #include <QTreeView>
-#include <QSettings>
+#include <QMouseEvent>
 
 #include <QComboBox>
 #include "octave-dock-widget.h"
@@ -86,6 +86,7 @@
   /* context menu actions */
   void contextmenu_open (bool);
   void contextmenu_open_in_app (bool);
+  void contextmenu_copy_selection (bool);
   void contextmenu_run (bool);
   void contextmenu_load (bool);
   void contextmenu_rename (bool);
@@ -97,6 +98,7 @@
   /* popdown menu options */
   void popdownmenu_newfile(bool);
   void popdownmenu_newdir(bool);
+  void popdownmenu_search_dir (bool);
 
 signals:
 
Binary file libgui/src/icons/fileclose.png has changed
--- a/libgui/src/m-editor/file-editor.cc	Wed May 08 14:57:33 2013 -0400
+++ b/libgui/src/m-editor/file-editor.cc	Wed May 08 14:57:45 2013 -0400
@@ -319,9 +319,8 @@
 
 // open a file from the mru list
 void
-file_editor::request_mru_open_file (void)
+file_editor::request_mru_open_file (QAction *action)
 {
-  QAction *action = qobject_cast<QAction *> (sender ());
   if (action)
     {
       request_open_file (action->data ().toString ());
@@ -625,6 +624,36 @@
 }
 
 void
+file_editor::request_close_file (bool)
+{
+  emit fetab_close_request (_tab_widget->currentWidget ());
+}
+
+void
+file_editor::request_close_all_files (bool)
+{
+  int index;
+  while ((index = _tab_widget->currentIndex ()) > -1)
+    emit fetab_close_request (_tab_widget->widget (index));
+}
+
+void
+file_editor::request_close_other_files (bool)
+{
+  int index = 0;
+  QWidget *tabID = _tab_widget->currentWidget ();
+
+  while (_tab_widget->count () > 1)
+    {
+      if (tabID != _tab_widget->widget (index))
+        emit fetab_close_request (_tab_widget->widget (index));
+      else
+        index++;
+    }
+}
+
+
+void
 file_editor::handle_tab_close_request (int index)
 {
   // Signal to the tabs a request to close whomever matches the identifying
@@ -848,22 +877,40 @@
 
   // menu bar
   QMenu *fileMenu = new QMenu (tr ("&File"), _menu_bar);
-  fileMenu->addAction (new_action);
-  fileMenu->addAction (open_action);
-  fileMenu->addAction (save_action);
-  fileMenu->addAction (save_as_action);
-  fileMenu->addSeparator ();
+
   _mru_file_menu = new QMenu (tr ("&Recent Editor Files"), fileMenu);
-
   for (int i = 0; i < MaxMRUFiles; ++i)
     _mru_file_menu->addAction (_mru_file_actions[i]);
 
+  fileMenu->addAction (new_action);
+  fileMenu->addAction (open_action);
   fileMenu->addMenu (_mru_file_menu);
-  _menu_bar->addMenu (fileMenu);
+
+  fileMenu->addSeparator ();
+  fileMenu->addAction (save_action);
+  fileMenu->addAction (save_as_action);
+
+  fileMenu->addSeparator ();
+  fileMenu->addAction (QIcon::fromTheme("window-close",
+                                      QIcon (":/actions/icons/fileclose.png")),
+                       tr ("&Close"),
+                       this, SLOT (request_close_file (bool)),
+                             QKeySequence::Close);
+  fileMenu->addAction (QIcon::fromTheme("window-close",
+                                      QIcon (":/actions/icons/fileclose.png")),
+                       tr ("Close All"),
+                       this, SLOT (request_close_all_files (bool)));
+  fileMenu->addAction (QIcon::fromTheme("window-close",
+                                      QIcon (":/actions/icons/fileclose.png")),
+                       tr ("Close Other Files"),
+                       this, SLOT (request_close_other_files (bool)));
 
   fileMenu->addSeparator ();
   fileMenu->addAction (print_action);
 
+  _menu_bar->addMenu (fileMenu);
+
+
   QMenu *editMenu = new QMenu (tr ("&Edit"), _menu_bar);
   editMenu->addAction (undo_action);
   editMenu->addAction (redo_action);
@@ -906,9 +953,6 @@
   editor_widget->setLayout (vbox_layout);
   setWidget (editor_widget);
 
-  connect (parent (), SIGNAL (settings_changed (const QSettings *)),
-           this, SLOT (notice_settings (const QSettings *)));
-
   connect (parent (), SIGNAL (new_file_signal (const QString&)),
            this, SLOT (request_new_file (const QString&)));
 
@@ -984,12 +1028,8 @@
   connect (goto_line_action, SIGNAL (triggered ()),
            this, SLOT (request_goto_line ()));
 
-  // The actions of the mru file menu
-  for (int i = 0; i < MaxMRUFiles; ++i)
-    {
-      connect (_mru_file_actions[i], SIGNAL (triggered ()),
-               this, SLOT (request_mru_open_file ()));
-    }
+  connect (_mru_file_menu, SIGNAL (triggered (QAction *)),
+           this, SLOT (request_mru_open_file (QAction *)));
 
   mru_menu_update ();
 
--- a/libgui/src/m-editor/file-editor.h	Wed May 08 14:57:33 2013 -0400
+++ b/libgui/src/m-editor/file-editor.h	Wed May 08 14:57:45 2013 -0400
@@ -29,7 +29,6 @@
 #include <QStatusBar>
 #include <QCloseEvent>
 #include <QTabWidget>
-#include <QSettings>
 
 #include <map>
 
@@ -106,7 +105,10 @@
   void request_new_script (const QString& commands);
   void request_new_function (const QString& commands);
   void request_open_file (void);
-  void request_mru_open_file (void);
+  void request_close_file (bool);
+  void request_close_all_files (bool);
+  void request_close_other_files (bool);
+  void request_mru_open_file (QAction *action);
   void request_print_file (void);
 
   void request_undo (void);
--- a/libgui/src/module.mk	Wed May 08 14:57:33 2013 -0400
+++ b/libgui/src/module.mk	Wed May 08 14:57:45 2013 -0400
@@ -23,6 +23,7 @@
   src/icons/editcut.png \
   src/icons/editdelete.png \
   src/icons/editpaste.png \
+  src/icons/fileclose.png \
   src/icons/filenew.png \
   src/icons/fileopen.png \
   src/icons/fileprint.png \
--- a/libgui/src/octave-dock-widget.h	Wed May 08 14:57:33 2013 -0400
+++ b/libgui/src/octave-dock-widget.h	Wed May 08 14:57:45 2013 -0400
@@ -24,6 +24,7 @@
 #define octave_dock_widget_h 1
 
 #include <QDockWidget>
+#include <QSettings>
 
 class octave_dock_widget : public QDockWidget
 {
@@ -39,6 +40,9 @@
 
     connect (this, SIGNAL (topLevelChanged (bool)),
              this, SLOT (top_level_changed (bool)));
+
+    connect (p, SIGNAL (settings_changed (const QSettings*)),
+             this, SLOT (notice_settings (const QSettings*)));
   }
 
   virtual ~octave_dock_widget () { }
@@ -49,6 +53,7 @@
              this, SLOT (handle_visibility (bool)));
   }
 
+
 signals:
 
   /** Custom signal that tells whether a user has clicked away
@@ -82,6 +87,10 @@
       focus ();
   }
 
+  virtual void notice_settings (const QSettings*)
+  {
+  }
+
 protected slots:
 
   /** Slot to steer changing visibility from outside. */
--- a/libgui/src/resource-manager.cc	Wed May 08 14:57:33 2013 -0400
+++ b/libgui/src/resource-manager.cc	Wed May 08 14:57:45 2013 -0400
@@ -217,6 +217,24 @@
                           << QColor(255,190,255);
 }
 
+QStringList 
+resource_manager::terminal_color_names (void)
+{
+  return QStringList () << QObject::tr ("foreground")
+                        << QObject::tr ("background")
+                        << QObject::tr ("selection")
+                        << QObject::tr ("cursor");
+}
+
+QList<QColor>
+resource_manager::terminal_default_colors (void)
+{
+  return QList<QColor> () << QColor(0,0,0)
+                          << QColor(255,255,255)
+                          << QColor(192,192,192)
+                          << QColor(128,128,128);
+}
+
 const char*
 resource_manager::octave_keywords (void)
 {
--- a/libgui/src/resource-manager.h	Wed May 08 14:57:33 2013 -0400
+++ b/libgui/src/resource-manager.h	Wed May 08 14:57:45 2013 -0400
@@ -87,6 +87,10 @@
   static QStringList storage_class_names (void);
   static QList<QColor> storage_class_default_colors (void);
 
+  static QString terminal_color_chars (void) { return "fbsc"; }
+  static QStringList terminal_color_names (void);
+  static QList<QColor> terminal_default_colors (void);
+
 private:
 
   static resource_manager *instance;
--- a/libgui/src/resource.qrc	Wed May 08 14:57:33 2013 -0400
+++ b/libgui/src/resource.qrc	Wed May 08 14:57:45 2013 -0400
@@ -5,6 +5,7 @@
         <file>icons/editcut.png</file>
         <file>icons/editdelete.png</file>
         <file>icons/editpaste.png</file>
+        <file>icons/fileclose.png</file>
         <file>icons/filenew.png</file>
         <file>icons/fileopen.png</file>
         <file>icons/filesave.png</file>
--- a/libgui/src/settings-dialog.cc	Wed May 08 14:57:33 2013 -0400
+++ b/libgui/src/settings-dialog.cc	Wed May 08 14:57:45 2013 -0400
@@ -31,6 +31,7 @@
 #include <QSettings>
 #include <QDir>
 #include <QFileInfo>
+#include <QVector>
 
 #ifdef HAVE_QSCINTILLA
 #include <QScrollArea>
@@ -97,6 +98,7 @@
   ui->useProxyServer->setChecked (settings->value ("useProxyServer",false).toBool ());
   ui->proxyHostName->setText (settings->value ("proxyHostName").toString ());
   ui->terminal_cursorBlinking->setChecked (settings->value ("terminal/cursorBlinking",true).toBool ());
+  ui->terminal_cursorUseForegroundColor->setChecked (settings->value ("terminal/cursorUseForegroundColor",true).toBool ());
 
   QString cursorType = settings->value ("terminal/cursorType","ibeam").toString ();
 
@@ -129,6 +131,9 @@
   // qorkspace colors
   read_workspace_colors (settings);
 
+  // terminal colors
+  read_terminal_colors (settings);
+
 #ifdef HAVE_QSCINTILLA
   // editor styles: create lexer, read settings, and create dialog elements
   QsciLexer *lexer;
@@ -150,7 +155,9 @@
   lexer = new QsciLexerBash ();
   read_lexer_settings (lexer,settings);
   delete lexer;
-#endif    
+#endif
+
+  ui->tabWidget->setCurrentIndex (settings->value("settings/last_tab",0).toInt ());
 }
 
 settings_dialog::~settings_dialog ()
@@ -181,11 +188,11 @@
   int styles[MaxLexerStyles];  // array for saving valid styles (enum is not continuous)
   int max_style = get_valid_lexer_styles (lexer, styles);
   QGridLayout *style_grid = new QGridLayout ();
-  QLabel *description[max_style];
-  QFontComboBox *select_font[max_style];
-  QSpinBox *font_size[max_style];
-  QCheckBox *attrib_font[3][max_style];
-  color_picker *color[max_style];
+  QVector<QLabel*> description (max_style);
+  QVector<QFontComboBox*> select_font (max_style);
+  QVector<QSpinBox*> font_size (max_style);
+  QVector<QCheckBox*> attrib_font (3 * max_style);
+  QVector<color_picker*> color (max_style);
   int default_size = 10;
   QFont default_font = QFont ();
   for (int i = 0; i < max_style; i++)  // create dialog elements for all styles
@@ -217,25 +224,25 @@
           font_size[i]->setValue (actual_font.pointSize ()-default_size);
           font_size[i]->setToolTip ("Difference to the defalt size");
         }
-      attrib_font[0][i] = new QCheckBox (tr("b"));
-      attrib_font[1][i] = new QCheckBox (tr("i"));
-      attrib_font[2][i] = new QCheckBox (tr("u"));
-      attrib_font[0][i]->setChecked(Qt::Checked && actual_font.bold ());
-      attrib_font[0][i]->setObjectName (actual_name+"_bold");
-      attrib_font[1][i]->setChecked(Qt::Checked && actual_font.italic ());
-      attrib_font[1][i]->setObjectName (actual_name+"_italic");
-      attrib_font[2][i]->setChecked(Qt::Checked && actual_font.underline ());
-      attrib_font[2][i]->setObjectName (actual_name+"_underline");
+      attrib_font[0+3*i] = new QCheckBox (tr("b"));
+      attrib_font[1+3*i] = new QCheckBox (tr("i"));
+      attrib_font[2+3*i] = new QCheckBox (tr("u"));
+      attrib_font[0+3*i]->setChecked(Qt::Checked && actual_font.bold ());
+      attrib_font[0+3*i]->setObjectName (actual_name+"_bold");
+      attrib_font[1+3*i]->setChecked(Qt::Checked && actual_font.italic ());
+      attrib_font[1+3*i]->setObjectName (actual_name+"_italic");
+      attrib_font[2+3*i]->setChecked(Qt::Checked && actual_font.underline ());
+      attrib_font[2+3*i]->setObjectName (actual_name+"_underline");
       color[i] = new color_picker (lexer->color (styles[i]));
       color[i]->setObjectName (actual_name+"_color");
       int column = 1;
-      style_grid->addWidget (description[i],   i,column++);
-      style_grid->addWidget (select_font[i],   i,column++);
-      style_grid->addWidget (font_size[i],     i,column++);
-      style_grid->addWidget (attrib_font[0][i],i,column++);
-      style_grid->addWidget (attrib_font[1][i],i,column++);
-      style_grid->addWidget (attrib_font[2][i],i,column++);
-      style_grid->addWidget (color[i],         i,column++);
+      style_grid->addWidget (description[i],     i, column++);
+      style_grid->addWidget (select_font[i],     i, column++);
+      style_grid->addWidget (font_size[i],       i, column++);
+      style_grid->addWidget (attrib_font[0+3*i], i, column++);
+      style_grid->addWidget (attrib_font[1+3*i], i, column++);
+      style_grid->addWidget (attrib_font[2+3*i], i, column++);
+      style_grid->addWidget (color[i],           i, column++);
     }
   // place grid with elements into the tab
   QScrollArea *scroll_area = new QScrollArea ();
@@ -244,6 +251,9 @@
   scroll_area_contents->setLayout (style_grid);
   scroll_area->setWidget (scroll_area_contents);
   ui->tabs_editor_styles->addTab (scroll_area,lexer->language ());
+
+  ui->tabs_editor_styles->setCurrentIndex (
+          settings->value("settings/last_editor_styles_tab",0).toInt ());
 }
 #endif  
 
@@ -257,8 +267,8 @@
   int nr_of_classes = class_chars.length ();
 
   QGridLayout *style_grid = new QGridLayout ();
-  QLabel *description[nr_of_classes];
-  color_picker *color[nr_of_classes];
+  QVector<QLabel*> description (nr_of_classes);
+  QVector<color_picker*> color (nr_of_classes);
 
   int column = 0;
   int row = 0;
@@ -285,6 +295,43 @@
   ui->workspace_colors_box->setLayout (style_grid);
 }
 
+void
+settings_dialog::read_terminal_colors (QSettings *settings)
+{
+
+  QList<QColor> default_colors = resource_manager::terminal_default_colors ();
+  QStringList class_names = resource_manager::terminal_color_names ();
+  QString class_chars = resource_manager::terminal_color_chars ();
+  int nr_of_classes = class_chars.length ();
+
+  QGridLayout *style_grid = new QGridLayout ();
+  QVector<QLabel*> description (nr_of_classes);
+  QVector<color_picker*> color (nr_of_classes);
+
+  int column = 0;
+  int row = 0;
+  for (int i = 0; i < nr_of_classes; i++)
+    {
+      description[i] = new QLabel (class_names.at (i));
+      description[i]->setAlignment (Qt::AlignRight);
+      QVariant default_var = default_colors.at (i);
+      QColor setting_color = settings->value ("terminal/color_"+class_chars.mid (i,1),
+                                              default_var).value<QColor> ();
+      color[i] = new color_picker (setting_color);
+      color[i]->setObjectName ("terminal_color_"+class_chars.mid (i,1));
+      color[i]->setMinimumSize (30,10);
+      style_grid->addWidget (description[i], row,2*column);
+      style_grid->addWidget (color[i],       row,2*column+1);
+      if (++column == 2)
+        {
+          row++;
+          column = 0;
+        }
+    }
+
+  // place grid with elements into the tab
+  ui->terminal_colors_box->setLayout (style_grid);
+}
 
 void
 settings_dialog::write_changed_settings ()
@@ -330,6 +377,7 @@
   settings->setValue ("proxyUserName", ui->proxyUserName->text ());
   settings->setValue ("proxyPassword", ui->proxyPassword->text ());
   settings->setValue ("terminal/cursorBlinking", ui->terminal_cursorBlinking->isChecked ());
+  settings->setValue ("terminal/cursorUseForegroundColor", ui->terminal_cursorUseForegroundColor->isChecked ());
 
   // the cursor
   QString cursorType;
@@ -366,6 +414,10 @@
 #endif
 
   write_workspace_colors (settings);
+
+  write_terminal_colors (settings);
+
+  settings->setValue("settings/last_tab",ui->tabWidget->currentIndex ());
 }
 
 #ifdef HAVE_QSCINTILLA
@@ -424,6 +476,9 @@
         lexer->setColor (color->color (),styles[i]);
     }
   lexer->writeSettings (*settings);
+
+  settings->setValue (
+    "settings/last_editor_styles_tab",ui->tabs_editor_styles->currentIndex ());
 }
 #endif
 
@@ -444,3 +499,20 @@
     }
   settings->sync ();
 }
+
+void
+settings_dialog::write_terminal_colors (QSettings *settings)
+{
+  QString class_chars = resource_manager::terminal_color_chars ();
+  color_picker *color;
+
+  for (int i = 0; i < class_chars.length (); i++)
+    {
+      color = ui->terminal_colors_box->findChild <color_picker *>(
+                            "terminal_color_"+class_chars.mid (i,1));
+      if (color)
+        settings->setValue ("terminal/color_"+class_chars.mid (i,1),
+                            color->color ());
+    }
+  settings->sync ();
+}
--- a/libgui/src/settings-dialog.h	Wed May 08 14:57:33 2013 -0400
+++ b/libgui/src/settings-dialog.h	Wed May 08 14:57:45 2013 -0400
@@ -52,6 +52,9 @@
 
   void read_workspace_colors (QSettings *settings);
   void write_workspace_colors (QSettings *settings);
+
+  void read_terminal_colors (QSettings *settings);
+  void write_terminal_colors (QSettings *settings);
 };
 
 #endif // SETTINGSDIALOG_H
--- a/libgui/src/settings-dialog.ui	Wed May 08 14:57:33 2013 -0400
+++ b/libgui/src/settings-dialog.ui	Wed May 08 14:57:45 2013 -0400
@@ -32,7 +32,7 @@
    <item>
     <widget class="QTabWidget" name="tabWidget">
      <property name="currentIndex">
-      <number>0</number>
+      <number>3</number>
      </property>
      <widget class="QWidget" name="tab_4">
       <property name="enabled">
@@ -317,126 +317,167 @@
       <attribute name="title">
        <string>Terminal</string>
       </attribute>
-      <layout class="QVBoxLayout" name="verticalLayout">
-       <item>
-        <layout class="QHBoxLayout" name="horizontalLayout_5">
-         <item>
-          <widget class="QLabel" name="label_11">
-           <property name="text">
-            <string>Font</string>
-           </property>
-          </widget>
-         </item>
-         <item>
-          <widget class="QFontComboBox" name="terminal_fontName">
-           <property name="editable">
-            <bool>false</bool>
-           </property>
-           <property name="fontFilters">
-            <set>QFontComboBox::MonospacedFonts</set>
-           </property>
-          </widget>
-         </item>
-         <item>
-          <widget class="QLabel" name="label_12">
-           <property name="text">
-            <string>Font Size</string>
-           </property>
-          </widget>
-         </item>
-         <item>
-          <widget class="QSpinBox" name="terminal_fontSize">
-           <property name="minimum">
-            <number>2</number>
-           </property>
-           <property name="maximum">
-            <number>96</number>
-           </property>
-           <property name="value">
-            <number>10</number>
-           </property>
-          </widget>
-         </item>
-         <item>
-          <spacer name="horizontalSpacer_5">
-           <property name="orientation">
-            <enum>Qt::Horizontal</enum>
-           </property>
-           <property name="sizeHint" stdset="0">
-            <size>
-             <width>40</width>
-             <height>20</height>
-            </size>
-           </property>
-          </spacer>
-         </item>
-        </layout>
-       </item>
-       <item>
-        <layout class="QHBoxLayout" name="horizontalLayout_3">
-         <item>
-          <widget class="QLabel" name="label">
-           <property name="text">
-            <string>Cursor type:</string>
-           </property>
-          </widget>
-         </item>
-         <item>
-          <widget class="QComboBox" name="terminal_cursorType"/>
-         </item>
-         <item>
-          <spacer name="horizontalSpacer">
-           <property name="orientation">
-            <enum>Qt::Horizontal</enum>
-           </property>
-           <property name="sizeHint" stdset="0">
-            <size>
-             <width>40</width>
-             <height>20</height>
-            </size>
-           </property>
-          </spacer>
-         </item>
-        </layout>
-       </item>
-       <item>
-        <layout class="QHBoxLayout" name="horizontalLayout_2">
-         <item>
-          <widget class="QCheckBox" name="terminal_cursorBlinking">
-           <property name="text">
-            <string>Cursor blinking</string>
-           </property>
-          </widget>
-         </item>
-         <item>
-          <spacer name="horizontalSpacer_2">
-           <property name="orientation">
-            <enum>Qt::Horizontal</enum>
-           </property>
-           <property name="sizeHint" stdset="0">
-            <size>
-             <width>40</width>
-             <height>20</height>
-            </size>
-           </property>
-          </spacer>
-         </item>
-        </layout>
-       </item>
-       <item>
-        <spacer name="verticalSpacer_3">
-         <property name="orientation">
-          <enum>Qt::Vertical</enum>
-         </property>
-         <property name="sizeHint" stdset="0">
-          <size>
-           <width>20</width>
-           <height>321</height>
-          </size>
-         </property>
-        </spacer>
-       </item>
-      </layout>
+      <widget class="QWidget" name="horizontalLayoutWidget">
+       <property name="geometry">
+        <rect>
+         <x>10</x>
+         <y>50</y>
+         <width>631</width>
+         <height>31</height>
+        </rect>
+       </property>
+       <layout class="QHBoxLayout" name="horizontalLayout_3">
+        <item>
+         <widget class="QLabel" name="label">
+          <property name="text">
+           <string>Cursor type:</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QComboBox" name="terminal_cursorType"/>
+        </item>
+        <item>
+         <spacer name="horizontalSpacer">
+          <property name="orientation">
+           <enum>Qt::Horizontal</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>40</width>
+            <height>20</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+        <item>
+         <widget class="QCheckBox" name="terminal_cursorBlinking">
+          <property name="text">
+           <string>Cursor blinking</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QCheckBox" name="terminal_cursorUseForegroundColor">
+          <property name="text">
+           <string>Use Foreground Color</string>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+      <widget class="QWidget" name="verticalLayoutWidget_2">
+       <property name="geometry">
+        <rect>
+         <x>10</x>
+         <y>90</y>
+         <width>631</width>
+         <height>164</height>
+        </rect>
+       </property>
+       <layout class="QVBoxLayout" name="verticalLayout">
+        <item>
+         <widget class="QGroupBox" name="terminal_colors_box">
+          <property name="minimumSize">
+           <size>
+            <width>0</width>
+            <height>162</height>
+           </size>
+          </property>
+          <property name="title">
+           <string>Terminal Colors</string>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+      <widget class="QWidget" name="verticalLayoutWidget_3">
+       <property name="geometry">
+        <rect>
+         <x>10</x>
+         <y>260</y>
+         <width>631</width>
+         <height>121</height>
+        </rect>
+       </property>
+       <layout class="QVBoxLayout" name="verticalLayout_8">
+        <item>
+         <spacer name="verticalSpacer_3">
+          <property name="orientation">
+           <enum>Qt::Vertical</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>20</width>
+            <height>40</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+       </layout>
+      </widget>
+      <widget class="QWidget" name="layoutWidget">
+       <property name="geometry">
+        <rect>
+         <x>10</x>
+         <y>10</y>
+         <width>631</width>
+         <height>30</height>
+        </rect>
+       </property>
+       <layout class="QHBoxLayout" name="horizontalLayout_5">
+        <item>
+         <widget class="QLabel" name="label_11">
+          <property name="text">
+           <string>Font</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QFontComboBox" name="terminal_fontName">
+          <property name="editable">
+           <bool>false</bool>
+          </property>
+          <property name="fontFilters">
+           <set>QFontComboBox::MonospacedFonts</set>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QLabel" name="label_12">
+          <property name="text">
+           <string>Font Size</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QSpinBox" name="terminal_fontSize">
+          <property name="minimum">
+           <number>2</number>
+          </property>
+          <property name="maximum">
+           <number>96</number>
+          </property>
+          <property name="value">
+           <number>10</number>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <spacer name="horizontalSpacer_5">
+          <property name="orientation">
+           <enum>Qt::Horizontal</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>40</width>
+            <height>20</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+       </layout>
+      </widget>
      </widget>
      <widget class="QWidget" name="tab_2">
       <attribute name="title">
@@ -513,6 +554,12 @@
          <height>81</height>
         </rect>
        </property>
+       <property name="minimumSize">
+        <size>
+         <width>0</width>
+         <height>81</height>
+        </size>
+       </property>
        <property name="title">
         <string>Storage Class Colors</string>
        </property>
--- a/libgui/src/terminal-dock-widget.cc	Wed May 08 14:57:33 2013 -0400
+++ b/libgui/src/terminal-dock-widget.cc	Wed May 08 14:57:45 2013 -0400
@@ -38,9 +38,6 @@
   setWindowTitle (tr ("Command Window"));
   setWidget (terminal);
 
-  connect (parent (), SIGNAL (settings_changed (const QSettings *)),
-           this, SLOT (notice_settings (const QSettings *)));
-
   connect (this, SIGNAL (visibilityChanged (bool)),
            this, SLOT (handle_visibility (bool)));
 
--- a/libgui/src/workspace-view.cc	Wed May 08 14:57:33 2013 -0400
+++ b/libgui/src/workspace-view.cc	Wed May 08 14:57:45 2013 -0400
@@ -78,9 +78,6 @@
   connect (this, SIGNAL (command_requested (const QString&)),
            p, SLOT (execute_command_in_terminal (const QString&)));
 
-  connect (parent (), SIGNAL (settings_changed (const QSettings *)),
-           this, SLOT (notice_settings (const QSettings *)));
-
 }
 
 workspace_view::~workspace_view (void)
--- a/libinterp/interpfcn/debug.cc	Wed May 08 14:57:33 2013 -0400
+++ b/libinterp/interpfcn/debug.cc	Wed May 08 14:57:45 2013 -0400
@@ -316,19 +316,27 @@
     {
       if (! do_add_breakpoint_1 (dbg_fcn, fname, line, retval))
         {
-          typedef std::map<std::string, octave_value>::const_iterator
-            subfunction_map_const_iterator;
+          // Search subfunctions in the order they appear in the file.
+
+          const std::list<std::string> subfcn_names
+            = dbg_fcn->subfunction_names ();
 
           std::map<std::string, octave_value> subfcns
             = dbg_fcn->subfunctions ();
 
-          for (subfunction_map_const_iterator p = subfcns.begin ();
-               p != subfcns.end (); p++)
+          for (std::list<std::string>::const_iterator p = subfcn_names.begin ();
+               p != subfcn_names.end (); p++)
             {
-              octave_user_code *dbg_subfcn = p->second.user_code_value ();
+              std::map<std::string, octave_value>::const_iterator
+                q = subfcns.find (*p);
 
-              if (do_add_breakpoint_1 (dbg_subfcn, fname, line, retval))
-                break;
+              if (q != subfcns.end ())
+                {
+                  octave_user_code *dbg_subfcn = q->second.user_code_value ();
+
+                  if (do_add_breakpoint_1 (dbg_subfcn, fname, line, retval))
+                    break;
+                }
             }
         }
     }
@@ -342,6 +350,56 @@
 
 
 int
+bp_table::do_remove_breakpoint_1 (octave_user_code *fcn,
+                                  const std::string& fname,
+                                  const bp_table::intmap& line)
+{
+  int retval = 0;
+
+  std::string file = fcn->fcn_file_name ();
+
+  tree_statement_list *cmds = fcn->body ();
+
+  // FIXME -- move the operation on cmds to the
+  // tree_statement_list class?
+
+  if (cmds)
+    {
+      octave_value_list results = cmds->list_breakpoints ();
+
+      if (results.length () > 0)
+        {
+          octave_idx_type len = line.size ();
+
+          for (int i = 0; i < len; i++)
+            {
+              const_intmap_iterator p = line.find (i);
+
+              if (p != line.end ())
+                {
+                  int lineno = p->second;
+
+                  cmds->delete_breakpoint (lineno);
+
+                  if (! file.empty ())
+                    octave_link::update_breakpoint (false, file, lineno);
+                }
+            }
+
+          results = cmds->list_breakpoints ();
+
+          bp_set_iterator it = bp_set.find (fname);
+          if (results.length () == 0 && it != bp_set.end ())
+            bp_set.erase (it);
+        }
+
+      retval = results.length ();
+    }
+
+  return retval;
+}
+
+int
 bp_table::do_remove_breakpoint (const std::string& fname,
                                 const bp_table::intmap& line)
 {
@@ -360,41 +418,28 @@
 
       if (dbg_fcn)
         {
-          std::string file = dbg_fcn->fcn_file_name ();
+          retval = do_remove_breakpoint_1 (dbg_fcn, fname, line);
 
-          tree_statement_list *cmds = dbg_fcn->body ();
+          // Search subfunctions in the order they appear in the file.
 
-          // FIXME -- move the operation on cmds to the
-          // tree_statement_list class?
-          if (cmds)
-            {
-              octave_value_list results = cmds->list_breakpoints ();
+          const std::list<std::string> subfcn_names
+            = dbg_fcn->subfunction_names ();
 
-              if (results.length () > 0)
-                {
-                  for (int i = 0; i < len; i++)
-                    {
-                      const_intmap_iterator p = line.find (i);
+          std::map<std::string, octave_value> subfcns
+            = dbg_fcn->subfunctions ();
 
-                      if (p != line.end ())
-                        {
-                          int lineno = p->second;
-
-                          cmds->delete_breakpoint (lineno);
+          for (std::list<std::string>::const_iterator p = subfcn_names.begin ();
+               p != subfcn_names.end (); p++)
+            {
+              std::map<std::string, octave_value>::const_iterator
+                q = subfcns.find (*p);
 
-                          if (! file.empty ())
-                            octave_link::update_breakpoint (false, file, lineno);
-                        }
-                    }
-
-                  results = cmds->list_breakpoints ();
+              if (q != subfcns.end ())
+                {
+                  octave_user_code *dbg_subfcn = q->second.user_code_value ();
 
-                  bp_set_iterator it = bp_set.find (fname);
-                  if (results.length () == 0 && it != bp_set.end ())
-                    bp_set.erase (it);
+                  retval += do_remove_breakpoint_1 (dbg_subfcn, fname, line);
                 }
-
-              retval = results.length ();
             }
         }
       else
@@ -406,6 +451,27 @@
   return retval;
 }
 
+bp_table::intmap
+bp_table::do_remove_all_breakpoints_in_file_1 (octave_user_code *fcn,
+                                               const std::string& fname)
+{
+  intmap retval;
+
+  std::string file = fcn->fcn_file_name ();
+
+  tree_statement_list *cmds = fcn->body ();
+
+  if (cmds)
+    {
+      retval = cmds->remove_all_breakpoints (file);
+
+      bp_set_iterator it = bp_set.find (fname);
+      if (it != bp_set.end ())
+        bp_set.erase (it);
+    }
+
+  return retval;
+}
 
 bp_table::intmap
 bp_table::do_remove_all_breakpoints_in_file (const std::string& fname,
@@ -417,17 +483,24 @@
 
   if (dbg_fcn)
     {
-      std::string file = dbg_fcn->fcn_file_name ();
+      retval = do_remove_all_breakpoints_in_file_1 (dbg_fcn, fname);
+
+      // Order is not important here.
 
-      tree_statement_list *cmds = dbg_fcn->body ();
+      typedef std::map<std::string, octave_value>::const_iterator
+        subfcns_const_iterator;
 
-      if (cmds)
+      std::map<std::string, octave_value> subfcns = dbg_fcn->subfunctions ();
+
+      for (subfcns_const_iterator p = subfcns.begin ();
+           p != subfcns.end (); p++)
         {
-          retval = cmds->remove_all_breakpoints (file);
+          octave_user_code *dbg_subfcn = p->second.user_code_value ();
 
-          bp_set_iterator it = bp_set.find (fname);
-          if (it != bp_set.end ())
-            bp_set.erase (it);
+          intmap tmp = do_remove_all_breakpoints_in_file_1 (dbg_subfcn, fname);
+
+          // Merge new list with retval.
+          retval.insert (tmp.begin (), tmp.end ());
         }
     }
   else if (! silent)
--- a/libinterp/interpfcn/debug.h	Wed May 08 14:57:33 2013 -0400
+++ b/libinterp/interpfcn/debug.h	Wed May 08 14:57:45 2013 -0400
@@ -120,8 +120,14 @@
 
   intmap do_add_breakpoint (const std::string& fname, const intmap& lines);
 
+  int do_remove_breakpoint_1 (octave_user_code *fcn, const std::string&,
+                              const intmap& lines);
+
   int do_remove_breakpoint (const std::string&, const intmap& lines);
 
+  intmap do_remove_all_breakpoints_in_file_1 (octave_user_code *fcn,
+                                              const std::string& fname);
+
   intmap do_remove_all_breakpoints_in_file (const std::string& fname,
                                             bool silent);
 
--- a/libinterp/interpfcn/load-save.h	Wed May 08 14:57:33 2013 -0400
+++ b/libinterp/interpfcn/load-save.h	Wed May 08 14:57:45 2013 -0400
@@ -83,7 +83,7 @@
          bool list_only, bool swap, bool verbose,
          const string_vector& argv, int argv_idx, int argc, int nargout);
 
-extern bool is_octave_data_file (const std::string& file);
+extern OCTINTERP_API bool is_octave_data_file (const std::string& file);
 
 extern void
 do_save (std::ostream& os, const symbol_table::symbol_record& sr,
--- a/libinterp/interpfcn/octave-link.h	Wed May 08 14:57:33 2013 -0400
+++ b/libinterp/interpfcn/octave-link.h	Wed May 08 14:57:45 2013 -0400
@@ -41,7 +41,9 @@
 // buffering access operations to octave and executing them in the
 // readline event hook, which lives in the octave thread.
 
-class octave_link
+class
+OCTINTERP_API
+octave_link
 {
 protected:
 
--- a/libinterp/octave-value/ov-fcn.h	Wed May 08 14:57:33 2013 -0400
+++ b/libinterp/octave-value/ov-fcn.h	Wed May 08 14:57:45 2013 -0400
@@ -134,6 +134,18 @@
 
   virtual void unlock_subfunctions (void) { }
 
+  virtual void maybe_relocate_end (void) { }
+
+  // Not valid until after the function is completley parsed.
+  virtual bool has_subfunctions (void) const { return false; }
+
+  virtual void stash_subfunction_names (const std::list<std::string>&) { }
+
+  virtual std::list<std::string> subfunction_names (void) const
+  {
+    return std::list<std::string> ();
+  }
+
   void mark_relative (void) { relative = true; }
 
   bool is_relative (void) const { return relative; }
--- a/libinterp/octave-value/ov-usr-fcn.cc	Wed May 08 14:57:33 2013 -0400
+++ b/libinterp/octave-value/ov-usr-fcn.cc	Wed May 08 14:57:45 2013 -0400
@@ -248,6 +248,70 @@
   file_name = nm;
 }
 
+// If there is no explicit end statement at the end of the function,
+// relocate the no_op that was generated for the end of file condition
+// to appear on the next line after the last statement in the file, or
+// the next line after the function keyword if there are no statements.
+// More precisely, the new location should probably be on the next line
+// after the end of the parameter list, but we aren't tracking that
+// information (yet).
+
+void
+octave_user_function::maybe_relocate_end_internal (void)
+{
+  if (cmd_list && ! cmd_list->empty ())
+    {
+      tree_statement *last_stmt = cmd_list->back ();
+
+      if (last_stmt && last_stmt->is_end_of_fcn_or_script ()
+          && last_stmt->is_end_of_file ())
+        {
+          tree_statement_list::reverse_iterator
+            next_to_last_elt = cmd_list->rbegin ();
+
+          next_to_last_elt++;
+
+          int new_eof_line;
+          int new_eof_col;
+
+          if (next_to_last_elt == cmd_list->rend ())
+            {
+              new_eof_line = beginning_line ();
+              new_eof_col = beginning_column ();
+            }
+          else
+            {
+              tree_statement *next_to_last_stmt = *next_to_last_elt;
+
+              new_eof_line = next_to_last_stmt->line ();
+              new_eof_col = next_to_last_stmt->column ();
+            }
+
+          last_stmt->set_location (new_eof_line + 1, new_eof_col);
+        }
+    }
+}
+
+void
+octave_user_function::maybe_relocate_end (void)
+{
+  std::map<std::string, octave_value> fcns = subfunctions ();
+
+  if (! fcns.empty ())
+    {
+      for (std::map<std::string, octave_value>::iterator p = fcns.begin ();
+           p != fcns.end (); p++)
+        {
+          octave_user_function *f = (p->second).user_function_value ();
+
+          if (f)
+            f->maybe_relocate_end_internal ();
+        }
+    }
+
+  maybe_relocate_end_internal ();
+}
+
 std::string
 octave_user_function::profiler_name (void) const
 {
@@ -320,6 +384,19 @@
   return symbol_table::subfunctions_defined_in_scope (local_scope);
 }
 
+bool
+octave_user_function::has_subfunctions (void) const
+{
+  return ! subfcn_names.empty ();
+}
+
+void
+octave_user_function::stash_subfunction_names
+  (const std::list<std::string>& names)
+{
+  subfcn_names = names;
+}
+
 octave_value_list
 octave_user_function::all_va_args (const octave_value_list& args)
 {
--- a/libinterp/octave-value/ov-usr-fcn.h	Wed May 08 14:57:33 2013 -0400
+++ b/libinterp/octave-value/ov-usr-fcn.h	Wed May 08 14:57:45 2013 -0400
@@ -208,6 +208,20 @@
       location_column = col;
     }
 
+  int beginning_line (void) const { return location_line; }
+  int beginning_column (void) const { return location_column; }
+
+  void stash_fcn_end_location (int line, int col)
+    {
+      end_location_line = line;
+      end_location_column = col;
+    }
+
+  int ending_line (void) const { return end_location_line; }
+  int ending_column (void) const { return end_location_column; }
+
+  void maybe_relocate_end (void);
+
   void stash_parent_fcn_name (const std::string& p) { parent_name = p; }
 
   void stash_parent_fcn_scope (symbol_table::scope_id ps) { parent_scope = ps; }
@@ -266,6 +280,15 @@
 
   std::map<std::string, octave_value> subfunctions (void) const;
 
+  bool has_subfunctions (void) const;
+
+  void stash_subfunction_names (const std::list<std::string>& names);
+
+  std::list<std::string> subfunction_names (void) const
+  {
+    return subfcn_names;
+  }
+
   octave_value_list all_va_args (const octave_value_list& args);
 
   void stash_function_name (const std::string& s) { my_name = s; }
@@ -406,10 +429,16 @@
   // Location where this function was defined.
   int location_line;
   int location_column;
+  int end_location_line;
+  int end_location_column;
 
   // The name of the parent function, if any.
   std::string parent_name;
 
+  // The list of subfunctions (if any) in the order they appear in the
+  // file.
+  std::list<std::string> subfcn_names;
+
   // The time the file was parsed.
   octave_time t_parsed;
 
@@ -458,6 +487,8 @@
   jit_function_info *jit_info;
 #endif
 
+  void maybe_relocate_end_internal (void);
+
   void print_code_function_header (void);
 
   void print_code_function_trailer (void);
--- a/libinterp/parse-tree/oct-parse.in.yy	Wed May 08 14:57:33 2013 -0400
+++ b/libinterp/parse-tree/oct-parse.in.yy	Wed May 08 14:57:45 2013 -0400
@@ -219,14 +219,16 @@
 %token <tok_val> METAQUERY
 %token <tok_val> SUPERCLASSREF
 %token <tok_val> GET SET
+%token <tok_val> FCN
 
 // Other tokens.
 %token END_OF_INPUT LEXICAL_ERROR
-%token FCN INPUT_FILE CLASSDEF
+%token INPUT_FILE CLASSDEF
 // %token VARARGIN VARARGOUT
 
 // Nonterminals we construct.
-%type <comment_type> stash_comment function_beg classdef_beg
+%type <tok_val> function_beg
+%type <comment_type> stash_comment classdef_beg
 %type <comment_type> properties_beg methods_beg events_beg enum_beg
 %type <sep_type> sep_no_nl opt_sep_no_nl nl opt_nl sep opt_sep
 %type <tree_type> input
@@ -1119,9 +1121,9 @@
                     if (! lexer.reading_fcn_file)
                       {
                         tree_statement *end_of_script
-                          = parser.make_end ("endscript",
-                                                  lexer.input_line_number,
-                                                  lexer.current_input_column);
+                          = parser.make_end ("endscript", true,
+                                             lexer.input_line_number,
+                                             lexer.current_input_column);
 
                         parser.make_script ($3, end_of_script);
                       }
@@ -1134,23 +1136,25 @@
 // Function definition
 // ===================
 
-function_beg    : push_fcn_symtab FCN stash_comment
+function_beg    : push_fcn_symtab FCN
                   {
-                    $$ = $3;
+                    $$ = $2;
                     if (lexer.reading_classdef_file
                         || lexer.parsing_classdef)
                       lexer.maybe_classdef_get_set_method = true;
                   }
                 ;
 
-function        : function_beg function1
+function        : function_beg stash_comment function1
                   {
-                    $$ = parser.finish_function (0, $2, $1);
+                    $$ = parser.finish_function (0, $3, $2, $1->line (),
+                                                 $1->column ());
                     parser.recover_from_parsing_function ();
                   }
-                | function_beg return_list '=' function1
+                | function_beg stash_comment return_list '=' function1
                   {
-                    $$ = parser.finish_function ($2, $4, $1);
+                    $$ = parser.finish_function ($3, $5, $2, $1->line (),
+                                                 $1->column ());
                     parser.recover_from_parsing_function ();
                   }
                 ;
@@ -1199,7 +1203,8 @@
                   {
                     parser.endfunction_found = true;
                     if (parser.end_token_ok ($1, token::function_end))
-                      $$ = parser.make_end ("endfunction", $1->line (), $1->column ());
+                      $$ = parser.make_end ("endfunction", false,
+                                            $1->line (), $1->column ());
                     else
                       ABORT_PARSE;
                   }
@@ -1233,9 +1238,9 @@
                         YYABORT;
                       }
 
-                    $$ = parser.make_end ("endfunction",
-                                                lexer.input_line_number,
-                                                lexer.current_input_column);
+                    $$ = parser.make_end ("endfunction", true,
+                                          lexer.input_line_number,
+                                          lexer.current_input_column);
                   }
                 ;
 
@@ -1255,7 +1260,8 @@
                     lexer.parsing_classdef = false;
 
                     if (parser.end_token_ok ($1, token::classdef_end))
-                      $$ = parser.make_end ("endclassdef", $1->line (), $1->column ());
+                      $$ = parser.make_end ("endclassdef", false,
+                                            $1->line (), $1->column ());
                     else
                       ABORT_PARSE;
                   }
@@ -1494,6 +1500,7 @@
   curr_class_name = "";
   function_scopes.clear ();
   primary_fcn_ptr  = 0;
+  subfunction_names.clear ();
 
   delete stmt_list;
   stmt_list = 0;
@@ -2598,15 +2605,17 @@
       octave_comment_list *tc = octave_comment_buffer::get_comment ();
 
       fcn->stash_trailing_comment (tc);
+      fcn->stash_fcn_end_location (end_fcn_stmt->line (),
+                                   end_fcn_stmt->column ());
     }
 
   return fcn;
 }
 
 tree_statement *
-octave_base_parser::make_end (const std::string& type, int l, int c)
+octave_base_parser::make_end (const std::string& type, bool eof, int l, int c)
 {
-  return make_statement (new tree_no_op_command (type, l, c));
+  return make_statement (new tree_no_op_command (type, eof, l, c));
 }
 
 // Do most of the work for defining a function.
@@ -2695,8 +2704,6 @@
     }
 
   fcn->stash_function_name (id_name);
-  fcn->stash_fcn_location (lexer.input_line_number,
-                           lexer.current_input_column);
 
   if (! lexer.help_text.empty () && curr_fcn_depth == 1
       && ! parsing_subfunctions)
@@ -2716,7 +2723,8 @@
 tree_function_def *
 octave_base_parser::finish_function (tree_parameter_list *ret_list,
                                      octave_user_function *fcn,
-                                     octave_comment_list *lc)
+                                     octave_comment_list *lc,
+                                     int l, int c)
 {
   tree_function_def *retval = 0;
 
@@ -2742,6 +2750,9 @@
       if (curr_fcn_depth > 1 || parsing_subfunctions)
         {
           fcn->mark_as_subfunction ();
+          fcn->stash_fcn_location (l, c);
+
+          subfunction_names.push_back (nm);
 
           if (endfunction_found && function_scopes.size () > 1)
             {
@@ -3301,6 +3312,19 @@
 
       fcn_ptr = parser.primary_fcn_ptr;
 
+      if (fcn_ptr)
+        {
+          fcn_ptr->maybe_relocate_end ();
+
+          if (parser.parsing_subfunctions)
+            {
+              if (! parser.endfunction_found)
+                parser.subfunction_names.reverse ();
+
+              fcn_ptr->stash_subfunction_names (parser.subfunction_names);
+            }
+        }
+
       if (status != 0)
         error ("parse error while reading file %s", full_file.c_str ());
     }
--- a/libinterp/parse-tree/parse.h	Wed May 08 14:57:33 2013 -0400
+++ b/libinterp/parse-tree/parse.h	Wed May 08 14:57:45 2013 -0400
@@ -136,7 +136,7 @@
       parsing_subfunctions (false), max_fcn_depth (0),
       curr_fcn_depth (0), primary_fcn_scope (-1),
       curr_class_name (), function_scopes (), primary_fcn_ptr (0),
-      stmt_list (0),
+      subfunction_names (), stmt_list (0),
       lexer (lxr)
   {
     init ();
@@ -270,7 +270,7 @@
                   tree_statement *end_function);
 
   // Create a no-op statement for end_function.
-  tree_statement *make_end (const std::string& type, int l, int c);
+  tree_statement *make_end (const std::string& type, bool eof, int l, int c);
 
   // Do most of the work for defining a function.
   octave_user_function *
@@ -279,7 +279,8 @@
   // Finish defining a function.
   tree_function_def *
   finish_function (tree_parameter_list *ret_list,
-                   octave_user_function *fcn, octave_comment_list *lc);
+                   octave_user_function *fcn, octave_comment_list *lc,
+                   int l, int c);
 
   // Reset state after parsing function.
   void
@@ -377,6 +378,11 @@
   // Pointer to the primary user function or user script function.
   octave_function *primary_fcn_ptr;
 
+  // List of subfunction names, initially in the order they are
+  // installed in the symbol table, then ordered as they appear in the
+  // file.  Eventually stashed in the primary function object.
+  std::list<std::string> subfunction_names;
+
   // Result of parsing input.
   tree_statement_list *stmt_list;
 
--- a/libinterp/parse-tree/pt-cmd.cc	Wed May 08 14:57:33 2013 -0400
+++ b/libinterp/parse-tree/pt-cmd.cc	Wed May 08 14:57:45 2013 -0400
@@ -33,7 +33,8 @@
 tree_no_op_command::dup (symbol_table::scope_id,
                          symbol_table::context_id) const
 {
-  return new tree_no_op_command (orig_cmd, line (), column ());
+  return new tree_no_op_command (orig_cmd, is_end_of_file (),
+                                 line (), column ());
 }
 
 void
--- a/libinterp/parse-tree/pt-cmd.h	Wed May 08 14:57:33 2013 -0400
+++ b/libinterp/parse-tree/pt-cmd.h	Wed May 08 14:57:45 2013 -0400
@@ -63,9 +63,9 @@
 {
 public:
 
-  tree_no_op_command (const std::string& cmd = "no_op", int l = -1, int c = -1)
-    : tree_command (l, c), eof (cmd == "endfunction" || cmd == "endscript"),
-      orig_cmd (cmd) { }
+  tree_no_op_command (const std::string& cmd = "no_op", bool e = false,
+                      int l = -1, int c = -1)
+    : tree_command (l, c), eof (e), orig_cmd (cmd) { }
 
   ~tree_no_op_command (void) { }
 
@@ -74,7 +74,12 @@
 
   void accept (tree_walker& tw);
 
-  bool is_end_of_fcn_or_script (void) const { return eof; }
+  bool is_end_of_fcn_or_script (void) const
+  {
+    return (orig_cmd == "endfunction" || orig_cmd == "endscript");
+  }
+
+  bool is_end_of_file (void) const { return eof; }
 
   std::string original_command (void) { return orig_cmd; }
 
--- a/libinterp/parse-tree/pt-stmt.cc	Wed May 08 14:57:33 2013 -0400
+++ b/libinterp/parse-tree/pt-stmt.cc	Wed May 08 14:57:45 2013 -0400
@@ -107,6 +107,15 @@
 }
 
 void
+tree_statement::set_location (int l, int c)
+{
+  if (cmd)
+    cmd->set_location (l, c);
+  else if (expr)
+    expr->set_location (l, c);
+}
+
+void
 tree_statement::echo_code (void)
 {
   tree_print_code tpc (octave_stdout, VPS4);
@@ -131,6 +140,23 @@
   return retval;
 }
 
+bool
+tree_statement::is_end_of_file (void) const
+{
+  bool retval = false;
+
+  if (cmd)
+    {
+      tree_no_op_command *no_op_cmd
+        = dynamic_cast<tree_no_op_command *> (cmd);
+
+      if (no_op_cmd)
+        retval = no_op_cmd->is_end_of_file ();
+    }
+
+  return retval;
+}
+
 tree_statement *
 tree_statement::dup (symbol_table::scope_id scope,
                      symbol_table::context_id context) const
--- a/libinterp/parse-tree/pt-stmt.h	Wed May 08 14:57:33 2013 -0400
+++ b/libinterp/parse-tree/pt-stmt.h	Wed May 08 14:57:45 2013 -0400
@@ -74,6 +74,8 @@
   int line (void) const;
   int column (void) const;
 
+  void set_location (int l, int c);
+
   void echo_code (void);
 
   tree_command *command (void) { return cmd; }
@@ -86,6 +88,8 @@
 
   bool is_end_of_fcn_or_script (void) const;
 
+  bool is_end_of_file (void) const;
+
   // Allow modification of this statement.  Note that there is no
   // checking.  If you use these, are you sure you knwo what you are
   // doing?
--- a/libinterp/parse-tree/pt.h	Wed May 08 14:57:33 2013 -0400
+++ b/libinterp/parse-tree/pt.h	Wed May 08 14:57:45 2013 -0400
@@ -50,6 +50,12 @@
 
   void column (int c) { column_num = c; }
 
+  void set_location (int l, int c)
+  {
+    line_num = l;
+    column_num = c;
+  }
+
   virtual void set_breakpoint (void) { bp = true; }
 
   virtual void delete_breakpoint (void) { bp = false; }
--- a/liboctave/util/base-list.h	Wed May 08 14:57:33 2013 -0400
+++ b/liboctave/util/base-list.h	Wed May 08 14:57:45 2013 -0400
@@ -36,6 +36,9 @@
   typedef typename std::list<elt_type>::iterator iterator;
   typedef typename std::list<elt_type>::const_iterator const_iterator;
 
+  typedef typename std::list<elt_type>::reverse_iterator reverse_iterator;
+  typedef typename std::list<elt_type>::const_reverse_iterator const_reverse_iterator;
+
   bool empty (void) const { return lst.empty (); }
 
   size_t size (void) const { return lst.size (); }
@@ -74,6 +77,12 @@
   iterator end (void) { return iterator (lst.end ()); }
   const_iterator end (void) const { return const_iterator (lst.end ()); }
 
+  reverse_iterator rbegin (void) { return reverse_iterator (lst.rbegin ()); }
+  const_reverse_iterator rbegin (void) const { return const_reverse_iterator (lst.rbegin ()); }
+
+  reverse_iterator rend (void) { return reverse_iterator (lst.rend ()); }
+  const_reverse_iterator rend (void) const { return const_reverse_iterator (lst.rend ()); }
+
   elt_type& front (void) { return lst.front (); }
   elt_type& back (void) { return lst.back (); }
 
--- a/src/mkoctfile.in.cc	Wed May 08 14:57:33 2013 -0400
+++ b/src/mkoctfile.in.cc	Wed May 08 14:57:45 2013 -0400
@@ -396,6 +396,13 @@
   return system (cmd.c_str ());
 }
 
+bool
+is_true (const std::string& s)
+{
+  return (s == "yes"
+          || s == "true");
+}
+
 int
 main (int argc, char **argv)
 {
@@ -414,7 +421,7 @@
   string ldflags = "";
   string pass_on_options = "";
   bool strip = false;
-  bool no_oct_file_strip_on_this_platform = %NO_OCT_FILE_STRIP%;
+  bool no_oct_file_strip_on_this_platform = is_true ("%NO_OCT_FILE_STRIP%");
   bool link = true;
   bool link_stand_alone = false;
   string output_ext = ".oct";