Commit dd1d8b21 authored by Christian Hergert's avatar Christian Hergert

Merge branch 'gwagner/gnome-builder-gwagner/gdb-interpret'

parents 06e60fd2 c63527a9
......@@ -259,3 +259,32 @@ _ide_debugger_real_disassemble_finish (IdeDebugger *self,
return g_task_propagate_pointer (G_TASK (result), error);
}
void
_ide_debugger_real_interpret_async (IdeDebugger *self,
const gchar *command,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_assert (IDE_IS_DEBUGGER (self));
g_assert (command != NULL);
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
g_task_report_new_error (self, callback, user_data,
_ide_debugger_real_interpret_async,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"Interpret command is not supported");
}
gboolean
_ide_debugger_real_interpret_finish (IdeDebugger *self,
GAsyncResult *result,
GError **error)
{
g_assert (IDE_IS_DEBUGGER (self));
g_assert (G_IS_TASK (result));
return g_task_propagate_boolean (G_TASK (result), error);
}
......@@ -46,6 +46,14 @@ void _ide_debugger_real_list_frames_async (IdeDebugger
GPtrArray *_ide_debugger_real_list_frames_finish (IdeDebugger *self,
GAsyncResult *result,
GError **error);
void _ide_debugger_real_interpret_async (IdeDebugger *self,
const gchar *command,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean _ide_debugger_real_interpret_finish (IdeDebugger *self,
GAsyncResult *result,
GError **error);
void _ide_debugger_real_interrupt_async (IdeDebugger *self,
IdeDebuggerThreadGroup *thread_group,
GCancellable *cancellable,
......
......@@ -490,6 +490,8 @@ ide_debugger_class_init (IdeDebuggerClass *klass)
klass->thread_group_removed = ide_debugger_real_thread_group_removed;
klass->thread_removed = ide_debugger_real_thread_removed;
klass->thread_selected = ide_debugger_real_thread_selected;
klass->interpret_async = _ide_debugger_real_interpret_async;
klass->interpret_finish = _ide_debugger_real_interpret_finish;
/**
* IdeDebugger:display-name:
......@@ -2012,3 +2014,62 @@ ide_debugger_prepare (IdeDebugger *self,
if (IDE_DEBUGGER_GET_CLASS (self)->prepare)
IDE_DEBUGGER_GET_CLASS (self)->prepare (self, runner);
}
/**
* ide_debugger_interpret_async:
* @self: an #IdeDebugger
* @command: a command to execute
* @cancellable: (nullable): a #GCancellable or %NULL
* @callback: a callback to execute, or %NULL
* @user_data: user data for @callback
*
* Asynchronously requests that the debugger interpret the command.
*
* This is used by the interactive-console to submit commands to the debugger
* that are in the native syntax of that debugger.
*
* The debugger is expected to return any textual output via the
* IdeDebugger::log signal.
*
* Call ide_debugger_interpret_finish() from @callback to determine if the
* command was interpreted.
*
* Since: 3.32
*/
void
ide_debugger_interpret_async (IdeDebugger *self,
const gchar *command,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_return_if_fail (IDE_IS_DEBUGGER (self));
g_return_if_fail (command != NULL);
return IDE_DEBUGGER_GET_CLASS (self)->interpret_async (self, command, cancellable, callback, user_data);
}
/**
* ide_debugger_interpret_finish:
* @self: an #IdeDebugger
* @result: a #GAsyncResult provided to callback
* @error: a location for a #GError, or %NULL
*
* Retrieves the result of the asynchronous operation to interpret a debugger
* command.
*
* Returns: %TRUE if the command was interpreted, otherwise %FALSE and
* @error is set.
*
* Since: 3.32
*/
gboolean
ide_debugger_interpret_finish (IdeDebugger *self,
GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (IDE_IS_DEBUGGER (self), FALSE);
g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
return IDE_DEBUGGER_GET_CLASS (self)->interpret_finish (self, result, error);
}
......@@ -185,6 +185,14 @@ struct _IdeDebuggerClass
GPtrArray *(*disassemble_finish) (IdeDebugger *self,
GAsyncResult *result,
GError **error);
void (*interpret_async) (IdeDebugger *self,
const gchar *command,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean (*interpret_finish) (IdeDebugger *self,
GAsyncResult *result,
GError **error);
/*< private >*/
gpointer _reserved[32];
......@@ -385,5 +393,15 @@ void ide_debugger_emit_library_loaded (IdeDebugger
IDE_AVAILABLE_IN_3_32
void ide_debugger_emit_library_unloaded (IdeDebugger *self,
IdeDebuggerLibrary *library);
IDE_AVAILABLE_IN_3_32
void ide_debugger_interpret_async (IdeDebugger *self,
const gchar *command,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
IDE_AVAILABLE_IN_3_32
gboolean ide_debugger_interpret_finish (IdeDebugger *self,
GAsyncResult *result,
GError **error);
G_END_DECLS
......@@ -11,5 +11,7 @@
<file preprocess="xml-stripblanks">ide-debugger-locals-view.ui</file>
<file preprocess="xml-stripblanks">ide-debugger-registers-view.ui</file>
<file preprocess="xml-stripblanks">ide-debugger-threads-view.ui</file>
<file preprocess="xml-stripblanks">ide-debugger-log-view.ui</file>
<file>themes/Adwaita-shared.css</file>
</gresource>
</gresources>
......@@ -29,7 +29,6 @@
#include <libide-foundry.h>
#include <libide-gui.h>
#include <libide-io.h>
#include <libide-terminal.h>
#include <glib/gi18n.h>
#include "ide-debugger-breakpoints-view.h"
......@@ -40,6 +39,7 @@
#include "ide-debugger-locals-view.h"
#include "ide-debugger-registers-view.h"
#include "ide-debugger-threads-view.h"
#include "ide-debugger-log-view.h"
/**
* SECTION:ide-debugger-editor-addin
......@@ -71,49 +71,9 @@ struct _IdeDebuggerEditorAddin
DzlDockWidget *panel;
IdeDebuggerRegistersView *registers_view;
IdeDebuggerThreadsView *threads_view;
IdeTerminal *log_view;
GtkScrollbar *log_view_scroller;
IdeDebuggerLogView *log_view;
};
static void
debugger_log (IdeDebuggerEditorAddin *self,
IdeDebuggerStream stream,
GBytes *content,
IdeDebugger *debugger)
{
g_assert (IDE_IS_DEBUGGER_EDITOR_ADDIN (self));
g_assert (IDE_IS_DEBUGGER_STREAM (stream));
g_assert (content != NULL);
g_assert (IDE_IS_DEBUGGER (debugger));
if (stream == IDE_DEBUGGER_CONSOLE)
{
IdeLineReader reader;
const gchar *str;
gchar *line;
gsize len;
gsize line_len;
str = g_bytes_get_data (content, &len);
/*
* Ingnore \n so we can add \r\n. Otherwise we get problematic
* output in the terminal.
*/
ide_line_reader_init (&reader, (gchar *)str, len);
while (NULL != (line = ide_line_reader_next (&reader, &line_len)))
{
vte_terminal_feed (VTE_TERMINAL (self->log_view), line, line_len);
if ((line + line_len) < (str + len))
{
if (line[line_len] == '\r' || line[line_len] == '\n')
vte_terminal_feed (VTE_TERMINAL (self->log_view), "\r\n", 2);
}
}
}
}
static void
debugger_stopped (IdeDebuggerEditorAddin *self,
IdeDebuggerStopReason reason,
......@@ -228,6 +188,7 @@ debug_manager_notify_debugger (IdeDebuggerEditorAddin *self,
ide_debugger_libraries_view_set_debugger (self->libraries_view, debugger);
ide_debugger_registers_view_set_debugger (self->registers_view, debugger);
ide_debugger_threads_view_set_debugger (self->threads_view, debugger);
ide_debugger_log_view_set_debugger (self->log_view, debugger);
dzl_signal_group_set_target (self->debugger_signals, debugger);
}
......@@ -311,7 +272,6 @@ on_frame_activated (IdeDebuggerEditorAddin *self,
static void
ide_debugger_editor_addin_add_ui (IdeDebuggerEditorAddin *self)
{
GtkWidget *scroll_box;
GtkWidget *box;
GtkWidget *hpaned;
GtkWidget *utilities;
......@@ -397,28 +357,13 @@ ide_debugger_editor_addin_add_ui (IdeDebuggerEditorAddin *self)
gtk_container_add_with_properties (GTK_CONTAINER (box), GTK_WIDGET (self->registers_view),
"tab-label", _("Registers"),
NULL);
scroll_box = g_object_new (GTK_TYPE_BOX,
"orientation", GTK_ORIENTATION_HORIZONTAL,
"visible", TRUE,
NULL);
gtk_container_add_with_properties (GTK_CONTAINER (box), GTK_WIDGET (scroll_box),
"tab-label", _("Log"),
NULL);
self->log_view = g_object_new (IDE_TYPE_TERMINAL,
"hexpand", TRUE,
self->log_view = g_object_new (IDE_TYPE_DEBUGGER_LOG_VIEW,
"visible", TRUE,
NULL);
OBSERVE_DESTROY (self->log_view);
gtk_container_add (GTK_CONTAINER (scroll_box), GTK_WIDGET (self->log_view));
self->log_view_scroller = g_object_new (GTK_TYPE_SCROLLBAR,
"adjustment", gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (self->log_view)),
"orientation", GTK_ORIENTATION_VERTICAL,
"visible", TRUE,
NULL);
gtk_container_add (GTK_CONTAINER (scroll_box), GTK_WIDGET (self->log_view_scroller));
gtk_container_add_with_properties (GTK_CONTAINER (box), GTK_WIDGET (self->log_view),
"tab-label", _("Console"),
NULL);
utilities = ide_editor_surface_get_utilities (self->editor);
gtk_container_add (GTK_CONTAINER (utilities), GTK_WIDGET (self->panel));
......@@ -465,8 +410,8 @@ ide_debugger_editor_addin_load (IdeEditorAddin *addin,
dzl_signal_group_connect_swapped (self->debugger_signals,
"log",
G_CALLBACK (debugger_log),
self);
G_CALLBACK (ide_debugger_log_view_debugger_log),
self->log_view);
dzl_signal_group_connect_swapped (self->debugger_signals,
"stopped",
......
/* ide-debugger-log-view.c
*
* Copyright 2020 Günther Wagner <info@gunibert.de>
*
* This program 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 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#define G_LOG_DOMAIN "ide-debugger-log-view"
#include <libide-terminal.h>
#include "ide-debugger-log-view.h"
struct _IdeDebuggerLogView
{
GtkBox parent_instance;
IdeTerminal *terminal;
GtkScrollbar *scroller;
GtkEntry *commandentry;
IdeDebugger *debugger;
};
G_DEFINE_TYPE (IdeDebuggerLogView, ide_debugger_log_view, GTK_TYPE_BOX)
enum {
PROP_0,
PROP_DEBUGGER,
N_PROPS
};
static GParamSpec *properties [N_PROPS];
IdeDebuggerLogView *
ide_debugger_log_view_new (void)
{
return g_object_new (IDE_TYPE_DEBUGGER_LOG_VIEW, NULL);
}
static void
ide_debugger_log_view_finalize (GObject *object)
{
IdeDebuggerLogView *self = (IdeDebuggerLogView *)object;
g_clear_object (&self->debugger);
G_OBJECT_CLASS (ide_debugger_log_view_parent_class)->finalize (object);
}
static void
ide_debugger_log_view_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
IdeDebuggerLogView *self = IDE_DEBUGGER_LOG_VIEW (object);
switch (prop_id)
{
case PROP_DEBUGGER:
g_value_set_object (value, ide_debugger_log_view_get_debugger (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
ide_debugger_log_view_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
IdeDebuggerLogView *self = IDE_DEBUGGER_LOG_VIEW (object);
switch (prop_id)
{
case PROP_DEBUGGER:
ide_debugger_log_view_set_debugger (self, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
on_entry_activate_cb (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
IdeDebugger *debugger = (IdeDebugger *)source;
g_autoptr(IdeDebuggerLogView) self = user_data;
g_autoptr(GError) error = NULL;
IDE_ENTRY;
g_assert (IDE_IS_DEBUGGER (debugger));
g_assert (G_IS_ASYNC_RESULT (result));
g_assert (IDE_IS_DEBUGGER_LOG_VIEW (self));
gtk_entry_set_text (self->commandentry, "");
gtk_widget_set_sensitive (GTK_WIDGET (self->commandentry), TRUE);
gtk_widget_grab_focus (GTK_WIDGET (self->commandentry));
if (!ide_debugger_interpret_finish (debugger, result, &error))
{
vte_terminal_feed (VTE_TERMINAL (self->terminal),
error->message,
strlen (error->message));
vte_terminal_feed (VTE_TERMINAL (self->terminal), "\r\n", 2);
}
IDE_EXIT;
}
static void
on_entry_activate (IdeDebuggerLogView *self,
GtkEntry *entry)
{
g_autofree gchar *text = NULL;
g_return_if_fail (IDE_IS_DEBUGGER_LOG_VIEW (self));
g_return_if_fail (GTK_IS_ENTRY (entry));
text = g_strstrip (g_strdup (gtk_entry_get_text (entry)));
if (ide_str_empty0 (text))
return;
vte_terminal_feed (VTE_TERMINAL (self->terminal), "> ", 2);
vte_terminal_feed (VTE_TERMINAL (self->terminal), text, strlen (text));
vte_terminal_feed (VTE_TERMINAL (self->terminal), "\r\n", 2);
if (self->debugger != NULL)
{
gtk_widget_set_sensitive (GTK_WIDGET (self->commandentry), FALSE);
ide_debugger_interpret_async (self->debugger,
text,
NULL,
on_entry_activate_cb,
g_object_ref (self));
}
}
static void
ide_debugger_log_view_class_init (IdeDebuggerLogViewClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->finalize = ide_debugger_log_view_finalize;
object_class->get_property = ide_debugger_log_view_get_property;
object_class->set_property = ide_debugger_log_view_set_property;
properties [PROP_DEBUGGER] =
g_param_spec_object ("debugger",
"Debugger",
"Debugger",
IDE_TYPE_DEBUGGER,
(G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, N_PROPS, properties);
gtk_widget_class_set_template_from_resource (widget_class, "/plugins/debuggerui/ide-debugger-log-view.ui");
gtk_widget_class_bind_template_child (widget_class, IdeDebuggerLogView, terminal);
gtk_widget_class_bind_template_child (widget_class, IdeDebuggerLogView, commandentry);
gtk_widget_class_bind_template_callback (widget_class, on_entry_activate);
}
static void
ide_debugger_log_view_init (IdeDebuggerLogView *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
/* TODO: somehow scroll sync does now work */
g_object_set (self->scroller,
"adjustment", gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (self->terminal)),
NULL);
}
void
ide_debugger_log_view_debugger_log (IdeDebuggerLogView *self,
IdeDebuggerStream stream,
GBytes *content,
IdeDebugger *debugger)
{
g_assert (IDE_IS_DEBUGGER_LOG_VIEW (self));
g_assert (IDE_IS_DEBUGGER_STREAM (stream));
g_assert (content != NULL);
g_assert (IDE_IS_DEBUGGER (debugger));
if (stream == IDE_DEBUGGER_CONSOLE)
{
IdeLineReader reader;
const gchar *str;
gchar *line;
gsize len;
gsize line_len;
str = g_bytes_get_data (content, &len);
/*
* Ignore \n so we can add \r\n. Otherwise we get problematic
* output in the terminal.
*/
ide_line_reader_init (&reader, (gchar *)str, len);
while (NULL != (line = ide_line_reader_next (&reader, &line_len)))
{
vte_terminal_feed (VTE_TERMINAL (self->terminal), line, line_len);
if ((line + line_len) < (str + len))
{
if (line[line_len] == '\r' || line[line_len] == '\n')
vte_terminal_feed (VTE_TERMINAL (self->terminal), "\r\n", 2);
}
}
}
}
void
ide_debugger_log_view_set_debugger (IdeDebuggerLogView *self,
IdeDebugger *debugger)
{
g_return_if_fail (IDE_IS_DEBUGGER_LOG_VIEW (self));
g_return_if_fail (!debugger || IDE_IS_DEBUGGER (debugger));
self->debugger = g_object_ref (debugger);
}
IdeDebugger *
ide_debugger_log_view_get_debugger (IdeDebuggerLogView *self)
{
g_return_val_if_fail (IDE_IS_DEBUGGER_LOG_VIEW (self), NULL);
return self->debugger;
}
/* ide-debugger-log-view.h
*
* Copyright 2020 Günther Wagner <info@gunibert.de>
*
* This program 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 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include <gtk/gtk.h>
#include <libide-debugger.h>
G_BEGIN_DECLS
#define IDE_TYPE_DEBUGGER_LOG_VIEW (ide_debugger_log_view_get_type())
G_DECLARE_FINAL_TYPE (IdeDebuggerLogView, ide_debugger_log_view, IDE, DEBUGGER_LOG_VIEW, GtkBox)
IdeDebuggerLogView *ide_debugger_log_view_new (void);
void ide_debugger_log_view_debugger_log (IdeDebuggerLogView *self,
IdeDebuggerStream stream,
GBytes *content,
IdeDebugger *debugger);
void ide_debugger_log_view_set_debugger (IdeDebuggerLogView *self,
IdeDebugger *debugger);
IdeDebugger *ide_debugger_log_view_get_debugger (IdeDebuggerLogView *self);
G_END_DECLS
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.37.0 -->
<interface>
<requires lib="gtk+" version="3.0"/>
<template class="IdeDebuggerLogView" parent="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<child>
<object class="IdeTerminal" id="terminal">
<property name="visible">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrollbar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<style>
<class name="commandbox"/>
</style>
<child>
<object class="GtkEntry" id="commandentry">
<property name="primary-icon-name">pan-end-symbolic</property>
<property name="visible">True</property>
<property name="margin">6</property>
<signal name="activate" handler="on_entry_activate" swapped="yes" object="IdeDebuggerLogView"/>
<style>
<class name="commandentry"/>
</style>
</object>