1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-06-01 10:08:10 +00:00

HackStudio: Remove "evaluate expression" dialog

This was built on Web::InProcessWebView which is going to be removed.
Since this feature wasn't really used or maintained, let's just remove
it for now, and it can be resurrected on top of OutOfProcessWebView if
someone finds it useful enough to do that work.
This commit is contained in:
Andreas Kling 2022-04-06 14:53:33 +02:00
parent 81aa601637
commit e076f9997f
9 changed files with 0 additions and 436 deletions

View file

@ -18,11 +18,8 @@ set(SOURCES
Debugger/BacktraceModel.cpp
Debugger/DebugInfoWidget.cpp
Debugger/Debugger.cpp
Debugger/DebuggerGlobalJSObject.cpp
Debugger/DebuggerVariableJSObject.cpp
Debugger/DisassemblyModel.cpp
Debugger/DisassemblyWidget.cpp
Debugger/EvaluateExpressionDialog.cpp
Debugger/RegistersModel.cpp
Debugger/VariablesModel.cpp
Dialogs/Git/GitCommitDialog.cpp

View file

@ -1,115 +0,0 @@
/*
* Copyright (c) 2021, Hunter Salyer <thefalsehonesty@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "DebuggerGlobalJSObject.h"
#include "Debugger.h"
#include "DebuggerVariableJSObject.h"
#include <LibJS/Runtime/Completion.h>
#include <LibJS/Runtime/Object.h>
#include <LibJS/Runtime/ProxyObject.h>
namespace HackStudio {
DebuggerGlobalJSObject::DebuggerGlobalJSObject()
{
auto regs = Debugger::the().session()->get_registers();
auto lib = Debugger::the().session()->library_at(regs.ip());
if (!lib)
return;
m_variables = lib->debug_info->get_variables_in_current_scope(regs);
}
JS::ThrowCompletionOr<JS::Value> DebuggerGlobalJSObject::internal_get(JS::PropertyKey const& property_key, JS::Value receiver) const
{
if (m_variables.is_empty() || !property_key.is_string())
return Base::internal_get(property_key, receiver);
auto it = m_variables.find_if([&](auto& variable) {
return variable->name == property_key.as_string();
});
if (it.is_end())
return Base::internal_get(property_key, receiver);
auto& target_variable = **it;
auto js_value = debugger_to_js(target_variable);
if (js_value.has_value())
return js_value.value();
auto error_string = String::formatted("Variable {} of type {} is not convertible to a JS Value", property_key.as_string(), target_variable.type_name);
return vm().throw_completion<JS::TypeError>(const_cast<DebuggerGlobalJSObject&>(*this), move(error_string));
}
JS::ThrowCompletionOr<bool> DebuggerGlobalJSObject::internal_set(JS::PropertyKey const& property_key, JS::Value value, JS::Value receiver)
{
if (m_variables.is_empty() || !property_key.is_string())
return Base::internal_set(property_key, value, receiver);
auto it = m_variables.find_if([&](auto& variable) {
return variable->name == property_key.as_string();
});
if (it.is_end())
return Base::internal_set(property_key, value, receiver);
auto& target_variable = **it;
auto debugger_value = js_to_debugger(value, target_variable);
if (debugger_value.has_value())
return Debugger::the().session()->poke(target_variable.location_data.address, debugger_value.value());
auto error_string = String::formatted("Cannot convert JS value {} to variable {} of type {}", value.to_string_without_side_effects(), property_key.as_string(), target_variable.type_name);
return vm().throw_completion<JS::TypeError>(const_cast<DebuggerGlobalJSObject&>(*this), move(error_string));
}
Optional<JS::Value> DebuggerGlobalJSObject::debugger_to_js(Debug::DebugInfo::VariableInfo const& variable) const
{
if (variable.location_type != Debug::DebugInfo::VariableInfo::LocationType::Address)
return {};
auto variable_address = variable.location_data.address;
if (variable.is_enum_type() || variable.type_name == "int") {
auto value = Debugger::the().session()->peek(variable_address);
VERIFY(value.has_value());
return JS::Value((i32)value.value());
}
if (variable.type_name == "char") {
auto value = Debugger::the().session()->peek(variable_address);
VERIFY(value.has_value());
return JS::Value((char)value.value());
}
if (variable.type_name == "bool") {
auto value = Debugger::the().session()->peek(variable_address);
VERIFY(value.has_value());
return JS::Value(value.value() != 0);
}
auto* object = DebuggerVariableJSObject::create(const_cast<DebuggerGlobalJSObject&>(*this), variable);
for (auto& member : variable.members) {
auto member_value = debugger_to_js(member);
if (!member_value.has_value())
continue;
object->define_direct_property(member.name, member_value.value(), JS::default_attributes);
}
return JS::Value(object);
}
Optional<u32> DebuggerGlobalJSObject::js_to_debugger(JS::Value value, Debug::DebugInfo::VariableInfo const& variable) const
{
if (value.is_string() && variable.type_name == "char") {
auto string = value.as_string().string();
if (string.length() != 1)
return {};
return string[0];
}
if (value.is_number() && (variable.is_enum_type() || variable.type_name == "int"))
return value.as_u32();
if (value.is_boolean() && variable.type_name == "bool")
return value.as_bool();
return {};
}
}

View file

@ -1,34 +0,0 @@
/*
* Copyright (c) 2021, Hunter Salyer <thefalsehonesty@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Weakable.h>
#include <LibDebug/DebugInfo.h>
#include <LibJS/Runtime/Completion.h>
#include <LibJS/Runtime/GlobalObject.h>
namespace HackStudio {
class DebuggerGlobalJSObject final
: public JS::GlobalObject
, public Weakable<DebuggerGlobalJSObject> {
JS_OBJECT(DebuggerGlobalJSObject, JS::GlobalObject);
public:
DebuggerGlobalJSObject();
virtual JS::ThrowCompletionOr<JS::Value> internal_get(JS::PropertyKey const&, JS::Value receiver) const override;
virtual JS::ThrowCompletionOr<bool> internal_set(JS::PropertyKey const&, JS::Value value, JS::Value receiver) override;
Optional<JS::Value> debugger_to_js(Debug::DebugInfo::VariableInfo const&) const;
Optional<u32> js_to_debugger(JS::Value value, Debug::DebugInfo::VariableInfo const&) const;
private:
NonnullOwnPtrVector<Debug::DebugInfo::VariableInfo> m_variables;
};
}

View file

@ -1,58 +0,0 @@
/*
* Copyright (c) 2021, Matthew Olsson <matthewcolsson@gmail.com>
* Copyright (c) 2021, Hunter Salyer <thefalsehonesty@gmail.com>
* Copyright (c) 2022, the SerenityOS developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "DebuggerVariableJSObject.h"
#include "Debugger.h"
#include <LibJS/Runtime/Completion.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/PrimitiveString.h>
#include <LibJS/Runtime/PropertyKey.h>
namespace HackStudio {
DebuggerVariableJSObject* DebuggerVariableJSObject::create(DebuggerGlobalJSObject& global_object, Debug::DebugInfo::VariableInfo const& variable_info)
{
return global_object.heap().allocate<DebuggerVariableJSObject>(global_object, variable_info, *global_object.object_prototype());
}
DebuggerVariableJSObject::DebuggerVariableJSObject(Debug::DebugInfo::VariableInfo const& variable_info, JS::Object& prototype)
: JS::Object(prototype)
, m_variable_info(variable_info)
{
}
JS::ThrowCompletionOr<bool> DebuggerVariableJSObject::internal_set(const JS::PropertyKey& property_key, JS::Value value, JS::Value)
{
auto& vm = this->vm();
if (!property_key.is_string())
return vm.throw_completion<JS::TypeError>(global_object(), String::formatted("Invalid variable name {}", property_key.to_string()));
auto name = property_key.as_string();
auto it = m_variable_info.members.find_if([&](auto& variable) {
return variable->name == name;
});
if (it.is_end())
return vm.throw_completion<JS::TypeError>(global_object(), String::formatted("Variable of type {} has no property {}", m_variable_info.type_name, property_key));
auto& member = **it;
auto new_value = debugger_object().js_to_debugger(value, member);
if (!new_value.has_value())
return vm.throw_completion<JS::TypeError>(global_object(), String::formatted("Cannot convert JS value {} to variable {} of type {}", value.to_string_without_side_effects(), name, member.type_name));
Debugger::the().session()->poke(member.location_data.address, new_value.value());
return true;
}
DebuggerGlobalJSObject& DebuggerVariableJSObject::debugger_object() const
{
return static_cast<DebuggerGlobalJSObject&>(global_object());
}
}

View file

@ -1,38 +0,0 @@
/*
* Copyright (c) 2021, Matthew Olsson <matthewcolsson@gmail.com>
* Copyright (c) 2021, Hunter Salyer <thefalsehonesty@gmail.com>
* Copyright (c) 2022, the SerenityOS developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include "DebuggerGlobalJSObject.h"
#include <AK/StringView.h>
#include <LibDebug/DebugInfo.h>
#include <LibJS/Runtime/Completion.h>
#include <LibJS/Runtime/Object.h>
namespace HackStudio {
class DebuggerVariableJSObject final : public JS::Object {
using Base = JS::Object;
public:
static DebuggerVariableJSObject* create(DebuggerGlobalJSObject&, Debug::DebugInfo::VariableInfo const& variable_info);
DebuggerVariableJSObject(Debug::DebugInfo::VariableInfo const& variable_info, JS::Object& prototype);
virtual ~DebuggerVariableJSObject() override = default;
virtual StringView class_name() const override { return m_variable_info.type_name; }
JS::ThrowCompletionOr<bool> internal_set(JS::PropertyKey const&, JS::Value value, JS::Value receiver) override;
private:
DebuggerGlobalJSObject& debugger_object() const;
Debug::DebugInfo::VariableInfo const& m_variable_info;
};
}

View file

@ -1,147 +0,0 @@
/*
* Copyright (c) 2021, Hunter Salyer <thefalsehonesty@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "EvaluateExpressionDialog.h"
#include "DebuggerGlobalJSObject.h"
#include <LibGUI/BoxLayout.h>
#include <LibGUI/Button.h>
#include <LibGUI/TextBox.h>
#include <LibGUI/Widget.h>
#include <LibGfx/FontDatabase.h>
#include <LibJS/Interpreter.h>
#include <LibJS/MarkupGenerator.h>
#include <LibJS/Parser.h>
#include <LibJS/SyntaxHighlighter.h>
#include <LibWeb/DOM/DocumentType.h>
namespace HackStudio {
static JS::VM& global_vm()
{
static RefPtr<JS::VM> vm;
if (!vm)
vm = JS::VM::create();
return *vm;
}
EvaluateExpressionDialog::EvaluateExpressionDialog(Window* parent_window)
: Dialog(parent_window)
, m_interpreter(JS::Interpreter::create<DebuggerGlobalJSObject>(global_vm()))
{
set_title("Evaluate Expression");
set_icon(parent_window->icon());
build(parent_window);
}
void EvaluateExpressionDialog::build(Window* parent_window)
{
auto& widget = set_main_widget<GUI::Widget>();
int width = max(parent_window->width() / 2, 150);
int height = max(parent_window->height() * (2 / 3), 350);
set_rect(x(), y(), width, height);
widget.set_layout<GUI::VerticalBoxLayout>();
widget.set_fill_with_background_color(true);
widget.layout()->set_margins(6);
widget.layout()->set_spacing(6);
m_text_editor = widget.add<GUI::TextBox>();
m_text_editor->set_fixed_height(19);
m_text_editor->set_syntax_highlighter(make<JS::SyntaxHighlighter>());
m_text_editor->set_font(Gfx::FontDatabase::default_fixed_width_font());
m_text_editor->set_history_enabled(true);
auto base_document = Web::DOM::Document::create();
base_document->append_child(adopt_ref(*new Web::DOM::DocumentType(base_document)));
auto html_element = base_document->create_element("html").release_value();
base_document->append_child(html_element);
auto head_element = base_document->create_element("head").release_value();
html_element->append_child(head_element);
auto body_element = base_document->create_element("body").release_value();
html_element->append_child(body_element);
m_output_container = body_element;
m_output_view = widget.add<Web::InProcessWebView>();
m_output_view->set_document(base_document);
auto& button_container_outer = widget.add<GUI::Widget>();
button_container_outer.set_fixed_height(20);
button_container_outer.set_layout<GUI::VerticalBoxLayout>();
auto& button_container_inner = button_container_outer.add<GUI::Widget>();
button_container_inner.set_layout<GUI::HorizontalBoxLayout>();
button_container_inner.layout()->set_spacing(6);
button_container_inner.layout()->set_margins({ 4, 0, 4 });
button_container_inner.layout()->add_spacer();
m_evaluate_button = button_container_inner.add<GUI::Button>();
m_evaluate_button->set_fixed_height(20);
m_evaluate_button->set_text("Evaluate");
m_evaluate_button->on_click = [this](auto) {
handle_evaluation(m_text_editor->text());
};
m_close_button = button_container_inner.add<GUI::Button>();
m_close_button->set_fixed_height(20);
m_close_button->set_text("Close");
m_close_button->on_click = [this](auto) {
done(ExecOK);
};
m_text_editor->on_return_pressed = [this] {
m_evaluate_button->click();
};
m_text_editor->on_escape_pressed = [this] {
m_close_button->click();
};
m_text_editor->set_focus(true);
}
void EvaluateExpressionDialog::handle_evaluation(String const& expression)
{
m_output_container->remove_all_children();
m_output_view->update();
auto script_or_error = JS::Script::parse(expression, m_interpreter->realm());
StringBuilder output_html;
auto result = JS::ThrowCompletionOr<JS::Value> { JS::js_undefined() };
if (script_or_error.is_error()) {
auto error = script_or_error.error()[0];
auto hint = error.source_location_hint(expression);
if (!hint.is_empty())
output_html.append(String::formatted("<pre>{}</pre>", escape_html_entities(hint)));
result = m_interpreter->vm().throw_completion<JS::SyntaxError>(m_interpreter->global_object(), error.to_string());
} else {
result = m_interpreter->run(script_or_error.value());
}
if (result.is_error()) {
output_html.append("Uncaught exception: ");
auto error = *result.throw_completion().value();
if (error.is_object())
output_html.append(JS::MarkupGenerator::html_from_error(error.as_object()));
else
output_html.append(JS::MarkupGenerator::html_from_value(error));
set_output(output_html.string_view());
return;
}
set_output(JS::MarkupGenerator::html_from_value(result.value()));
}
void EvaluateExpressionDialog::set_output(StringView html)
{
auto paragraph = m_output_container->document().create_element("p").release_value();
paragraph->set_inner_html(html);
m_output_container->append_child(paragraph);
}
}

View file

@ -1,32 +0,0 @@
/*
* Copyright (c) 2021, Hunter Salyer <thefalsehonesty@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibGUI/Dialog.h>
#include <LibWeb/InProcessWebView.h>
namespace HackStudio {
class EvaluateExpressionDialog : public GUI::Dialog {
C_OBJECT(EvaluateExpressionDialog);
private:
explicit EvaluateExpressionDialog(Window* parent_window);
void build(Window* parent_window);
void handle_evaluation(String const& expression);
void set_output(StringView html);
NonnullOwnPtr<JS::Interpreter> m_interpreter;
RefPtr<GUI::TextBox> m_text_editor;
RefPtr<Web::InProcessWebView> m_output_view;
RefPtr<Web::DOM::Element> m_output_container;
RefPtr<GUI::Button> m_evaluate_button;
RefPtr<GUI::Button> m_close_button;
};
}

View file

@ -7,7 +7,6 @@
#include "Editor.h"
#include "Debugger/Debugger.h"
#include "Debugger/EvaluateExpressionDialog.h"
#include "EditorWrapper.h"
#include "HackStudio.h"
#include "Language.h"
@ -56,11 +55,6 @@ Editor::Editor()
create_tokens_info_timer();
set_document(CodeDocument::create());
m_evaluate_expression_action = GUI::Action::create("Evaluate expression", { Mod_Ctrl, Key_E }, [this](auto&) {
VERIFY(is_program_running());
auto dialog = EvaluateExpressionDialog::construct(window());
dialog->exec();
});
m_move_execution_to_line_action = GUI::Action::create("Set execution point to line", [this](auto&) {
VERIFY(is_program_running());
auto success = Debugger::the().set_execution_position(currently_open_file(), cursor().line());
@ -73,7 +67,6 @@ Editor::Editor()
set_debug_mode(false);
add_custom_context_menu_action(*m_evaluate_expression_action);
add_custom_context_menu_action(*m_move_execution_to_line_action);
set_gutter_visible(true);
@ -722,7 +715,6 @@ void Editor::handle_function_parameters_hint_request()
void Editor::set_debug_mode(bool enabled)
{
m_evaluate_expression_action->set_enabled(enabled);
m_move_execution_to_line_action->set_enabled(enabled);
}

View file

@ -120,7 +120,6 @@ private:
bool m_hovering_editor { false };
bool m_hovering_clickable { false };
bool m_autocomplete_in_focus { false };
RefPtr<GUI::Action> m_evaluate_expression_action;
RefPtr<GUI::Action> m_move_execution_to_line_action;
RefPtr<Core::Timer> m_tokens_info_timer; // Used for querying language server for syntax highlighting info
OwnPtr<LanguageClient> m_language_client;