[nemiver/console: 2/11] WIP - Nemiver's console



commit aac4fc153cd336be210c9fe8aab5e5a1bba5dcdc
Author: Fabien Parent <parent f gmail com>
Date:   Sat Jan 21 18:58:05 2012 +0100

    WIP - Nemiver's console

 configure.ac                                    |    3 +-
 src/common/Makefile.am                          |    3 +-
 src/common/nmv-console.cc                       |  452 +++++++++++++++
 src/common/nmv-console.h                        |  112 ++++
 src/common/nmv-str-utils.h                      |   20 +
 src/dbgengine/Makefile.am                       |   11 +-
 src/dbgengine/nmv-dbg-console.cc                |  684 +++++++++++++++++++++++
 src/dbgengine/nmv-dbg-console.h                 |   58 ++
 src/persp/dbgperspective/nmv-dbg-perspective.cc |   74 +++
 src/persp/dbgperspective/nmv-dbg-perspective.h  |    4 +-
 src/uicommon/nmv-terminal.cc                    |    6 +
 src/uicommon/nmv-terminal.h                     |    1 +
 12 files changed, 1423 insertions(+), 5 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 1d45c0c..68430b8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -337,8 +337,9 @@ DEP_COMMON="gmodule-2.0 >= $LIBGMODULE_VERSION \
            glibmm-2.4 >= $LIBGLIBMM_VERSION"
 
 PKG_CHECK_MODULES(NEMIVERCOMMON, $DEP_COMMON)
+AC_CHECK_FUNCS(readline)
 NEMIVERCOMMON_CFLAGS="$NEMIVERCOMMON_CFLAGS $CPPUNIT_CFLAGS"
-NEMIVERCOMMON_LIBS="$NEMIVERCOMMON_LIBS $LIBGTOP_LIBS $CPPUNIT_LIBS"
+NEMIVERCOMMON_LIBS="$NEMIVERCOMMON_LIBS $LIBGTOP_LIBS $CPPUNIT_LIBS -lreadline"
 
 AC_SUBST(NEMIVERCOMMON_LIBS)
 AC_SUBST(NEMIVERCOMMON_CFLAGS)
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index 5b61d90..8318d34 100644
--- a/src/common/Makefile.am
+++ b/src/common/Makefile.am
@@ -71,7 +71,8 @@ $(h)/nmv-sql-statement.cc \
 $(h)/nmv-insert-statement.cc \
 $(h)/nmv-delete-statement.cc \
 $(h)/nmv-proc-utils.cc \
-$(h)/nmv-proc-mgr.cc
+$(h)/nmv-proc-mgr.cc \
+$(h)/nmv-console.cc
 
 publicheaders_DATA=$(headers)
 publicheadersdir=$(NEMIVER_INCLUDE_DIR)/common
diff --git a/src/common/nmv-console.cc b/src/common/nmv-console.cc
new file mode 100644
index 0000000..8df71b9
--- /dev/null
+++ b/src/common/nmv-console.cc
@@ -0,0 +1,452 @@
+//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 "nmv-str-utils.h"
+#include <map>
+#include <vector>
+#include <cstring>
+#include <cctype>
+#include <readline/readline.h>
+#include <readline/history.h>
+
+NEMIVER_BEGIN_NAMESPACE(nemiver)
+NEMIVER_BEGIN_NAMESPACE(common)
+
+const char *const CONSOLE_PROMPT = "> ";
+const unsigned int COMMAND_EXECUTION_TIMEOUT_IN_SECONDS = 10;
+
+struct Console::Stream::Priv {
+    int fd;
+
+    Priv (int a_fd) :
+        fd (a_fd)
+    {
+    }
+
+    void
+    write (const std::string &a_msg) const
+    {
+        THROW_IF_FAIL (fd);
+        ::write (fd, a_msg.c_str (), a_msg.size ());
+    }
+};
+
+Console::Stream::Stream (int a_fd) :
+    m_priv (new Priv (a_fd))
+{
+}
+
+Console::Stream&
+Console::Stream::operator<< (const char *const a_string)
+{
+    THROW_IF_FAIL (m_priv);
+    m_priv->write (a_string);
+    return *this;
+}
+
+Console::Stream&
+Console::Stream::operator<< (const std::string &a_string)
+{
+    THROW_IF_FAIL (m_priv);
+    m_priv->write (a_string);
+    return *this;
+}
+
+Console::Stream&
+Console::Stream::operator<< (unsigned int a_uint)
+{
+    THROW_IF_FAIL (m_priv);
+    m_priv->write (str_utils::to_string (a_uint));
+    return *this;
+}
+
+Console::Stream&
+Console::Stream::operator<< (int a_int)
+{
+    THROW_IF_FAIL (m_priv);
+    m_priv->write (str_utils::to_string (a_int));
+    return *this;
+}
+
+struct Console::Priv {
+    std::map<std::string, Console::Command&> commands;
+    std::vector<Console::Command*> commands_vector;
+
+    int fd;
+    struct readline_state console_state;
+    struct readline_state saved_state;
+
+    Console::Stream stream;
+    Glib::RefPtr<Glib::IOSource> io_source;
+    sigc::connection cmd_execution_done_connection;
+    sigc::connection cmd_execution_timeout_connection;
+
+    Priv (int a_fd) :
+        fd (a_fd),
+        stream (a_fd),
+        io_source (Glib::IOSource::create (a_fd, Glib::IO_IN))
+    {
+        init ();
+    }
+
+    void
+    init ()
+    {
+        THROW_IF_FAIL (fd);
+        THROW_IF_FAIL (io_source);
+
+        if (consoles ().count (fd)) {
+            THROW ("Cannot create two consoles from the same file descriptor.");
+        }
+        consoles ()[fd] = this;
+
+        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);
+    }
+
+    bool
+    read_char (Glib::IOCondition)
+    {
+        NEMIVER_TRY
+
+        if (cmd_execution_done_connection.connected ())
+            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
+    do_command_completion (const std::string &a_line)
+    {
+        std::vector<Console::Command*> matches;
+        for (std::vector<Console::Command*>::const_iterator iter =
+                commands_vector.begin ();
+             iter != commands_vector.end ();
+             ++iter) {
+            if (*iter && !(*iter)->name ().find (a_line)) {
+                matches.push_back (*iter);
+            }
+        }
+
+        if (matches.size () == 1) {
+            std::string completion =
+                matches[0]->name ().substr (a_line.size ());
+            do_completion (completion);
+        } else if (matches.size () > 1) {
+            std::string msg;
+            std::string completion =
+                matches[0]->name ().substr (a_line.size ());
+            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);
+                msg += matches[i]->name () + "\t";
+            }
+
+            rl_save_prompt ();
+            rl_message ("%s%s\n%s\n%s",
+                        rl_display_prompt,
+                        std::string (rl_line_buffer, rl_end).c_str (),
+                        msg.c_str (),
+                        rl_display_prompt);
+            rl_clear_message ();
+            rl_restore_prompt ();
+            do_completion (completion);
+        }
+    }
+
+    void
+    do_param_completion (std::vector<UString> &a_tokens)
+    {
+        if (!a_tokens.size ()) {
+            return;
+        }
+
+        Console::Command* command = 0;
+        for (std::vector<Console::Command*>::const_iterator iter =
+                commands_vector.begin ();
+             iter != commands_vector.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::string msg;
+                UString completion = matches[0].substr (token.size ());
+                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);
+                    msg += matches[i] + "\t";
+                }
+                rl_save_prompt ();
+                rl_message ("%s%s\n%s\n%s",
+                            rl_display_prompt,
+                            std::string (rl_line_buffer, rl_end).c_str (),
+                            msg.c_str (),
+                            rl_display_prompt);
+                rl_clear_message ();
+                rl_restore_prompt ();
+                do_completion (completion);
+            } else {
+                rl_complete (0, '\t');
+            }
+        }
+    }
+
+    void
+    execute_command (char *a_buffer)
+    {
+        std::string command_name;
+        std::vector<std::string> cmd_argv;
+
+        int size = std::strlen (a_buffer);
+        for (int i = 0, local_index = 0; i <= size; ++i, ++local_index) {
+            if (!std::isspace (a_buffer[local_index]) && i != size) {
+                continue;
+            }
+
+            a_buffer[local_index] = '\0';
+            if (command_name.empty ()) {
+                command_name = a_buffer;
+            } else {
+                cmd_argv.push_back (a_buffer);
+            }
+            a_buffer += local_index + 1;
+            local_index = 0;
+        }
+
+        if (command_name.empty ()) {
+            stream << CONSOLE_PROMPT;
+            return;
+        }
+
+        if (!commands.count (command_name)) {
+            stream << "Undefined command: " << command_name << ".\n"
+                   << CONSOLE_PROMPT;
+            return;
+        }
+
+        Command &command = commands.at (command_name);
+        cmd_execution_done_connection = command.done_signal ().connect
+            (sigc::mem_fun (*this, &Console::Priv::on_done_signal));
+        commands.at (command_name) (cmd_argv, stream);
+        cmd_execution_timeout_connection =
+            Glib::signal_timeout().connect_seconds
+                (sigc::mem_fun
+                    (*this, &Console::Priv::on_cmd_execution_timeout_signal),
+                 COMMAND_EXECUTION_TIMEOUT_IN_SECONDS);
+    }
+
+    bool
+    on_cmd_execution_timeout_signal ()
+    {
+        NEMIVER_TRY
+        on_done_signal ();
+        NEMIVER_CATCH_NOX
+
+        return true;
+    }
+
+    void
+    on_done_signal ()
+    {
+        NEMIVER_TRY
+
+        stream << CONSOLE_PROMPT;
+        cmd_execution_timeout_connection.disconnect();
+        cmd_execution_done_connection.disconnect ();
+
+        NEMIVER_CATCH_NOX
+    }
+
+    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 ().execute_command (a_command);
+
+        NEMIVER_CATCH_NOX
+
+        free (a_command);
+    }
+};
+
+Console::Console (int a_fd) :
+    m_priv (new Priv (a_fd))
+{
+}
+
+Console::~Console ()
+{
+}
+
+void
+Console::register_command (Console::Command &a_command)
+{
+    THROW_IF_FAIL (m_priv);
+
+    if (m_priv->commands.count (a_command.name ())) {
+        LOG ("Command '" << a_command.name () << "' is already registered in"
+             " the console. The previous command will be overwritten");
+    }
+
+    m_priv->commands.insert (std::make_pair<std::string, Command&>
+        (a_command.name (), a_command));
+    m_priv->commands_vector.push_back (&a_command);
+
+    const char **aliases = a_command.aliases ();
+    for (int i = 0; aliases && aliases[i]; i++) {
+        if (m_priv->commands.count (aliases[i])) {
+            LOG ("Command '" << aliases[i] << "' is already registered in"
+                 " the console. The previous command will be overwritten");
+        }
+        m_priv->commands.insert (std::make_pair<std::string, Command&>
+            (aliases[i], a_command));
+    }
+}
+
+NEMIVER_END_NAMESPACE(common)
+NEMIVER_END_NAMESPACE(nemiver)
+
diff --git a/src/common/nmv-console.h b/src/common/nmv-console.h
new file mode 100644
index 0000000..0ac41cf
--- /dev/null
+++ b/src/common/nmv-console.h
@@ -0,0 +1,112 @@
+//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 "nmv-safe-ptr.h"
+#include "nmv-namespace.h"
+#include "nmv-exception.h"
+#include <string>
+#include <vector>
+
+NEMIVER_BEGIN_NAMESPACE(nemiver)
+NEMIVER_BEGIN_NAMESPACE(common)
+
+class Console {
+    struct Priv;
+    SafePtr<Priv> m_priv;
+
+public:
+    class Stream {
+        struct Priv;
+        SafePtr<Priv> m_priv;
+        
+    public:
+        explicit Stream (int a_fd);
+        Stream& operator<< (const char *const a_string);
+        Stream& operator<< (const std::string &a_string);
+        Stream& operator<< (unsigned int a_uint);
+        Stream& operator<< (int a_int);
+    };
+
+    class Command {
+        sigc::signal<void> m_done_signal;
+
+public:
+        sigc::signal<void>& done_signal ()
+        {
+            return m_done_signal;
+        }
+
+        virtual const std::string& name () const = 0;
+
+        virtual const char** aliases () const
+        {
+            return 0;
+        }
+
+        virtual void completions (const std::vector<UString>&,
+                                  std::vector<UString>&) const
+        {
+        }
+
+        virtual void display_usage (const std::vector<UString>&, Stream&) const
+        {
+        }
+
+        virtual void execute (const std::vector<std::string> &a_argv,
+                              Stream &a_output) = 0;
+
+        virtual void operator() (const std::vector<std::string> &a_argv,
+                         Stream &a_output)
+        {
+            execute (a_argv, a_output);
+        }
+
+        virtual ~Command ()
+        {
+        }
+    };
+
+    typedef Command AsynchronousCommand;
+    struct SynchronousCommand : public Command{
+        virtual void operator() (const std::vector<std::string> &a_argv,
+                         Stream &a_output)
+        {
+            execute (a_argv, a_output);
+            done_signal ().emit ();
+        }
+    };
+
+    explicit Console (int a_fd);
+    virtual ~Console ();
+    void register_command (Console::Command &a_command);
+};
+
+NEMIVER_END_NAMESPACE(common)
+NEMIVER_END_NAMESPACE(nemiver)
+
+#endif /* __NMV_CONSOLE_H__ */
+
diff --git a/src/common/nmv-str-utils.h b/src/common/nmv-str-utils.h
index 8c72b8c..9a9f856 100644
--- a/src/common/nmv-str-utils.h
+++ b/src/common/nmv-str-utils.h
@@ -25,6 +25,7 @@
 #ifndef __NMV_STR_UTILS_H__
 #define __NMV_STR_UTILS_H__
 #include "nmv-ustring.h"
+#include <sstream>
 
 NEMIVER_BEGIN_NAMESPACE (nemiver)
 NEMIVER_BEGIN_NAMESPACE (str_utils)
@@ -52,6 +53,25 @@ UString join (vector<UString>::const_iterator &a_from,
               vector<UString>::const_iterator &a_to,
               const UString &a_delim=" ");
 
+template<typename T>
+T
+from_string (const std::string &a_string)
+{
+    std::istringstream is (a_string);
+    T out;
+    is >> out;
+    return out;
+}
+
+template<typename T>
+std::string
+to_string (const T &a_value)
+{
+    std::ostringstream os;
+    os << a_value;
+    return os.str ();
+}
+
 template<typename S>
 void
 chomp (S &a_string)
diff --git a/src/dbgengine/Makefile.am b/src/dbgengine/Makefile.am
index d1cd044..a271197 100644
--- a/src/dbgengine/Makefile.am
+++ b/src/dbgengine/Makefile.am
@@ -20,7 +20,8 @@ noinst_LTLIBRARIES=\
 libgdbmiparser.la \
 libdbgcommon.la \
 libdebuggerutils.la \
-libgdbengine.la
+libgdbengine.la \
+libdbgconsole.la
 
 h=$(abs_srcdir)
 
@@ -85,6 +86,12 @@ $(h)/nmv-debugger-utils.cc
 
 libdebuggerutils_la_CFLAGS=-fPIC -DPIC
 
+libdbgconsole_la_SOURCES= \
+$(h)/nmv-dbg-console.cc \
+$(h)/nmv-dbg-console.h
+
+libdbgconsole_la_CFLAGS=-fPIC -DPIC
+
 libgdbengine_la_SOURCES= \
 $(h)/nmv-gdb-engine.cc \
 $(h)/nmv-gdb-engine.h
@@ -96,7 +103,7 @@ publicheadersdir=$(NEMIVER_INCLUDE_DIR)/dynmods
 
 libgdbmod_la_LDFLAGS=-module -avoid-version -Wl,--as-needed
 libgdbmod_la_LIBADD=libgdbmiparser.la \
-libgdbengine.la libdebuggerutils.la @NEMIVERCOMMON_LIBS@ \
+libgdbengine.la libdebuggerutils.la libdbgconsole.la @NEMIVERCOMMON_LIBS@ \
 $(abs_top_builddir)/src/langs/libnemivercparser.la \
 $(abs_top_builddir)/src/common/libnemivercommon.la
 
diff --git a/src/dbgengine/nmv-dbg-console.cc b/src/dbgengine/nmv-dbg-console.cc
new file mode 100644
index 0000000..85de1ec
--- /dev/null
+++ b/src/dbgengine/nmv-dbg-console.cc
@@ -0,0 +1,684 @@
+//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.
+ */
+
+#include "nmv-dbg-console.h"
+#include "nmv-i-debugger.h"
+#include "uicommon/nmv-terminal.h"
+#include "common/nmv-exception.h"
+#include "common/nmv-str-utils.h"
+#include "common/nmv-ustring.h"
+
+NEMIVER_BEGIN_NAMESPACE(nemiver)
+
+const char *const NEMIVER_DBG_CONSOLE_COOKIE = "nemiver-dbg-console";
+
+using namespace common;
+
+struct DebuggingData {
+    IDebugger &debugger;
+    IDebugger::Frame current_frame;
+    UString current_file_path;
+    std::vector<UString> source_files;
+
+    DebuggingData (IDebugger &a_debugger) :
+        debugger (a_debugger)
+    {
+    }
+};
+
+struct CommandContinue : public Console::SynchronousCommand {
+    IDebugger &debugger;
+
+    CommandContinue (IDebugger &a_debugger) :
+        debugger (a_debugger)
+    {
+    }
+
+    const std::string&
+    name () const
+    {
+        static const std::string &s_name = "continue";
+        return s_name;
+    }
+
+    const char**
+    aliases () const
+    {
+        static const char *s_aliases[] =
+        {
+            "c",
+            0
+        };
+        return s_aliases;
+    }
+
+    void
+    execute (const std::vector<std::string>&, Console::Stream&)
+    {
+        debugger.do_continue ();
+    }
+};
+
+struct CommandNext : public Console::SynchronousCommand {
+    IDebugger &debugger;
+
+    CommandNext (IDebugger &a_debugger) :
+        debugger (a_debugger)
+    {
+    }
+
+    const std::string&
+    name () const
+    {
+        static const std::string &s_name = "next";
+        return s_name;
+    }
+
+    const char**
+    aliases () const
+    {
+        static const char *s_aliases[] =
+        {
+            "n",
+            0
+        };
+        return s_aliases;
+    }
+
+    void
+    execute (const std::vector<std::string>&, Console::Stream&)
+    {
+        debugger.step_over ();
+    }
+};
+
+struct CommandStep : public Console::SynchronousCommand {
+    IDebugger &debugger;
+
+    CommandStep (IDebugger &a_debugger) :
+        debugger (a_debugger)
+    {
+    }
+
+    const std::string&
+    name () const
+    {
+        static const std::string &s_name = "step";
+        return s_name;
+    }
+
+    const char**
+    aliases () const
+    {
+        static const char *s_aliases[] =
+        {
+            "s",
+            0
+        };
+        return s_aliases;
+    }
+
+    void
+    execute (const std::vector<std::string>&,
+             Console::Stream&)
+    {
+        debugger.step_in ();
+    }
+};
+
+struct CommandNexti : public Console::SynchronousCommand {
+    IDebugger &debugger;
+
+    CommandNexti (IDebugger &a_debugger) :
+        debugger (a_debugger)
+    {
+    }
+
+    const std::string&
+    name () const
+    {
+        static const std::string &s_name = "nexti";
+        return s_name;
+    }
+
+    const char**
+    aliases () const
+    {
+        static const char *s_aliases[] =
+        {
+            "ni",
+            0
+        };
+        return s_aliases;
+    }
+
+    void
+    execute (const std::vector<std::string>&, Console::Stream&)
+    {
+        debugger.step_over_asm ();
+    }
+};
+
+struct CommandStepi : public Console::SynchronousCommand {
+    IDebugger &debugger;
+
+    CommandStepi (IDebugger &a_debugger) :
+        debugger (a_debugger)
+    {
+    }
+
+    const std::string&
+    name () const
+    {
+        static const std::string &s_name = "stepi";
+        return s_name;
+    }
+
+    const char**
+    aliases () const
+    {
+        static const char *s_aliases[] =
+        {
+            "si",
+            0
+        };
+        return s_aliases;
+    }
+
+    void
+    execute (const std::vector<std::string>&, Console::Stream&)
+    {
+        debugger.step_in_asm ();
+    }
+};
+
+struct CommandStop : public Console::SynchronousCommand {
+    IDebugger &debugger;
+
+    CommandStop (IDebugger &a_debugger) :
+        debugger (a_debugger)
+    {
+    }
+
+    const std::string&
+    name () const
+    {
+        static const std::string &s_name = "stop";
+        return s_name;
+    }
+
+    void
+    execute (const std::vector<std::string>&, Console::Stream&)
+    {
+        debugger.stop_target ();
+    }
+};
+
+struct CommandFinish : public Console::SynchronousCommand {
+    IDebugger &debugger;
+
+    CommandFinish (IDebugger &a_debugger) :
+        debugger (a_debugger)
+    {
+    }
+
+    const std::string&
+    name () const
+    {
+        static const std::string &s_name = "finish";
+        return s_name;
+    }
+
+    void
+    execute (const std::vector<std::string>&, Console::Stream&)
+    {
+        debugger.step_out ();
+    }
+};
+
+struct CommandCall : public Console::SynchronousCommand {
+    IDebugger &debugger;
+    std::string cmd;
+
+    CommandCall (IDebugger &a_debugger) :
+        debugger (a_debugger)
+    {
+    }
+
+    const std::string&
+    name () const
+    {
+        static const std::string &s_name = "call";
+        return s_name;
+    }
+
+    void
+    execute (const std::vector<std::string> &a_argv, Console::Stream &a_stream)
+    {
+        if (a_argv.size ()) {
+            cmd.clear ();
+        }
+
+        for (std::vector<std::string>::const_iterator iter = a_argv.begin ();
+             iter != a_argv.end ();
+             ++iter) {
+            cmd += *iter;
+        }
+
+        if (cmd.empty ()) {
+            a_stream << "The history is empty.\n";
+        } else {
+            debugger.call_function (cmd);
+        }
+    }
+};
+
+struct CommandThread : public Console::AsynchronousCommand {
+    IDebugger &debugger;
+
+    CommandThread (IDebugger &a_debugger) :
+        debugger (a_debugger)
+    {
+    }
+
+    const std::string&
+    name () const
+    {
+        static const std::string &s_name = "thread";
+        return s_name;
+    }
+
+    void completions (const std::vector<UString> &a_argv,
+                      std::vector<UString> &a_completion_vector) const
+    {
+        if (a_argv.size () == 0) {
+            a_completion_vector.push_back ("list");
+        }
+    }
+
+    void display_usage (const std::vector<UString> &a_argv,
+                        Console::Stream &a_stream) const
+    {
+        if (a_argv.size ()) {
+            return;
+        }
+
+        a_stream << "Usage:\n"
+                 << "\tthread\n"
+                 << "\tthread [THREAD ID]\n"
+                 << "\tthread list\n";
+    }
+
+    void
+    threads_listed_signal (const std::list<int> a_thread_ids,
+                           const UString &a_cookie,
+                           Console::Stream &a_stream)
+    {
+        NEMIVER_TRY
+
+        if (a_cookie != NEMIVER_DBG_CONSOLE_COOKIE) {
+            return;
+        }
+
+        a_stream << "Threads:\n";
+        for (std::list<int>::const_iterator iter = a_thread_ids.begin ();
+             iter != a_thread_ids.end ();
+             ++iter) {
+            a_stream << *iter << "\n";
+        }
+        done_signal().emit ();
+
+        NEMIVER_CATCH_NOX
+    }
+
+    void
+    execute (const std::vector<std::string> &a_argv, Console::Stream &a_stream)
+    {
+        if (a_argv.size () > 1) {
+            a_stream << "Too much parameters.\n";
+        } else if (!a_argv.size ()) {
+            a_stream << "Current thread ID: " << debugger.get_current_thread ()
+                     << ".\n";
+        } else if (str_utils::string_is_number (a_argv[0])) {
+            debugger.select_thread
+                (str_utils::from_string<unsigned int> (a_argv[0]));
+        } else if (a_argv[0] == "list") {
+            debugger.threads_listed_signal ().connect
+                (sigc::bind<Console::Stream&> (sigc::mem_fun
+                    (*this, &CommandThread::threads_listed_signal),
+                 a_stream));
+            debugger.list_threads (NEMIVER_DBG_CONSOLE_COOKIE);
+            return;
+        } else {
+            a_stream << "Invalid argument: " << a_argv[0] << ".\n";
+        }
+
+        done_signal().emit ();
+    }
+};
+
+struct CommandBreak : public Console::SynchronousCommand {
+    DebuggingData &dbg_data;
+
+    CommandBreak (DebuggingData &a_dbg_data) :
+        dbg_data (a_dbg_data)
+    {
+    }
+
+    const std::string&
+    name () const
+    {
+        static const std::string &s_name = "break";
+        return s_name;
+    }
+
+    const char**
+    aliases () const
+    {
+        static const char *s_aliases[] =
+        {
+            "b",
+            0
+        };
+        return s_aliases;
+    }
+
+    void display_usage (const std::vector<UString>&,
+                        Console::Stream &a_stream) const
+    {
+        a_stream << "Usage:\n"
+                 << "\tbreak\n"
+                 << "\tbreak [LINE]\n"
+                 << "\tbreak [FUNCTION]\n"
+                 << "\tbreak *[ADDRESS]\n"
+                 << "\tbreak +[OFFSET]\n"
+                 << "\tbreak -[OFFSET]\n";
+    }
+
+    void
+    execute (const std::vector<std::string> &a_argv, Console::Stream &a_stream)
+    {
+        IDebugger::Frame &frame = dbg_data.current_frame;
+        IDebugger &debugger = dbg_data.debugger;
+
+        if (frame.file_full_name ().empty () ||
+            dbg_data.current_file_path.empty ()) {
+            a_stream << "Cannot set a breakpoint at this position.\n";
+        }
+
+        if (a_argv.size () > 1) {
+            a_stream << "Too much parameters.\n";
+        } else if (a_argv.size () == 0) {
+            debugger.set_breakpoint (frame.file_full_name (), frame.line ());
+        }
+
+        const char first_param_char = a_argv[0][0];
+        if (str_utils::string_is_number (a_argv[0])) {
+            debugger.set_breakpoint (dbg_data.current_file_path,
+                                     str_utils::from_string<int> (a_argv[0]));
+        } else if ((first_param_char >= 'a' && first_param_char <= 'z')
+                   || first_param_char == '_') {
+            debugger.set_breakpoint (a_argv[0]);
+        } else if (first_param_char == '*') {
+            std::string addr (a_argv[0].substr (1));
+            if (str_utils::string_is_hexa_number (addr)) {
+                Address address (addr);
+                debugger.set_breakpoint (address);
+            } else {
+                a_stream << "Invalid address: " << addr << ".\n";
+            }
+        } else if (first_param_char == '+' || first_param_char == '-') {
+            std::string offset (a_argv[0].substr (1));
+            if (str_utils::string_is_decimal_number (offset)) {
+                int line = frame.line ();
+                if (first_param_char == '+') {
+                    line += str_utils::from_string<int> (offset);
+                } else {
+                    line -= str_utils::from_string<int> (offset);
+                }
+                debugger.set_breakpoint (frame.file_full_name (), line);
+            } else {
+                a_stream << "Invalid offset: " << offset << ".\n";
+            }
+        } else {
+            a_stream << "Invalid argument: " << a_argv[0] << ".\n";
+        }
+    }
+};
+
+struct CommandPrint : public Console::AsynchronousCommand {
+    IDebugger &debugger;
+    std::string expression;
+
+    CommandPrint (IDebugger &a_debugger) :
+        debugger (a_debugger)
+    {
+    }
+
+    const std::string&
+    name () const
+    {
+        static const std::string &s_name = "print";
+        return s_name;
+    }
+
+    void
+    on_variable_created_signal (const IDebugger::VariableSafePtr a_var,
+                                Console::Stream &a_stream)
+    {
+        NEMIVER_TRY
+
+        THROW_IF_FAIL (a_var);
+        a_stream << a_var->name () << " = " << a_var->value () << "\n";
+        debugger.delete_variable (a_var);
+        done_signal ().emit ();
+
+        NEMIVER_CATCH_NOX
+    }
+
+    void
+    execute (const std::vector<std::string> &a_argv, Console::Stream &a_stream)
+    {
+        if (a_argv.size ()) {
+            expression.clear ();
+        }
+
+        for (std::vector<std::string>::const_iterator iter = a_argv.begin ();
+             iter != a_argv.end ();
+             ++iter) {
+            expression += *iter;
+        }
+
+        if (expression.empty ()) {
+            a_stream << "No history\n";
+            done_signal ().emit ();
+            return;
+        }
+
+        debugger.create_variable
+            (expression, sigc::bind<Console::Stream&>
+                (sigc::mem_fun
+                    (*this, &CommandPrint::on_variable_created_signal),
+                 a_stream));
+    }
+};
+
+struct CommandOpen : public Console::SynchronousCommand {
+    DebuggingData &dbg_data;
+    sigc::signal<void, UString> file_opened_signal;
+
+    CommandOpen (DebuggingData &a_dbg_data) :
+        dbg_data (a_dbg_data)
+    {
+    }
+
+    const std::string&
+    name () const
+    {
+        static const std::string &s_name = "open";
+        return s_name;
+    }
+
+    const char**
+    aliases () const
+    {
+        static const char *s_aliases[] =
+        {
+            "o",
+            0
+        };
+        return s_aliases;
+    }
+
+    void completions (const std::vector<UString>&,
+                      std::vector<UString> &a_completion_vector) const
+    {
+        a_completion_vector.insert (a_completion_vector.begin (),
+                                    dbg_data.source_files.begin (),
+                                    dbg_data.source_files.end ());
+    }
+
+    void
+    execute (const std::vector<std::string> &a_argv, Console::Stream&)
+    {
+        for (std::vector<std::string>::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 ());
+            }
+            file_opened_signal.emit (path);
+        }
+    }
+};
+
+struct DBGConsole::Priv {
+    DebuggingData data;
+
+    CommandContinue cmd_continue;
+    CommandNext cmd_next;
+    CommandStep cmd_step;
+    CommandBreak cmd_break;
+    CommandPrint cmd_print;
+    CommandCall cmd_call;
+    CommandFinish cmd_finish;
+    CommandThread cmd_thread;
+    CommandStop cmd_stop;
+    CommandNexti cmd_nexti;
+    CommandStepi cmd_stepi;
+    CommandOpen cmd_open;
+
+    Priv (IDebugger &a_debugger) :
+        data (a_debugger),
+        cmd_continue (a_debugger),
+        cmd_next (a_debugger),
+        cmd_step (a_debugger),
+        cmd_break (data),
+        cmd_print (a_debugger),
+        cmd_call (a_debugger),
+        cmd_finish (a_debugger),
+        cmd_thread (a_debugger),
+        cmd_stop (a_debugger),
+        cmd_nexti (a_debugger),
+        cmd_stepi (a_debugger),
+        cmd_open (data)
+    {
+        init_signals ();
+    }
+
+    void
+    on_stopped_signal (IDebugger::StopReason,
+                       bool,
+                       const IDebugger::Frame &a_frame,
+                       int,
+                       int,
+                       const UString&)
+    {
+        data.current_frame = a_frame;
+        data.current_file_path = a_frame.file_full_name ();
+    }
+
+    void
+    on_files_listed_signal (const std::vector<UString> &a_files, const UString&)
+    {
+        data.source_files = a_files;
+    }
+
+    void
+    init_signals ()
+    {
+        data.debugger.stopped_signal ().connect
+            (sigc::mem_fun (*this, &DBGConsole::Priv::on_stopped_signal));
+        data.debugger.files_listed_signal ().connect (sigc::mem_fun
+            (*this, &DBGConsole::Priv::on_files_listed_signal));
+    }
+};
+
+DBGConsole::DBGConsole (int a_fd, IDebugger &a_debugger) :
+    Console (a_fd),
+    m_priv (new Priv (a_debugger))
+{
+    register_command (m_priv->cmd_continue);
+    register_command (m_priv->cmd_next);
+    register_command (m_priv->cmd_step);
+    register_command (m_priv->cmd_break);
+    register_command (m_priv->cmd_print);
+    register_command (m_priv->cmd_call);
+    register_command (m_priv->cmd_finish);
+    register_command (m_priv->cmd_thread);
+    register_command (m_priv->cmd_stop);
+    register_command (m_priv->cmd_nexti);
+    register_command (m_priv->cmd_stepi);
+    register_command (m_priv->cmd_open);
+}
+
+void
+DBGConsole::current_file_path (const UString &a_file_path)
+{
+    THROW_IF_FAIL (m_priv);
+    m_priv->data.current_file_path = a_file_path;
+}
+
+const UString&
+DBGConsole::current_file_path () const
+{
+    THROW_IF_FAIL (m_priv);
+    return m_priv->data.current_file_path;
+}
+
+DBGConsole::~DBGConsole ()
+{
+}
+
+sigc::signal<void, UString>
+DBGConsole::file_opened_signal () const
+{
+    THROW_IF_FAIL (m_priv);
+    return m_priv->cmd_open.file_opened_signal;
+}
+
+NEMIVER_END_NAMESPACE(nemiver)
+
diff --git a/src/dbgengine/nmv-dbg-console.h b/src/dbgengine/nmv-dbg-console.h
new file mode 100644
index 0000000..d2a8b6b
--- /dev/null
+++ b/src/dbgengine/nmv-dbg-console.h
@@ -0,0 +1,58 @@
+//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_DBG_CONSOLE_H__
+#define __NMV_DBG_CONSOLE_H__
+
+#include "common/nmv-console.h"
+
+NEMIVER_BEGIN_NAMESPACE(nemiver)
+
+namespace common {
+    class UString;
+}
+
+class IDebugger;
+
+using common::SafePtr;
+using common::UString;
+
+class DBGConsole : public common::Console {
+    struct Priv;
+    SafePtr<Priv> m_priv;
+
+public:
+    DBGConsole (int a_fd, IDebugger &a_debugger);
+    ~DBGConsole ();
+
+    void current_file_path (const UString &a_file_path);
+    const UString& current_file_path () const;
+
+    sigc::signal<void, UString> file_opened_signal () const;
+};
+
+NEMIVER_END_NAMESPACE(nemiver)
+
+#endif /* __NMV_DBG_CONSOLE_H__ */
+
diff --git a/src/persp/dbgperspective/nmv-dbg-perspective.cc b/src/persp/dbgperspective/nmv-dbg-perspective.cc
index 48cf7bb..e3b68da 100644
--- a/src/persp/dbgperspective/nmv-dbg-perspective.cc
+++ b/src/persp/dbgperspective/nmv-dbg-perspective.cc
@@ -53,6 +53,7 @@
 #include "common/nmv-str-utils.h"
 #include "common/nmv-address.h"
 #include "common/nmv-loc.h"
+#include "nmv-dbg-console.h"
 #include "nmv-sess-mgr.h"
 #include "nmv-dbg-perspective.h"
 #include "nmv-source-editor.h"
@@ -118,6 +119,7 @@ const char *TARGET_TERMINAL_VIEW_TITLE = _("Target Terminal");
 const char *BREAKPOINTS_VIEW_TITLE     = _("Breakpoints");
 const char *REGISTERS_VIEW_TITLE       = _("Registers");
 const char *MEMORY_VIEW_TITLE          = _("Memory");
+const char *CONSOLE_VIEW_TITLE         = _("Console");
 
 const char *CAPTION_SESSION_NAME = "captionname";
 const char *SESSION_NAME = "sessionname";
@@ -412,6 +414,7 @@ private:
     void on_notebook_tabs_reordered(Gtk::Widget* a_page, guint a_page_num);
 
     void on_layout_changed ();
+    void on_file_opened (UString a_path);
     void on_activate_context_view ();
     void on_activate_target_terminal_view ();
     void on_activate_breakpoints_view ();
@@ -739,6 +742,10 @@ public:
 
     Gtk::ScrolledWindow& get_local_vars_inspector_scrolled_win ();
 
+    Terminal& console_terminal ();
+
+    Gtk::Box& console_box ();
+
     Terminal& get_terminal ();
 
     Gtk::Box& get_terminal_box ();
@@ -897,6 +904,9 @@ struct DBGPerspective::Priv {
     Path2MonitorMap path_2_monitor_map;
     SafePtr<LocalVarsInspector> variables_editor;
     SafePtr<Gtk::ScrolledWindow> variables_editor_scrolled_win;
+    SafePtr<Terminal> console_terminal;
+    SafePtr<DBGConsole> dbg_console;
+    SafePtr<Gtk::Box> console_box;
     SafePtr<Terminal> terminal;
     SafePtr<Gtk::Box> terminal_box;
     SafePtr<Gtk::ScrolledWindow> breakpoints_scrolled_win;
@@ -1761,6 +1771,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) {
+            THROW_IF_FAIL (m_priv->dbg_console);
+            m_priv->dbg_console->current_file_path (editor->get_path ());
+        }
+    }
     NEMIVER_CATCH
 }
 
@@ -2811,6 +2832,14 @@ DBGPerspective::on_layout_changed ()
 }
 
 void
+DBGPerspective::on_file_opened (UString a_file)
+{
+    NEMIVER_TRY
+    open_file (a_file, -1);
+    NEMIVER_CATCH
+}
+
+void
 DBGPerspective::on_activate_context_view ()
 {
     LOG_FUNCTION_SCOPE_NORMAL_DD;
@@ -3685,6 +3714,11 @@ DBGPerspective::init_body ()
         (sigc::mem_fun (this, &DBGPerspective::on_notebook_tabs_reordered));
 #endif
 
+    IDebuggerSafePtr& dbg = debugger ();
+    THROW_IF_FAIL (dbg);
+    m_priv->dbg_console.reset
+                (new DBGConsole (console_terminal ().slave_fd (), *dbg));
+
     UString layout = DBG_PERSPECTIVE_DEFAULT_LAYOUT;
     NEMIVER_TRY
     conf_mgr.get_key_value (CONF_KEY_DBG_PERSPECTIVE_LAYOUT, layout);
@@ -3732,6 +3766,10 @@ DBGPerspective::init_signals ()
 
     m_priv->layout_mgr.layout_changed_signal ().connect (sigc::mem_fun
             (*this, &DBGPerspective::on_layout_changed));
+
+    THROW_IF_FAIL (m_priv->dbg_console);
+    m_priv->dbg_console->file_opened_signal ().connect (sigc::mem_fun
+        (*this, &DBGPerspective::on_file_opened));
 }
 
 /// Connect slots (callbacks) to the signals emitted by the
@@ -4928,6 +4966,9 @@ DBGPerspective::add_views_to_layout ()
 {
     THROW_IF_FAIL (m_priv);
 
+    m_priv->layout ().add_view (console_box (),
+                                CONSOLE_VIEW_TITLE,
+                                CONSOLE_VIEW_INDEX);
 #ifdef WITH_MEMORYVIEW
     m_priv->layout ().add_view (get_memory_view ().widget (),
                                 MEMORY_VIEW_TITLE,
@@ -8011,6 +8052,39 @@ DBGPerspective::get_local_vars_inspector_scrolled_win ()
     return *m_priv->variables_editor_scrolled_win;
 }
 
+Terminal&
+DBGPerspective::console_terminal ()
+{
+    THROW_IF_FAIL (m_priv);
+    if (!m_priv->console_terminal) {
+        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));
+
+        m_priv->console_terminal.reset (new Terminal
+            (absolute_path, workbench ().get_ui_manager ()));
+    }
+    THROW_IF_FAIL (m_priv->console_terminal);
+    return *m_priv->console_terminal;
+}
+
+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);
+        m_priv->console_box->pack_start (console_terminal ().widget ());
+        scrollbar->set_adjustment (console_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 ddb00ff..cc0ea7b 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
 {
@@ -47,8 +48,9 @@ enum ViewsIndex
     BREAKPOINTS_VIEW_INDEX,
     REGISTERS_VIEW_INDEX,
 #ifdef WITH_MEMORYVIEW
-    MEMORY_VIEW_INDEX
+    MEMORY_VIEW_INDEX,
 #endif // WITH_MEMORYVIEW
+    CONSOLE_VIEW_INDEX
 };
 
 class SourceEditor;
diff --git a/src/uicommon/nmv-terminal.cc b/src/uicommon/nmv-terminal.cc
index 5222bd1..3ae6da1 100644
--- a/src/uicommon/nmv-terminal.cc
+++ b/src/uicommon/nmv-terminal.cc
@@ -335,6 +335,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 6f5b9ed..13d8818 100644
--- a/src/uicommon/nmv-terminal.h
+++ b/src/uicommon/nmv-terminal.h
@@ -67,6 +67,7 @@ public:
     Gtk::Widget& widget () const;
     Glib::RefPtr<Gtk::Adjustment> adjustment () 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



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