[PATCH 3/3] Add console widget to DBGPerspective



    * configure.ac: Check for readline dependency.
    * src/persp/dbgperspective/Makefile.am: Add new files.
    * src/persp/dbgperspective/menus/menus.xml: Add Console menu.
    * src/persp/dbgperspective/nmv-console.cc: New APIs.
    * src/persp/dbgperspective/nmv-console.h: New APIs.
    * src/persp/dbgperspective/nmv-dbg-perspective.cc
    (DBGPerspective::OpenCommand): New APIs.
    (DBGPerspective::on_activate_console_view): New API.
    (DBGPerspective::dbg_console): New API.
    (DBGPerspective::console_box): New API.
    (DBGPerspective::on_switch_page_signal): Notify the console of the
    change of the currently focused source file.
    (DBGPerspective::init_actions): Add action for console menu.
    (DBGPerspective::add_views_to_layout): Add console to layout manager.
    (DBGPerspective::execute_commands_from_line): Removed.
    (DBGPerspective::execute_commands_from_file): Delegate the execution
    of commands to the console.
    (DBGPerspective::execute_commands_from_fd): Delegate the execution
    of commands to the console.
    * src/persp/dbgperspective/nmv-dbg-perspective.h
    (ViewsIndex::CONSOLE_VIEW_INDEX): Add view index for the console.
    * src/uicommon/nmv-terminal.cc (Terminal::slave_fd): New API.
    * src/uicommon/nmv-terminal.h (Terminal::slave_fd): New API.
---
 configure.ac                                    |   3 +-
 src/persp/dbgperspective/Makefile.am            |   4 +-
 src/persp/dbgperspective/menus/menus.xml        |   2 +
 src/persp/dbgperspective/nmv-console.cc         | 440 ++++++++++++++++++++++++
 src/persp/dbgperspective/nmv-console.h          | 100 ++++++
 src/persp/dbgperspective/nmv-dbg-perspective.cc | 219 +++++++++---
 src/persp/dbgperspective/nmv-dbg-perspective.h  |   4 +-
 src/uicommon/nmv-terminal.cc                    |   6 +
 src/uicommon/nmv-terminal.h                     |   1 +
 9 files changed, 723 insertions(+), 56 deletions(-)
 create mode 100644 src/persp/dbgperspective/nmv-console.cc
 create mode 100644 src/persp/dbgperspective/nmv-console.h

diff --git a/configure.ac b/configure.ac
index d5d6ad5..7e219b0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -378,8 +378,9 @@ dnl library dependencies for the nemiver debug perspective plugin
 DEP_PERSP="gtksourceviewmm-3.0 >= $LIBGTKSOURCEVIEWMM_VERSION \
            vte-2.90 >= $LIBVTE_VERSION"
 
+AC_CHECK_FUNCS(readline)
 PKG_CHECK_MODULES(NEMIVERDBGPERSP, $DEP_UICOMMON $DEP_VFS $DEP_PERSP $DEP_MEMORYVIEW $DEP_DYNAMICLAYOUT)
-NEMIVERDBGPERSP_LIBS="$NEMIVERDBGPERSP_LIBS $CPPUNIT_LIBS"
+NEMIVERDBGPERSP_LIBS="$NEMIVERDBGPERSP_LIBS $CPPUNIT_LIBS -lreadline"
 NEMIVERDBGPERSP_CFLAGS="$NEMIVERDBGPERSP_CFLAGS $CPPUNIT_CFLAGS"
 
 AC_SUBST(NEMIVERDBGPERSP_LIBS)
diff --git a/src/persp/dbgperspective/Makefile.am b/src/persp/dbgperspective/Makefile.am
index d6913d4..e497ae5 100644
--- a/src/persp/dbgperspective/Makefile.am
+++ b/src/persp/dbgperspective/Makefile.am
@@ -75,7 +75,9 @@ $(h)/nmv-dbg-perspective-default-layout.h \
 $(h)/nmv-dbg-perspective-two-pane-layout.cc \
 $(h)/nmv-dbg-perspective-two-pane-layout.h \
 $(h)/nmv-dbg-perspective-wide-layout.cc \
-$(h)/nmv-dbg-perspective-wide-layout.h
+$(h)/nmv-dbg-perspective-wide-layout.h \
+$(h)/nmv-console.cc \
+$(h)/nmv-console.h
 
 if BUILD_DYNAMICLAYOUT
 dynamiclayout_sources = \
diff --git a/src/persp/dbgperspective/menus/menus.xml b/src/persp/dbgperspective/menus/menus.xml
index 337838a..4f34a4d 100644
--- a/src/persp/dbgperspective/menus/menus.xml
+++ b/src/persp/dbgperspective/menus/menus.xml
@@ -47,6 +47,8 @@
                 name="ActivateRegistersViewMenuItem"/>
            <menuitem action="ActivateExprMonitorViewMenuAction"
                 name="ActivateExprMonitorViewMenuItem"/>
+            <menuitem action="ActivateConsoleViewMenuAction"
+                name="ActivateConsoleViewMenuItem"/>
         </menu>
         <menu action="DebugMenuAction" name="DebugMenu">
             <menuitem action="RunMenuItemAction" name="RunMenuItem"/>
diff --git a/src/persp/dbgperspective/nmv-console.cc b/src/persp/dbgperspective/nmv-console.cc
new file mode 100644
index 0000000..6cbcbfa
--- /dev/null
+++ b/src/persp/dbgperspective/nmv-console.cc
@@ -0,0 +1,440 @@
+//Author: Fabien Parent
+/*
+ *This file is part of the Nemiver project
+ *
+ *Nemiver is free software; you can redistribute
+ *it and/or modify it under the terms of
+ *the GNU General Public License as published by the
+ *Free Software Foundation; either version 2,
+ *or (at your option) any later version.
+ *
+ *Nemiver is distributed in the hope that it will
+ *be useful, but WITHOUT ANY WARRANTY;
+ *without even the implied warranty of
+ *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *See the GNU General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with Nemiver;
+ *see the file COPYING.
+ *If not, write to the Free Software Foundation,
+ *Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *See COPYRIGHT file copyright information.
+ */
+
+#define USE_VARARGS
+#define PREFER_STDARG
+
+#include "nmv-console.h"
+#include "common/nmv-str-utils.h"
+#include "uicommon/nmv-terminal.h"
+#include "dbgengine/nmv-cmd-interpreter.h"
+#include "dbgengine/nmv-i-debugger.h"
+#include <vector>
+#include <cstring>
+#include <fstream>
+#include <cctype>
+#include <readline/readline.h>
+#include <readline/history.h>
+#include <fcntl.h>
+
+NEMIVER_BEGIN_NAMESPACE(nemiver)
+
+const char *const CONSOLE_PROMPT = "(nemiver) ";
+
+struct Console::Priv {
+    Terminal terminal;
+    Console::Stream stream;
+    CmdInterpreter cmd_interpreter;
+    Glib::RefPtr<Glib::IOSource> io_source;
+    IDebugger &debugger;
+
+    struct readline_state console_state;
+    struct readline_state saved_state;
+
+    Priv (IDebugger &a_debugger,
+          const std::string &a_menu_file_path,
+          const Glib::RefPtr<Gtk::UIManager> &a_ui_manager) :
+        terminal (a_menu_file_path, a_ui_manager),
+        stream (terminal.slave_fd ()),
+        cmd_interpreter (a_debugger, stream),
+        io_source (Glib::IOSource::create (terminal.slave_fd (), Glib::IO_IN)),
+        debugger (a_debugger)
+    {
+        init ();
+    }
+
+    void
+    init ()
+    {
+        int fd = terminal.slave_fd ();
+        THROW_IF_FAIL (fd);
+        if (consoles ().count (fd)) {
+            THROW ("Cannot create two consoles from the same file descriptor.");
+        }
+        consoles ()[fd] = this;
+
+        cmd_interpreter.ready_signal ().connect
+            (sigc::mem_fun (*this, &Console::Priv::on_ready_signal));
+
+        io_source->connect (sigc::mem_fun (*this, &Console::Priv::read_char));
+        io_source->attach ();
+
+        rl_save_state (&saved_state);
+        rl_instream = fdopen (fd, "r");
+        rl_outstream = fdopen (fd, "w");
+        rl_bind_key ('\t', &Console::Priv::on_tab_key_pressed);
+        rl_callback_handler_install (CONSOLE_PROMPT,
+                                     &Console::Priv::process_command);
+        rl_already_prompted = true;
+        rl_save_state (&console_state);
+        rl_restore_state (&saved_state);
+    }
+
+    void
+    on_ready_signal ()
+    {
+        stream << CONSOLE_PROMPT;
+    }
+
+    bool
+    read_char (Glib::IOCondition)
+    {
+        NEMIVER_TRY;
+
+        if (!cmd_interpreter.ready ())
+            return false;
+
+        rl_restore_state (&console_state);
+        rl_callback_read_char ();
+        rl_save_state (&console_state);
+        rl_restore_state (&saved_state);
+
+        NEMIVER_CATCH_NOX;
+
+        return true;
+    }
+
+    void
+    do_completion (const std::string &a_completion)
+    {
+        size_t buffer_length = std::strlen (rl_line_buffer);
+        rl_extend_line_buffer (buffer_length + a_completion.size ());
+        std::memcpy (rl_line_buffer + rl_point + a_completion.size (),
+                     rl_line_buffer + rl_point,
+                     a_completion.size ());
+        for (size_t i = 0; i < a_completion.size(); i++) {
+            rl_line_buffer[rl_point + i] = a_completion[i];
+        }
+        rl_end += a_completion.size ();
+        rl_point += a_completion.size ();
+    }
+
+    void
+    display_message (const std::string &a_msg)
+    {
+        rl_save_prompt ();
+        rl_message ("%s%s\n",
+                    CONSOLE_PROMPT,
+                    std::string (rl_line_buffer, rl_end).c_str ());
+
+        std::istringstream iss (a_msg);
+        std::string line;
+        while (std::getline (iss, line)) {
+            line += '\n';
+            rl_message ("%s", line.c_str ());
+        }
+
+        rl_message ("%s", CONSOLE_PROMPT);
+        rl_restore_prompt ();
+        rl_clear_message ();
+    }
+
+    void
+    display_completion (const std::vector<std::string> &a_completions)
+    {
+        std::ostringstream msg;
+
+        for (size_t i = 0; i < a_completions.size (); i++) {
+            if ((i + 1) % 5) {
+                msg.width (16);
+                msg.fill (' ');
+                msg << std::left << a_completions[i];
+            } else {
+                msg << a_completions[i] << '\n';
+            }
+        }
+
+        if (msg.str ()[msg.str ().size () - 1] != '\n') {
+            msg << '\n';
+        }
+
+        display_message (msg.str ());
+    }
+
+    void
+    do_command_completion (const std::string &a_line)
+    {
+        const std::vector<CmdInterpreter::Command*> &commands =
+            cmd_interpreter.commands ();
+
+        std::vector<CmdInterpreter::Command*> matches;
+        for (std::vector<CmdInterpreter::Command*>::const_iterator iter =
+                commands.begin ();
+             iter != commands.end ();
+             ++iter) {
+            if (*iter && !(*iter)->name ().find (a_line)) {
+                matches.push_back (*iter);
+            }
+        }
+
+        if (!matches.size ()) {
+            return;
+        }
+
+        std::string completion = matches[0]->name ();
+        if (matches.size () > 1) {
+            std::vector<std::string> completions;
+            for (size_t i = 0; i < matches.size (); i++) {
+                size_t j = a_line.size ();
+                for (;
+                     j < matches[i]->name ().size ()
+                        && j < completion.size ()
+                        && matches[i]->name ()[j] == completion[j];
+                     j++) {
+                }
+                completion = completion.substr (0, j);
+                completions.push_back (matches[i]->name ());
+            }
+
+            display_completion (completions);
+        }
+        do_completion (completion.substr (a_line.size ()));
+    }
+
+    void
+    do_param_completion (std::vector<UString> &a_tokens)
+    {
+        if (!a_tokens.size ()) {
+            return;
+        }
+
+        const std::vector<CmdInterpreter::Command*> &commands =
+            cmd_interpreter.commands ();
+
+        CmdInterpreter::Command* command = 0;
+        for (std::vector<CmdInterpreter::Command*>::const_iterator iter =
+                commands.begin ();
+             iter != commands.end ();
+             ++iter) {
+            if (*iter && (*iter)->name () == a_tokens[0]) {
+                command = *iter;
+                break;
+            }
+        }
+
+        if (!command) {
+            return;
+        }
+
+        a_tokens.erase (a_tokens.begin ());
+        std::string line (rl_line_buffer, rl_point);
+        if (std::isspace (line[line.size () - 1])) {
+            stream << "\n";
+            command->display_usage (a_tokens, stream);
+            rl_forced_update_display ();
+        } else {
+            UString token = a_tokens.back ();
+            a_tokens.pop_back ();
+
+            std::vector<UString> completions;
+            std::vector<UString> matches;
+            command->completions (a_tokens, completions);
+            for (std::vector<UString>::iterator iter = completions.begin ();
+                 iter != completions.end ();
+                 ++iter) {
+                if (!iter->find (token)) {
+                    matches.push_back (*iter);
+                }
+            }
+
+            if (matches.size () == 1) {
+                std::string completion = matches[0].substr (token.size ());
+                do_completion (completion);
+            } else if (matches.size () > 1) {
+                std::vector<std::string> comps;
+                UString completion = matches[0];
+                for (size_t i = 0; i < matches.size (); i++) {
+                    size_t j = token.size ();
+                    for (; j < matches[i].size ()
+                                && j < completion.size ()
+                                && matches[i][j] == completion[j];
+                         j++) {
+                    }
+                    completion = completion.substr (0, j);
+                    comps.push_back (matches[i]);
+                }
+
+                display_completion (comps);
+                do_completion (completion.substr (token.size ()));
+            } else {
+                rl_complete (0, '\t');
+            }
+        }
+    }
+
+    static int
+    on_tab_key_pressed (int, int)
+    {
+        NEMIVER_TRY;
+
+        std::string line (rl_line_buffer, rl_point);
+        std::vector<UString> tokens_raw = str_utils::split (line, " ");
+        std::vector<UString> tokens;
+        for (size_t i = 0; i < tokens_raw.size (); i++) {
+            if (tokens_raw[i].size ()) {
+                tokens.push_back (tokens_raw[i]);
+            }
+        }
+
+        if (std::isspace (line[line.size () - 1]) || tokens.size () > 1) {
+            self ().do_param_completion (tokens);
+        } else {
+            self ().do_command_completion (line);
+        }
+
+        NEMIVER_CATCH_NOX;
+
+        return 0;
+    }
+
+    static std::map<int, Console::Priv*>& consoles ()
+    {
+        static std::map<int, Console::Priv*> s_consoles;
+        return s_consoles;
+    }
+
+    static Console::Priv& self ()
+    {
+        int fd = fileno (rl_instream);
+        THROW_IF_FAIL (fd);
+        THROW_IF_FAIL (consoles ().count (fd));
+        Console::Priv *self = consoles ()[fd];
+        THROW_IF_FAIL (self);
+        return *self;
+    }
+
+    static void
+    process_command (char *a_command)
+    {
+        NEMIVER_TRY;
+
+        THROW_IF_FAIL (a_command);
+        add_history (a_command);
+        self ().cmd_interpreter.execute_command (a_command);
+
+        NEMIVER_CATCH_NOX;
+
+        free (a_command);
+    }
+};
+
+Console::Console (IDebugger &a_debugger,
+                  const std::string &a_menu_file_path,
+                  const Glib::RefPtr<Gtk::UIManager> &a_ui_manager) :
+    m_priv (new Priv (a_debugger, a_menu_file_path, a_ui_manager))
+{
+}
+
+Console::~Console ()
+{
+}
+
+void
+Console::execute_commands_from_file (const UString &a_file)
+{
+    std::ifstream file (a_file.c_str ());
+    while (file.good ()) {
+        std::string line;
+        std::getline (file, line);
+        execute_line (line);
+    }
+    file.close ();
+}
+
+void
+Console::execute_commands_from_fd (int a_fd)
+{
+    struct File {
+        FILE *fd;
+        char buffer[4096];
+
+        explicit File (int a_fd) :
+            fd (fdopen (dup (a_fd), "r"))
+        {
+            THROW_IF_FAIL (fd);
+            int flags = fcntl (fileno (fd), F_GETFL, 0);
+            fcntl (fileno (fd), F_SETFL, flags | O_NONBLOCK);
+        }
+
+        ~File ()
+        {
+            if (fd) {
+                fclose (fd);
+            }
+        }
+    } file (a_fd);
+
+    while (fgets (file.buffer, sizeof (file.buffer), file.fd)) {
+        execute_line (file.buffer);
+    }
+}
+
+void
+Console::execute_line (const UString &a_line)
+{
+    std::vector<UString> commands = str_utils::split (a_line, ";");
+    for (std::vector<UString>::iterator iter = commands.begin ();
+         iter != commands.end ();
+         ++iter) {
+        str_utils::chomp (*iter);
+        execute_command (*iter);
+    }
+}
+
+void
+Console::execute_command (const UString &a_command)
+{
+    THROW_IF_FAIL (m_priv);
+
+    rl_restore_state (&m_priv->console_state);
+
+    add_history (a_command.c_str ());
+    if (!m_priv->cmd_interpreter.ready ()) {
+        m_priv->stream << CONSOLE_PROMPT;
+    }
+    m_priv->stream << a_command << "\n";
+
+    rl_save_state (&m_priv->console_state);
+    rl_restore_state (&m_priv->saved_state);
+
+    m_priv->cmd_interpreter.execute_command (a_command);
+}
+
+CmdInterpreter&
+Console::command_interpreter() const
+{
+    THROW_IF_FAIL (m_priv);
+    return m_priv->cmd_interpreter;
+}
+
+Terminal&
+Console::terminal () const
+{
+    THROW_IF_FAIL (m_priv);
+    return m_priv->terminal;
+}
+
+NEMIVER_END_NAMESPACE(nemiver)
+
diff --git a/src/persp/dbgperspective/nmv-console.h b/src/persp/dbgperspective/nmv-console.h
new file mode 100644
index 0000000..225b6a0
--- /dev/null
+++ b/src/persp/dbgperspective/nmv-console.h
@@ -0,0 +1,100 @@
+//Author: Fabien Parent
+/*
+ *This file is part of the Nemiver project
+ *
+ *Nemiver is free software; you can redistribute
+ *it and/or modify it under the terms of
+ *the GNU General Public License as published by the
+ *Free Software Foundation; either version 2,
+ *or (at your option) any later version.
+ *
+ *Nemiver is distributed in the hope that it will
+ *be useful, but WITHOUT ANY WARRANTY;
+ *without even the implied warranty of
+ *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *See the GNU General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with Nemiver;
+ *see the file COPYING.
+ *If not, write to the Free Software Foundation,
+ *Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *See COPYRIGHT file copyright information.
+ */
+#ifndef __NMV_CONSOLE_H__
+#define __NMV_CONSOLE_H__
+
+#include "common/nmv-safe-ptr.h"
+#include "common/nmv-namespace.h"
+#include "common/nmv-exception.h"
+#include <gtkmm/uimanager.h>
+#include <string>
+#include <vector>
+#include <ostream>
+
+NEMIVER_BEGIN_NAMESPACE(nemiver)
+
+class IDebugger;
+class CmdInterpreter;
+class Terminal;
+
+using nemiver::common::SafePtr;
+using nemiver::common::UString;
+
+class Console {
+    //non copyable
+    Console (const Console&);
+    Console& operator= (const Console&);
+
+    struct Priv;
+    SafePtr<Priv> m_priv;
+
+    struct StreamBuf : public std::streambuf {
+        int fd;
+
+        StreamBuf () :
+            fd (0)
+        {
+        }
+
+        StreamBuf (int a_fd) :
+            fd (a_fd)
+        {
+        }
+
+        virtual std::streamsize
+        xsputn (const char *a_string, std::streamsize a_size)
+        {
+            THROW_IF_FAIL (fd);
+            return ::write (fd, a_string, a_size);
+        }
+    };
+
+public:
+    class Stream : public std::ostream {
+        StreamBuf streambuf;
+    public:
+        explicit Stream (int a_fd) :
+            std::ostream (&streambuf),
+            streambuf (a_fd)
+        {
+        }
+    };
+
+    Console (IDebugger &a_debugger,
+             const std::string &a_menu_file_path,
+             const Glib::RefPtr<Gtk::UIManager> &a_ui_manager);
+    ~Console ();
+    void execute_commands_from_file (const UString &a_file);
+    void execute_commands_from_fd (int a_fd);
+    void execute_line (const UString &a_command);
+    void execute_command (const UString &a_command);
+    CmdInterpreter& command_interpreter() const;
+    Terminal& terminal () const;
+};
+
+NEMIVER_END_NAMESPACE(nemiver)
+
+#endif /* __NMV_CONSOLE_H__ */
+
diff --git a/src/persp/dbgperspective/nmv-dbg-perspective.cc b/src/persp/dbgperspective/nmv-dbg-perspective.cc
index 669b391..b963145 100644
--- a/src/persp/dbgperspective/nmv-dbg-perspective.cc
+++ b/src/persp/dbgperspective/nmv-dbg-perspective.cc
@@ -101,6 +101,7 @@
 #include "nmv-layout-manager.h"
 #include "nmv-expr-monitor.h"
 #include "nmv-cmd-interpreter.h"
+#include "nmv-console.h"
 
 using namespace std;
 using namespace nemiver::common;
@@ -124,6 +125,7 @@ const char *BREAKPOINTS_VIEW_TITLE       = _("Breakpoints");
 const char *REGISTERS_VIEW_TITLE         = _("Registers");
 const char *MEMORY_VIEW_TITLE            = _("Memory");
 const char *EXPR_MONITOR_VIEW_TITLE      = _("Expression Monitor");
+const char *CONSOLE_VIEW_TITLE           = _("Console");
 
 const char *CAPTION_SESSION_NAME = "captionname";
 const char *SESSION_NAME = "sessionname";
@@ -173,6 +175,77 @@ class DBGPerspective : public IDBGPerspective, public sigc::trackable {
 
 private:
 
+    struct OpenCommand : public CmdInterpreter::Command {
+
+        DBGPerspective& dbg_perspective;
+        std::vector<UString> source_files;
+
+        OpenCommand (DBGPerspective& a_dbg_perspective) :
+            dbg_perspective (a_dbg_perspective)
+        {
+            init_signals ();
+        }
+
+        void
+        init_signals ()
+        {
+            IDebuggerSafePtr debugger = dbg_perspective.debugger ();
+            THROW_IF_FAIL (debugger);
+            debugger->files_listed_signal ().connect (sigc::mem_fun
+                (*this, &OpenCommand::on_files_listed_signal));
+        }
+
+        void
+        on_files_listed_signal (const std::vector<UString> &a_files,
+                                const UString&)
+        {
+            source_files = a_files;
+        }
+
+        const std::string&
+        name () const
+        {
+            static const std::string &s_name = "open";
+            return s_name;
+        }
+
+        const std::vector<UString>&
+        aliases () const
+        {
+            static std::vector<UString> s_aliases;
+            if (!s_aliases.size ()) {
+                s_aliases.push_back ("o");
+            }
+            return s_aliases;
+        }
+
+        void
+        completions (const std::vector<UString>&,
+                     std::vector<UString> &a_completion_vector) const
+        {
+            a_completion_vector.insert (a_completion_vector.begin (),
+                                        source_files.begin (),
+                                        source_files.end ());
+        }
+
+        bool
+        execute (const std::vector<UString> &a_argv, std::ostream&)
+        {
+            for (std::vector<UString>::const_iterator iter = a_argv.begin ();
+                 iter != a_argv.end ();
+                 ++iter) {
+                UString path = *iter;
+                if (path.size () && path[0] == '~') {
+                    path = path.replace (0, 1, Glib::get_home_dir ());
+                }
+
+                dbg_perspective.open_file (path, -1);
+            }
+
+            return true;
+        }
+    };
+
     struct SlotedButton : Gtk::Button {
         UString file_path;
         DBGPerspective *perspective;
@@ -431,6 +504,7 @@ private:
     void on_activate_memory_view ();
 #endif // WITH_MEMORYVIEW
     void on_activate_expr_monitor_view ();
+    void on_activate_console_view ();
     void on_activate_global_variables ();
     void on_default_config_read ();
 
@@ -763,6 +837,10 @@ public:
 
     Gtk::ScrolledWindow& get_local_vars_inspector_scrolled_win ();
 
+    Console& dbg_console ();
+
+    Gtk::Box& console_box ();
+
     Terminal& get_terminal ();
 
     Gtk::Box& get_terminal_box ();
@@ -930,7 +1008,9 @@ struct DBGPerspective::Priv {
     Path2MonitorMap path_2_monitor_map;
     SafePtr<LocalVarsInspector> variables_editor;
     SafePtr<Gtk::ScrolledWindow> variables_editor_scrolled_win;
-    SafePtr<CmdInterpreter> interpreter;
+    SafePtr<Console> dbg_console;
+    CmdInterpreter::CommandSafePtr open_command;
+    SafePtr<Gtk::Box> console_box;
     SafePtr<Terminal> terminal;
     SafePtr<Gtk::Box> terminal_box;
     SafePtr<Gtk::ScrolledWindow> breakpoints_scrolled_win;
@@ -1840,6 +1920,17 @@ DBGPerspective::on_switch_page_signal (Gtk::Widget *a_page,
     NEMIVER_TRY
     m_priv->current_page_num = a_page_num;
     LOG_DD ("current_page_num: " << m_priv->current_page_num);
+
+    map<int, SourceEditor*>::iterator iter, nil;
+    nil = m_priv->pagenum_2_source_editor_map.end ();
+    iter = m_priv->pagenum_2_source_editor_map.find (m_priv->current_page_num);
+    if (iter != nil) {
+        SourceEditor *editor = get_current_source_editor ();
+        if (editor) {
+            dbg_console ().command_interpreter ().current_file_path
+                (editor->get_path ());
+        }
+    }
     NEMIVER_CATCH
 }
 
@@ -2916,6 +3007,19 @@ DBGPerspective::on_activate_target_terminal_view ()
 }
 
 void
+DBGPerspective::on_activate_console_view ()
+{
+    LOG_FUNCTION_SCOPE_NORMAL_DD;
+
+    NEMIVER_TRY;
+
+    THROW_IF_FAIL (m_priv);
+    m_priv->layout ().activate_view (CONSOLE_VIEW_INDEX);
+
+    NEMIVER_CATCH;
+}
+
+void
 DBGPerspective::on_activate_breakpoints_view ()
 {
     LOG_FUNCTION_SCOPE_NORMAL_DD;
@@ -3596,6 +3700,17 @@ DBGPerspective::init_actions ()
             false
         },
         {
+            "ActivateConsoleViewMenuAction",
+            nil_stock_id,
+            CONSOLE_VIEW_TITLE,
+            _("Switch to Console View"),
+            sigc::mem_fun (*this,
+                           &DBGPerspective::on_activate_console_view),
+            ActionEntry::DEFAULT,
+            "<alt>7",
+            false
+        },
+        {
             "DebugMenuAction",
             nil_stock_id,
             _("_Debug"),
@@ -5149,6 +5264,9 @@ DBGPerspective::add_views_to_layout ()
     m_priv->layout ().append_view (get_expr_monitor_view ().widget (),
                                    EXPR_MONITOR_VIEW_TITLE,
                                    EXPR_MONITOR_VIEW_INDEX);
+    m_priv->layout ().append_view (console_box (),
+                                   CONSOLE_VIEW_TITLE,
+                                   CONSOLE_VIEW_INDEX);
     m_priv->layout ().do_init ();
 
 }
@@ -5889,68 +6007,20 @@ DBGPerspective::session_manager ()
 }
 
 void
-DBGPerspective::execute_commands_from_line (const UString &a_line)
-{
-    THROW_IF_FAIL (debugger ());
-
-    if (!m_priv->interpreter) {
-        m_priv->interpreter.reset
-            (new CmdInterpreter (*debugger (), std::cout));
-    }
-
-    THROW_IF_FAIL (m_priv->interpreter);
-
-    std::vector<UString> commands = str_utils::split (a_line, ";");
-    for (std::vector<UString>::iterator iter = commands.begin ();
-         iter != commands.end ();
-         ++iter) {
-        str_utils::chomp (*iter);
-        m_priv->interpreter->execute_command (*iter);
-    }
-}
-
-void
 DBGPerspective::execute_commands_from_file (const UString &a_file)
 {
-    THROW_IF_FAIL (m_priv);
+    THROW_IF_FAIL (m_priv->dbg_console);
 
-    std::ifstream file (a_file.c_str ());
-    while (file.good ()) {
-        std::string line;
-        std::getline (file, line);
-        execute_commands_from_line (line);
-    }
-    file.close ();
+    m_priv->dbg_console->execute_commands_from_file (a_file);
 }
 
 void
 DBGPerspective::execute_commands_from_fd (int a_fd)
 {
     THROW_IF_FAIL (m_priv);
+    THROW_IF_FAIL (m_priv->dbg_console);
 
-    struct File {
-        FILE *fd;
-        char buffer[4096];
-
-        explicit File (int a_fd) :
-            fd (fdopen (dup (a_fd), "r"))
-        {
-            THROW_IF_FAIL (fd);
-            int flags = fcntl (fileno (fd), F_GETFL, 0);
-            fcntl (fileno (fd), F_SETFL, flags | O_NONBLOCK);
-        }
-
-        ~File ()
-        {
-            if (fd) {
-                fclose (fd);
-            }
-        }
-    } file (a_fd);
-
-    while (fgets (file.buffer, sizeof (file.buffer), file.fd)) {
-        execute_commands_from_line (file.buffer);
-    }
+    m_priv->dbg_console->execute_commands_from_fd (a_fd);
 }
 
 void
@@ -8415,6 +8485,49 @@ DBGPerspective::get_local_vars_inspector_scrolled_win ()
     return *m_priv->variables_editor_scrolled_win;
 }
 
+Console&
+DBGPerspective::dbg_console ()
+{
+    THROW_IF_FAIL (m_priv);
+    if (!m_priv->dbg_console) {
+        string relative_path = Glib::build_filename ("menus",
+                                                     "terminalmenu.xml");
+        string absolute_path;
+        THROW_IF_FAIL (build_absolute_resource_path
+            (Glib::filename_to_utf8 (relative_path), absolute_path));
+
+        IDebuggerSafePtr dbg = debugger ();
+        THROW_IF_FAIL (dbg);
+        m_priv->dbg_console.reset
+            (new Console (*dbg, absolute_path, workbench ().get_ui_manager ()));
+        THROW_IF_FAIL (m_priv->dbg_console);
+
+        m_priv->open_command.reset (new OpenCommand (*this));
+        THROW_IF_FAIL (m_priv->open_command);
+        m_priv->dbg_console->command_interpreter
+            ().register_command (*m_priv->open_command);
+    }
+    THROW_IF_FAIL (m_priv->dbg_console);
+    return *m_priv->dbg_console;
+}
+
+Gtk::Box&
+DBGPerspective::console_box ()
+{
+    THROW_IF_FAIL (m_priv);
+    if (!m_priv->console_box) {
+        m_priv->console_box.reset (new Gtk::HBox);
+        THROW_IF_FAIL (m_priv->console_box);
+        Gtk::VScrollbar *scrollbar = Gtk::manage (new Gtk::VScrollbar);
+        m_priv->console_box->pack_end (*scrollbar, false, false, 0);
+
+        Terminal &terminal = dbg_console ().terminal ();
+        m_priv->console_box->pack_start (terminal.widget ());
+        scrollbar->set_adjustment (terminal.adjustment ());
+    }
+    THROW_IF_FAIL (m_priv->console_box);
+    return *m_priv->console_box;
+}
 
 Terminal&
 DBGPerspective::get_terminal ()
diff --git a/src/persp/dbgperspective/nmv-dbg-perspective.h b/src/persp/dbgperspective/nmv-dbg-perspective.h
index c22ed92..bf32d9b 100644
--- a/src/persp/dbgperspective/nmv-dbg-perspective.h
+++ b/src/persp/dbgperspective/nmv-dbg-perspective.h
@@ -39,6 +39,7 @@ extern const char *TARGET_TERMINAL_VIEW_TITLE;
 extern const char *BREAKPOINTS_VIEW_TITLE;
 extern const char *REGISTERS_VIEW_TITLE;
 extern const char *MEMORY_VIEW_TITLE;
+extern const char *CONSOLE_VIEW_TITLE;
 
 enum ViewsIndex
 {
@@ -49,7 +50,8 @@ enum ViewsIndex
 #ifdef WITH_MEMORYVIEW
     MEMORY_VIEW_INDEX,
 #endif // WITH_MEMORYVIEW
-    EXPR_MONITOR_VIEW_INDEX
+    EXPR_MONITOR_VIEW_INDEX,
+    CONSOLE_VIEW_INDEX
 };
 
 class SourceEditor;
diff --git a/src/uicommon/nmv-terminal.cc b/src/uicommon/nmv-terminal.cc
index 717c094..49f136c 100644
--- a/src/uicommon/nmv-terminal.cc
+++ b/src/uicommon/nmv-terminal.cc
@@ -336,6 +336,12 @@ Terminal::feed (const UString &a_text)
         vte_terminal_feed (m_priv->vte, a_text.c_str (), a_text.size ());
 }
 
+int
+Terminal::slave_fd () const
+{
+    THROW_IF_FAIL (m_priv);
+    return m_priv->slave_pty;
+}
 
 NEMIVER_END_NAMESPACE(nemiver)
 
diff --git a/src/uicommon/nmv-terminal.h b/src/uicommon/nmv-terminal.h
index d8c075d..21eff0d 100644
--- a/src/uicommon/nmv-terminal.h
+++ b/src/uicommon/nmv-terminal.h
@@ -68,6 +68,7 @@ public:
     Glib::RefPtr<Gtk::Adjustment> adjustment () const;
     int slave_pty () const;
     UString slave_pts_name () const;
+    int slave_fd () const;
     void modify_font (const Pango::FontDescription &font_desc);
     void feed (const UString &a_text);
 };//end class Terminal
-- 
1.8.4.rc3



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]