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:
parent
81aa601637
commit
e076f9997f
9 changed files with 0 additions and 436 deletions
|
@ -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
|
||||
|
|
|
@ -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 {};
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue