Browse Source

Add global breakpoint list

Paulb23 4 years ago
parent
commit
895eb7539a

+ 1 - 0
editor/debugger/editor_debugger_node.cpp

@@ -95,6 +95,7 @@ ScriptEditorDebugger *EditorDebuggerNode::_add_debugger() {
 	node->connect("stopped", callable_mp(this, &EditorDebuggerNode::_debugger_stopped), varray(id));
 	node->connect("stopped", callable_mp(this, &EditorDebuggerNode::_debugger_stopped), varray(id));
 	node->connect("stack_frame_selected", callable_mp(this, &EditorDebuggerNode::_stack_frame_selected), varray(id));
 	node->connect("stack_frame_selected", callable_mp(this, &EditorDebuggerNode::_stack_frame_selected), varray(id));
 	node->connect("error_selected", callable_mp(this, &EditorDebuggerNode::_error_selected), varray(id));
 	node->connect("error_selected", callable_mp(this, &EditorDebuggerNode::_error_selected), varray(id));
+	node->connect("breakpoint_selected", callable_mp(this, &EditorDebuggerNode::_error_selected), varray(id));
 	node->connect("clear_execution", callable_mp(this, &EditorDebuggerNode::_clear_execution));
 	node->connect("clear_execution", callable_mp(this, &EditorDebuggerNode::_clear_execution));
 	node->connect("breaked", callable_mp(this, &EditorDebuggerNode::_breaked), varray(id));
 	node->connect("breaked", callable_mp(this, &EditorDebuggerNode::_breaked), varray(id));
 	node->connect("remote_tree_updated", callable_mp(this, &EditorDebuggerNode::_remote_tree_updated), varray(id));
 	node->connect("remote_tree_updated", callable_mp(this, &EditorDebuggerNode::_remote_tree_updated), varray(id));

+ 113 - 1
editor/debugger/script_editor_debugger.cpp

@@ -788,6 +788,7 @@ void ScriptEditorDebugger::_notification(int p_what) {
 			le_clear->connect("pressed", callable_mp(this, &ScriptEditorDebugger::_live_edit_clear));
 			le_clear->connect("pressed", callable_mp(this, &ScriptEditorDebugger::_live_edit_clear));
 			error_tree->connect("item_selected", callable_mp(this, &ScriptEditorDebugger::_error_selected));
 			error_tree->connect("item_selected", callable_mp(this, &ScriptEditorDebugger::_error_selected));
 			error_tree->connect("item_activated", callable_mp(this, &ScriptEditorDebugger::_error_activated));
 			error_tree->connect("item_activated", callable_mp(this, &ScriptEditorDebugger::_error_activated));
+			breakpoints_tree->connect("item_activated", callable_mp(this, &ScriptEditorDebugger::_breakpoint_tree_clicked));
 			vmem_refresh->set_icon(get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")));
 			vmem_refresh->set_icon(get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")));
 			vmem_export->set_icon(get_theme_icon(SNAME("Save"), SNAME("EditorIcons")));
 			vmem_export->set_icon(get_theme_icon(SNAME("Save"), SNAME("EditorIcons")));
 			search->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
 			search->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
@@ -895,6 +896,13 @@ void ScriptEditorDebugger::_clear_breakpoints() {
 	emit_signal("clear_breakpoints");
 	emit_signal("clear_breakpoints");
 }
 }
 
 
+void ScriptEditorDebugger::_breakpoint_tree_clicked() {
+	TreeItem *selected = breakpoints_tree->get_selected();
+	if (selected->has_meta("line")) {
+		emit_signal(SNAME("breakpoint_selected"), selected->get_parent()->get_text(0), int(selected->get_meta("line")));
+	}
+}
+
 void ScriptEditorDebugger::start(Ref<RemoteDebuggerPeer> p_peer) {
 void ScriptEditorDebugger::start(Ref<RemoteDebuggerPeer> p_peer) {
 	_clear_errors_list();
 	_clear_errors_list();
 	stop();
 	stop();
@@ -1353,6 +1361,45 @@ void ScriptEditorDebugger::set_breakpoint(const String &p_path, int p_line, bool
 	msg.push_back(p_line);
 	msg.push_back(p_line);
 	msg.push_back(p_enabled);
 	msg.push_back(p_enabled);
 	_put_msg("breakpoint", msg);
 	_put_msg("breakpoint", msg);
+
+	TreeItem *path_item = breakpoints_tree->search_item_text(p_path);
+	if (path_item == nullptr) {
+		if (!p_enabled) {
+			return;
+		}
+		path_item = breakpoints_tree->create_item();
+		path_item->set_text(0, p_path);
+	}
+
+	int idx = 0;
+	TreeItem *breakpoint_item;
+	for (breakpoint_item = path_item->get_first_child(); breakpoint_item; breakpoint_item = breakpoint_item->get_next()) {
+		if ((int)breakpoint_item->get_meta("line") < p_line) {
+			idx++;
+			continue;
+		}
+
+		if ((int)breakpoint_item->get_meta("line") == p_line) {
+			break;
+		}
+	}
+
+	if (breakpoint_item == nullptr) {
+		if (!p_enabled) {
+			return;
+		}
+		breakpoint_item = breakpoints_tree->create_item(path_item, idx);
+		breakpoint_item->set_meta("line", p_line);
+		breakpoint_item->set_text(0, vformat(TTR("Line %d"), p_line));
+		return;
+	}
+
+	if (!p_enabled) {
+		path_item->remove_child(breakpoint_item);
+		if (path_item->get_first_child() == nullptr) {
+			breakpoints_tree->get_root()->remove_child(path_item);
+		}
+	}
 }
 }
 
 
 void ScriptEditorDebugger::reload_scripts() {
 void ScriptEditorDebugger::reload_scripts() {
@@ -1419,6 +1466,23 @@ void ScriptEditorDebugger::_clear_errors_list() {
 	clear_button->set_disabled(true);
 	clear_button->set_disabled(true);
 }
 }
 
 
+void ScriptEditorDebugger::_breakpoints_item_rmb_selected(const Vector2 &p_pos) {
+	breakpoints_menu->clear();
+	breakpoints_menu->set_size(Size2(1, 1));
+
+	const TreeItem *selected = breakpoints_tree->get_selected();
+	String file = selected->get_text(0);
+	if (selected->has_meta("line")) {
+		breakpoints_menu->add_icon_item(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), TTR("Delete Breakpoint"), ACTION_DELETE_BREAKPOINT);
+		file = selected->get_parent()->get_text(0);
+	}
+	breakpoints_menu->add_icon_item(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), TTR("Delete All Breakpoints in: ") + file, ACTION_DELETE_BREAKPOINTS_IN_FILE);
+	breakpoints_menu->add_icon_item(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), TTR("Delete All Breakpoints"), ACTION_DELETE_ALL_BREAKPOINTS);
+
+	breakpoints_menu->set_position(breakpoints_tree->get_global_position() + p_pos);
+	breakpoints_menu->popup();
+}
+
 // Right click on specific file(s) or folder(s).
 // Right click on specific file(s) or folder(s).
 void ScriptEditorDebugger::_error_tree_item_rmb_selected(const Vector2 &p_pos) {
 void ScriptEditorDebugger::_error_tree_item_rmb_selected(const Vector2 &p_pos) {
 	item_menu->clear();
 	item_menu->clear();
@@ -1493,6 +1557,29 @@ void ScriptEditorDebugger::_item_menu_id_pressed(int p_option) {
 						line_number));
 						line_number));
 			}
 			}
 		} break;
 		} break;
+		case ACTION_DELETE_BREAKPOINT: {
+			const TreeItem *selected = breakpoints_tree->get_selected();
+			_set_breakpoint(selected->get_parent()->get_text(0), selected->get_meta("line"), false);
+		} break;
+		case ACTION_DELETE_BREAKPOINTS_IN_FILE: {
+			TreeItem *file_item = breakpoints_tree->get_selected();
+			if (file_item->has_meta("line")) {
+				file_item = file_item->get_parent();
+			}
+
+			// Store first else we will be removing as we loop.
+			List<int> lines;
+			for (TreeItem *breakpoint_item = file_item->get_first_child(); breakpoint_item; breakpoint_item = breakpoint_item->get_next()) {
+				lines.push_back(breakpoint_item->get_meta("line"));
+			}
+
+			for (const int &line : lines) {
+				_set_breakpoint(file_item->get_text(0), line, false);
+			}
+		} break;
+		case ACTION_DELETE_ALL_BREAKPOINTS: {
+			_clear_breakpoints();
+		} break;
 	}
 	}
 }
 }
 
 
@@ -1519,6 +1606,7 @@ void ScriptEditorDebugger::_bind_methods() {
 	ADD_SIGNAL(MethodInfo("stop_requested"));
 	ADD_SIGNAL(MethodInfo("stop_requested"));
 	ADD_SIGNAL(MethodInfo("stack_frame_selected", PropertyInfo(Variant::INT, "frame")));
 	ADD_SIGNAL(MethodInfo("stack_frame_selected", PropertyInfo(Variant::INT, "frame")));
 	ADD_SIGNAL(MethodInfo("error_selected", PropertyInfo(Variant::INT, "error")));
 	ADD_SIGNAL(MethodInfo("error_selected", PropertyInfo(Variant::INT, "error")));
+	ADD_SIGNAL(MethodInfo("breakpoint_selected", PropertyInfo("script"), PropertyInfo(Variant::INT, "line")));
 	ADD_SIGNAL(MethodInfo("set_execution", PropertyInfo("script"), PropertyInfo(Variant::INT, "line")));
 	ADD_SIGNAL(MethodInfo("set_execution", PropertyInfo("script"), PropertyInfo(Variant::INT, "line")));
 	ADD_SIGNAL(MethodInfo("clear_execution", PropertyInfo("script")));
 	ADD_SIGNAL(MethodInfo("clear_execution", PropertyInfo("script")));
 	ADD_SIGNAL(MethodInfo("breaked", PropertyInfo(Variant::BOOL, "reallydid"), PropertyInfo(Variant::BOOL, "can_debug"), PropertyInfo(Variant::STRING, "reason"), PropertyInfo(Variant::BOOL, "has_stackdump")));
 	ADD_SIGNAL(MethodInfo("breaked", PropertyInfo(Variant::BOOL, "reallydid"), PropertyInfo(Variant::BOOL, "can_debug"), PropertyInfo(Variant::STRING, "reason"), PropertyInfo(Variant::BOOL, "has_stackdump")));
@@ -1646,9 +1734,15 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) {
 		docontinue->set_shortcut(ED_GET_SHORTCUT("debugger/continue"));
 		docontinue->set_shortcut(ED_GET_SHORTCUT("debugger/continue"));
 		docontinue->connect("pressed", callable_mp(this, &ScriptEditorDebugger::debug_continue));
 		docontinue->connect("pressed", callable_mp(this, &ScriptEditorDebugger::debug_continue));
 
 
+		HSplitContainer *parent_sc = memnew(HSplitContainer);
+		vbc->add_child(parent_sc);
+		parent_sc->set_v_size_flags(SIZE_EXPAND_FILL);
+		parent_sc->set_split_offset(500 * EDSCALE);
+
 		HSplitContainer *sc = memnew(HSplitContainer);
 		HSplitContainer *sc = memnew(HSplitContainer);
-		vbc->add_child(sc);
 		sc->set_v_size_flags(SIZE_EXPAND_FILL);
 		sc->set_v_size_flags(SIZE_EXPAND_FILL);
+		sc->set_h_size_flags(SIZE_EXPAND_FILL);
+		parent_sc->add_child(sc);
 
 
 		stack_dump = memnew(Tree);
 		stack_dump = memnew(Tree);
 		stack_dump->set_allow_reselect(true);
 		stack_dump->set_allow_reselect(true);
@@ -1661,6 +1755,7 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) {
 		sc->add_child(stack_dump);
 		sc->add_child(stack_dump);
 
 
 		VBoxContainer *inspector_vbox = memnew(VBoxContainer);
 		VBoxContainer *inspector_vbox = memnew(VBoxContainer);
+		inspector_vbox->set_h_size_flags(SIZE_EXPAND_FILL);
 		sc->add_child(inspector_vbox);
 		sc->add_child(inspector_vbox);
 
 
 		HBoxContainer *tools_hb = memnew(HBoxContainer);
 		HBoxContainer *tools_hb = memnew(HBoxContainer);
@@ -1683,7 +1778,24 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) {
 		inspector->register_text_enter(search);
 		inspector->register_text_enter(search);
 		inspector->set_use_filter(true);
 		inspector->set_use_filter(true);
 		inspector_vbox->add_child(inspector);
 		inspector_vbox->add_child(inspector);
+		sc->add_child(inspector);
+
+		breakpoints_tree = memnew(Tree);
+		breakpoints_tree->set_h_size_flags(SIZE_EXPAND_FILL);
+		breakpoints_tree->set_column_titles_visible(true);
+		breakpoints_tree->set_column_title(0, TTR("Breakpoints"));
+		breakpoints_tree->set_allow_reselect(true);
+		breakpoints_tree->set_allow_rmb_select(true);
+		breakpoints_tree->set_hide_root(true);
+		breakpoints_tree->connect("item_rmb_selected", callable_mp(this, &ScriptEditorDebugger::_breakpoints_item_rmb_selected));
+		breakpoints_tree->create_item();
+
+		parent_sc->add_child(breakpoints_tree);
 		tabs->add_child(dbg);
 		tabs->add_child(dbg);
+
+		breakpoints_menu = memnew(PopupMenu);
+		breakpoints_menu->connect("id_pressed", callable_mp(this, &ScriptEditorDebugger::_item_menu_id_pressed));
+		breakpoints_tree->add_child(breakpoints_menu);
 	}
 	}
 
 
 	{ //errors
 	{ //errors

+ 9 - 0
editor/debugger/script_editor_debugger.h

@@ -81,6 +81,9 @@ private:
 	enum Actions {
 	enum Actions {
 		ACTION_COPY_ERROR,
 		ACTION_COPY_ERROR,
 		ACTION_OPEN_SOURCE,
 		ACTION_OPEN_SOURCE,
+		ACTION_DELETE_BREAKPOINT,
+		ACTION_DELETE_BREAKPOINTS_IN_FILE,
+		ACTION_DELETE_ALL_BREAKPOINTS,
 	};
 	};
 
 
 	AcceptDialog *msgdialog;
 	AcceptDialog *msgdialog;
@@ -99,6 +102,9 @@ private:
 	Button *clear_button;
 	Button *clear_button;
 	PopupMenu *item_menu;
 	PopupMenu *item_menu;
 
 
+	Tree *breakpoints_tree;
+	PopupMenu *breakpoints_menu;
+
 	EditorFileDialog *file_dialog;
 	EditorFileDialog *file_dialog;
 	enum FileDialogPurpose {
 	enum FileDialogPurpose {
 		SAVE_MONITORS_CSV,
 		SAVE_MONITORS_CSV,
@@ -198,6 +204,7 @@ private:
 
 
 	void _clear_errors_list();
 	void _clear_errors_list();
 
 
+	void _breakpoints_item_rmb_selected(const Vector2 &p_pos);
 	void _error_tree_item_rmb_selected(const Vector2 &p_pos);
 	void _error_tree_item_rmb_selected(const Vector2 &p_pos);
 	void _item_menu_id_pressed(int p_option);
 	void _item_menu_id_pressed(int p_option);
 	void _tab_changed(int p_tab);
 	void _tab_changed(int p_tab);
@@ -211,6 +218,8 @@ private:
 	void _set_breakpoint(const String &p_path, const int &p_line, const bool &p_enabled);
 	void _set_breakpoint(const String &p_path, const int &p_line, const bool &p_enabled);
 	void _clear_breakpoints();
 	void _clear_breakpoints();
 
 
+	void _breakpoint_tree_clicked();
+
 protected:
 protected:
 	void _notification(int p_what);
 	void _notification(int p_what);
 	static void _bind_methods();
 	static void _bind_methods();