CodeEditor: Make possible to select and copy error text
This commit is contained in:
parent
03bd8ba9c2
commit
db9b8ff003
@ -39,9 +39,13 @@
|
||||
#include "editor/plugins/script_editor_plugin.h"
|
||||
#include "editor/themes/editor_scale.h"
|
||||
#include "editor/themes/editor_theme_manager.h"
|
||||
#include "scene/gui/check_box.h"
|
||||
#include "scene/gui/label.h"
|
||||
#include "scene/gui/line_edit.h"
|
||||
#include "scene/gui/menu_button.h"
|
||||
#include "scene/gui/rich_text_label.h"
|
||||
#include "scene/gui/separator.h"
|
||||
#include "scene/main/timer.h"
|
||||
#include "scene/resources/font.h"
|
||||
|
||||
void GotoLinePopup::popup_find_line(CodeTextEditor *p_text_editor) {
|
||||
@ -716,10 +720,6 @@ bool FindReplaceBar::is_selection_only() const {
|
||||
return selection_only->is_pressed();
|
||||
}
|
||||
|
||||
void FindReplaceBar::set_error(const String &p_label) {
|
||||
emit_signal(SNAME("error"), p_label);
|
||||
}
|
||||
|
||||
void FindReplaceBar::set_text_edit(CodeTextEditor *p_text_editor) {
|
||||
if (p_text_editor == base_text_editor) {
|
||||
return;
|
||||
@ -749,8 +749,6 @@ void FindReplaceBar::set_text_edit(CodeTextEditor *p_text_editor) {
|
||||
|
||||
void FindReplaceBar::_bind_methods() {
|
||||
ClassDB::bind_method("_search_current", &FindReplaceBar::search_current);
|
||||
|
||||
ADD_SIGNAL(MethodInfo("error"));
|
||||
}
|
||||
|
||||
FindReplaceBar::FindReplaceBar() {
|
||||
@ -1187,7 +1185,6 @@ void CodeTextEditor::set_find_replace_bar(FindReplaceBar *p_bar) {
|
||||
|
||||
find_replace_bar = p_bar;
|
||||
find_replace_bar->set_text_edit(this);
|
||||
find_replace_bar->connect("error", callable_mp(error, &Label::set_text));
|
||||
}
|
||||
|
||||
void CodeTextEditor::remove_find_replace_bar() {
|
||||
@ -1195,7 +1192,6 @@ void CodeTextEditor::remove_find_replace_bar() {
|
||||
return;
|
||||
}
|
||||
|
||||
find_replace_bar->disconnect("error", callable_mp(error, &Label::set_text));
|
||||
find_replace_bar = nullptr;
|
||||
}
|
||||
|
||||
@ -1516,20 +1512,35 @@ Variant CodeTextEditor::get_navigation_state() {
|
||||
}
|
||||
|
||||
void CodeTextEditor::set_error(const String &p_error) {
|
||||
// Trim the error message if it is more than 2 lines long.
|
||||
if (p_error.count("\n") >= 2) {
|
||||
Vector<String> splits = p_error.split("\n");
|
||||
String trimmed_error = String("\n").join(splits.slice(0, 2));
|
||||
error->set_text(trimmed_error + "...");
|
||||
error->set_text(p_error);
|
||||
|
||||
_update_error_content_height();
|
||||
|
||||
if (p_error.is_empty()) {
|
||||
error->set_default_cursor_shape(CURSOR_ARROW);
|
||||
} else {
|
||||
error->set_text(p_error);
|
||||
error->set_default_cursor_shape(CURSOR_POINTING_HAND);
|
||||
}
|
||||
}
|
||||
|
||||
void CodeTextEditor::_update_error_content_height() {
|
||||
float margin_height = 0;
|
||||
const Ref<StyleBox> style = error->get_theme_stylebox(CoreStringName(normal));
|
||||
if (style.is_valid()) {
|
||||
margin_height += style->get_content_margin(SIDE_TOP) + style->get_content_margin(SIDE_BOTTOM);
|
||||
}
|
||||
|
||||
if (!p_error.is_empty()) {
|
||||
error->set_default_cursor_shape(CURSOR_POINTING_HAND);
|
||||
} else {
|
||||
error->set_default_cursor_shape(CURSOR_ARROW);
|
||||
const float content_height = margin_height + error->get_content_height();
|
||||
|
||||
float content_max_height = margin_height;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (i >= error->get_line_count()) {
|
||||
break;
|
||||
}
|
||||
content_max_height += error->get_line_height(i);
|
||||
}
|
||||
|
||||
error->set_custom_minimum_size(Size2(0, CLAMP(content_height, 0, content_max_height)));
|
||||
}
|
||||
|
||||
void CodeTextEditor::set_error_pos(int p_line, int p_column) {
|
||||
@ -1559,28 +1570,36 @@ void CodeTextEditor::goto_error() {
|
||||
void CodeTextEditor::_update_text_editor_theme() {
|
||||
emit_signal(SNAME("load_theme_settings"));
|
||||
|
||||
error_button->set_button_icon(get_editor_theme_icon(SNAME("StatusError")));
|
||||
warning_button->set_button_icon(get_editor_theme_icon(SNAME("NodeWarning")));
|
||||
|
||||
Ref<Font> status_bar_font = get_theme_font(SNAME("status_source"), EditorStringName(EditorFonts));
|
||||
int status_bar_font_size = get_theme_font_size(SNAME("status_source_size"), EditorStringName(EditorFonts));
|
||||
|
||||
int count = status_bar->get_child_count();
|
||||
for (int i = 0; i < count; i++) {
|
||||
Control *n = Object::cast_to<Control>(status_bar->get_child(i));
|
||||
if (n) {
|
||||
n->add_theme_font_override(SceneStringName(font), status_bar_font);
|
||||
n->add_theme_font_size_override(SceneStringName(font_size), status_bar_font_size);
|
||||
}
|
||||
}
|
||||
|
||||
const Ref<Font> status_bar_font = get_theme_font(SNAME("status_source"), EditorStringName(EditorFonts));
|
||||
const int status_bar_font_size = get_theme_font_size(SNAME("status_source_size"), EditorStringName(EditorFonts));
|
||||
const Color &error_color = get_theme_color(SNAME("error_color"), EditorStringName(Editor));
|
||||
const Color &warning_color = get_theme_color(SNAME("warning_color"), EditorStringName(Editor));
|
||||
const Ref<StyleBox> label_stylebox = get_theme_stylebox(SNAME("normal"), SNAME("Label")); // Empty stylebox.
|
||||
|
||||
error->add_theme_color_override(SceneStringName(font_color), error_color);
|
||||
error->begin_bulk_theme_override();
|
||||
error->add_theme_font_override(SNAME("normal_font"), status_bar_font);
|
||||
error->add_theme_font_size_override(SNAME("normal_font_size"), status_bar_font_size);
|
||||
error->add_theme_color_override(SNAME("default_color"), error_color);
|
||||
error->add_theme_style_override(SNAME("normal"), label_stylebox);
|
||||
error->end_bulk_theme_override();
|
||||
|
||||
error_button->set_button_icon(get_editor_theme_icon(SNAME("StatusError")));
|
||||
error_button->add_theme_color_override(SceneStringName(font_color), error_color);
|
||||
|
||||
warning_button->set_button_icon(get_editor_theme_icon(SNAME("NodeWarning")));
|
||||
warning_button->add_theme_color_override(SceneStringName(font_color), warning_color);
|
||||
|
||||
const int child_count = status_bar->get_child_count();
|
||||
for (int i = 0; i < child_count; i++) {
|
||||
Control *child = Object::cast_to<Control>(status_bar->get_child(i));
|
||||
if (child) {
|
||||
child->begin_bulk_theme_override();
|
||||
child->add_theme_font_override(SceneStringName(font), status_bar_font);
|
||||
child->add_theme_font_size_override(SceneStringName(font_size), status_bar_font_size);
|
||||
child->end_bulk_theme_override();
|
||||
}
|
||||
}
|
||||
|
||||
_update_font_ligatures();
|
||||
}
|
||||
|
||||
@ -1909,19 +1928,16 @@ CodeTextEditor::CodeTextEditor() {
|
||||
toggle_files_button->hide();
|
||||
|
||||
// Error
|
||||
ScrollContainer *scroll = memnew(ScrollContainer);
|
||||
scroll->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
scroll->set_v_size_flags(SIZE_EXPAND_FILL);
|
||||
scroll->set_vertical_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
|
||||
status_bar->add_child(scroll);
|
||||
|
||||
error = memnew(Label);
|
||||
error->set_focus_mode(FOCUS_ACCESSIBILITY);
|
||||
error = memnew(RichTextLabel);
|
||||
error->set_use_bbcode(true);
|
||||
error->set_selection_enabled(true);
|
||||
error->set_context_menu_enabled(true);
|
||||
error->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
|
||||
error->set_v_size_flags(SIZE_EXPAND | SIZE_SHRINK_CENTER);
|
||||
error->set_mouse_filter(MOUSE_FILTER_STOP);
|
||||
scroll->add_child(error);
|
||||
error->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
error->set_v_size_flags(SIZE_SHRINK_CENTER);
|
||||
error->connect(SceneStringName(gui_input), callable_mp(this, &CodeTextEditor::_error_pressed));
|
||||
error->connect(SceneStringName(resized), callable_mp(this, &CodeTextEditor::_update_error_content_height));
|
||||
status_bar->add_child(error);
|
||||
|
||||
// Errors
|
||||
error_button = memnew(Button);
|
||||
|
@ -31,17 +31,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "scene/gui/box_container.h"
|
||||
#include "scene/gui/button.h"
|
||||
#include "scene/gui/check_box.h"
|
||||
#include "scene/gui/code_edit.h"
|
||||
#include "scene/gui/dialogs.h"
|
||||
#include "scene/gui/label.h"
|
||||
#include "scene/gui/popup.h"
|
||||
#include "scene/main/timer.h"
|
||||
|
||||
class MenuButton;
|
||||
class Button;
|
||||
class CheckBox;
|
||||
class CodeTextEditor;
|
||||
class Label;
|
||||
class LineEdit;
|
||||
class MenuButton;
|
||||
class RichTextLabel;
|
||||
class Timer;
|
||||
|
||||
class GotoLinePopup : public PopupPanel {
|
||||
GDCLASS(GotoLinePopup, PopupPanel);
|
||||
@ -138,7 +138,6 @@ public:
|
||||
bool is_case_sensitive() const;
|
||||
bool is_whole_words() const;
|
||||
bool is_selection_only() const;
|
||||
void set_error(const String &p_label);
|
||||
|
||||
void set_text_edit(CodeTextEditor *p_text_editor);
|
||||
|
||||
@ -183,7 +182,7 @@ class CodeTextEditor : public VBoxContainer {
|
||||
|
||||
float zoom_factor = 1.0f;
|
||||
|
||||
Label *error = nullptr;
|
||||
RichTextLabel *error = nullptr;
|
||||
int error_line;
|
||||
int error_column;
|
||||
|
||||
@ -211,6 +210,8 @@ class CodeTextEditor : public VBoxContainer {
|
||||
void _zoom_out();
|
||||
void _zoom_to(float p_zoom_factor);
|
||||
|
||||
void _update_error_content_height();
|
||||
|
||||
void _error_button_pressed();
|
||||
void _warning_button_pressed();
|
||||
void _set_show_errors_panel(bool p_show);
|
||||
|
@ -643,6 +643,7 @@ void ScriptEditorDebugger::_msg_error(uint64_t p_thread_id, const Array &p_data)
|
||||
// item with the original error condition.
|
||||
error_title += oe.error_descr.is_empty() ? oe.error : oe.error_descr;
|
||||
error->set_text(1, error_title);
|
||||
error->set_autowrap_mode(1, TextServer::AUTOWRAP_WORD_SMART);
|
||||
tooltip += " " + error_title + "\n";
|
||||
|
||||
// Find the language of the error's source file.
|
||||
@ -980,16 +981,20 @@ void ScriptEditorDebugger::_init_parse_message_handlers() {
|
||||
void ScriptEditorDebugger::_set_reason_text(const String &p_reason, MessageType p_type) {
|
||||
switch (p_type) {
|
||||
case MESSAGE_ERROR:
|
||||
reason->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("error_color"), EditorStringName(Editor)));
|
||||
reason->add_theme_color_override(SNAME("default_color"), get_theme_color(SNAME("error_color"), EditorStringName(Editor)));
|
||||
break;
|
||||
case MESSAGE_WARNING:
|
||||
reason->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("warning_color"), EditorStringName(Editor)));
|
||||
reason->add_theme_color_override(SNAME("default_color"), get_theme_color(SNAME("warning_color"), EditorStringName(Editor)));
|
||||
break;
|
||||
default:
|
||||
reason->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("success_color"), EditorStringName(Editor)));
|
||||
reason->add_theme_color_override(SNAME("default_color"), get_theme_color(SNAME("success_color"), EditorStringName(Editor)));
|
||||
break;
|
||||
}
|
||||
|
||||
reason->set_text(p_reason);
|
||||
|
||||
_update_reason_content_height();
|
||||
|
||||
const PackedInt32Array boundaries = TS->string_get_word_breaks(p_reason, "", 80);
|
||||
PackedStringArray lines;
|
||||
for (int i = 0; i < boundaries.size(); i += 2) {
|
||||
@ -1001,6 +1006,26 @@ void ScriptEditorDebugger::_set_reason_text(const String &p_reason, MessageType
|
||||
reason->set_tooltip_text(String("\n").join(lines));
|
||||
}
|
||||
|
||||
void ScriptEditorDebugger::_update_reason_content_height() {
|
||||
float margin_height = 0;
|
||||
const Ref<StyleBox> style = reason->get_theme_stylebox(CoreStringName(normal));
|
||||
if (style.is_valid()) {
|
||||
margin_height += style->get_content_margin(SIDE_TOP) + style->get_content_margin(SIDE_BOTTOM);
|
||||
}
|
||||
|
||||
const float content_height = margin_height + reason->get_content_height();
|
||||
|
||||
float content_max_height = margin_height;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (i >= reason->get_line_count()) {
|
||||
break;
|
||||
}
|
||||
content_max_height += reason->get_line_height(i);
|
||||
}
|
||||
|
||||
reason->set_custom_minimum_size(Size2(0, CLAMP(content_height, 0, content_max_height)));
|
||||
}
|
||||
|
||||
void ScriptEditorDebugger::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
@ -1031,7 +1056,8 @@ void ScriptEditorDebugger::_notification(int p_what) {
|
||||
vmem_export->set_button_icon(get_editor_theme_icon(SNAME("Save")));
|
||||
search->set_right_icon(get_editor_theme_icon(SNAME("Search")));
|
||||
|
||||
reason->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("error_color"), EditorStringName(Editor)));
|
||||
reason->add_theme_color_override(SNAME("default_color"), get_theme_color(SNAME("error_color"), EditorStringName(Editor)));
|
||||
reason->add_theme_style_override(SNAME("normal"), get_theme_stylebox(SNAME("normal"), SNAME("Label"))); // Empty stylebox.
|
||||
|
||||
TreeItem *error_root = error_tree->get_root();
|
||||
if (error_root) {
|
||||
@ -1245,6 +1271,7 @@ void ScriptEditorDebugger::stop() {
|
||||
peer.unref();
|
||||
reason->set_text("");
|
||||
reason->set_tooltip_text("");
|
||||
reason->set_custom_minimum_size(Size2(0, 0));
|
||||
}
|
||||
|
||||
node_path_cache.clear();
|
||||
@ -1966,14 +1993,14 @@ ScriptEditorDebugger::ScriptEditorDebugger() {
|
||||
HBoxContainer *hbc = memnew(HBoxContainer);
|
||||
vbc->add_child(hbc);
|
||||
|
||||
reason = memnew(Label);
|
||||
reason = memnew(RichTextLabel);
|
||||
reason->set_focus_mode(FOCUS_ACCESSIBILITY);
|
||||
reason->set_text("");
|
||||
hbc->add_child(reason);
|
||||
reason->set_selection_enabled(true);
|
||||
reason->set_context_menu_enabled(true);
|
||||
reason->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
reason->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);
|
||||
reason->set_max_lines_visible(3);
|
||||
reason->set_mouse_filter(Control::MOUSE_FILTER_PASS);
|
||||
reason->set_v_size_flags(SIZE_SHRINK_CENTER);
|
||||
reason->connect(SceneStringName(resized), callable_mp(this, &ScriptEditorDebugger::_update_reason_content_height));
|
||||
hbc->add_child(reason);
|
||||
|
||||
hbc->add_child(memnew(VSeparator));
|
||||
|
||||
|
@ -118,7 +118,7 @@ private:
|
||||
|
||||
TabContainer *tabs = nullptr;
|
||||
|
||||
Label *reason = nullptr;
|
||||
RichTextLabel *reason = nullptr;
|
||||
|
||||
Button *skip_breakpoints = nullptr;
|
||||
Button *ignore_error_breaks = nullptr;
|
||||
@ -231,6 +231,7 @@ private:
|
||||
|
||||
void _parse_message(const String &p_msg, uint64_t p_thread_id, const Array &p_data);
|
||||
void _set_reason_text(const String &p_reason, MessageType p_type);
|
||||
void _update_reason_content_height();
|
||||
void _update_buttons_state();
|
||||
void _remote_object_selected(ObjectID p_object);
|
||||
void _remote_objects_edited(const String &p_prop, const TypedDictionary<uint64_t, Variant> &p_values, const String &p_field);
|
||||
|
@ -819,10 +819,12 @@ void ScriptTextEditor::_validate_script() {
|
||||
}
|
||||
|
||||
if (errors.size() > 0) {
|
||||
// TRANSLATORS: Script error pointing to a line and column number.
|
||||
String error_text = vformat(TTR("Error at (%d, %d):"), errors.front()->get().line, errors.front()->get().column) + " " + errors.front()->get().message;
|
||||
const int line = errors.front()->get().line;
|
||||
const int column = errors.front()->get().column;
|
||||
const String message = errors.front()->get().message.replace("[", "[lb]");
|
||||
const String error_text = vformat(TTR("Error at ([hint=Line %d, column %d]%d, %d[/hint]):"), line, column, line, column) + " " + message;
|
||||
code_editor->set_error(error_text);
|
||||
code_editor->set_error_pos(errors.front()->get().line - 1, errors.front()->get().column - 1);
|
||||
code_editor->set_error_pos(line - 1, column - 1);
|
||||
}
|
||||
script_is_valid = false;
|
||||
} else {
|
||||
|
@ -200,7 +200,7 @@ void TextEditor::_validate_script() {
|
||||
code_editor->set_error("");
|
||||
|
||||
if (json_file->parse(te->get_text(), true) != OK) {
|
||||
code_editor->set_error(json_file->get_error_message());
|
||||
code_editor->set_error(json_file->get_error_message().replace("[", "[lb]"));
|
||||
code_editor->set_error_pos(json_file->get_error_line(), 0);
|
||||
te->set_line_background_color(code_editor->get_error_pos().x, EDITOR_GET("text_editor/theme/highlighting/mark_color"));
|
||||
}
|
||||
|
@ -515,28 +515,35 @@ void ShaderTextEditor::_validate_script() {
|
||||
set_error_count(0);
|
||||
|
||||
if (last_compile_result != OK) {
|
||||
//preprocessor error
|
||||
// Preprocessor error.
|
||||
ERR_FAIL_COND(err_positions.is_empty());
|
||||
|
||||
String err_text = error_pp;
|
||||
int err_line = err_positions.front()->get().line;
|
||||
String err_text;
|
||||
const int err_line = err_positions.front()->get().line;
|
||||
if (err_positions.size() == 1) {
|
||||
// Error in main file
|
||||
err_text = "error(" + itos(err_line) + "): " + err_text;
|
||||
// Error in the main file.
|
||||
const String message = error_pp.replace("[", "[lb]");
|
||||
|
||||
err_text = vformat(TTR("Error at line %d:"), err_line) + " " + message;
|
||||
} else {
|
||||
err_text = "error(" + itos(err_line) + ") in include " + err_positions.back()->get().file.get_file() + ":" + itos(err_positions.back()->get().line) + ": " + err_text;
|
||||
// Error in an included file.
|
||||
const String inc_file = err_positions.back()->get().file.get_file();
|
||||
const int inc_line = err_positions.back()->get().line;
|
||||
const String message = error_pp.replace("[", "[lb]");
|
||||
|
||||
err_text = vformat(TTR("Error at line %d in include %s:%d:"), err_line, inc_file, inc_line) + " " + message;
|
||||
set_error_count(err_positions.size() - 1);
|
||||
}
|
||||
|
||||
set_error(err_text);
|
||||
set_error_pos(err_line - 1, 0);
|
||||
|
||||
for (int i = 0; i < get_text_editor()->get_line_count(); i++) {
|
||||
get_text_editor()->set_line_background_color(i, Color(0, 0, 0, 0));
|
||||
}
|
||||
get_text_editor()->set_line_background_color(err_line - 1, marked_line_color);
|
||||
|
||||
set_warning_count(0);
|
||||
|
||||
} else {
|
||||
ShaderLanguage sl;
|
||||
|
||||
@ -579,21 +586,33 @@ void ShaderTextEditor::_validate_script() {
|
||||
last_compile_result = sl.compile(code, comp_info);
|
||||
|
||||
if (last_compile_result != OK) {
|
||||
Vector<ShaderLanguage::FilePosition> include_positions = sl.get_include_positions();
|
||||
|
||||
String err_text;
|
||||
int err_line;
|
||||
Vector<ShaderLanguage::FilePosition> include_positions = sl.get_include_positions();
|
||||
if (include_positions.size() > 1) {
|
||||
//error is in an include
|
||||
// Error in an included file.
|
||||
err_line = include_positions[0].line;
|
||||
err_text = "error(" + itos(err_line) + ") in include " + include_positions[include_positions.size() - 1].file + ":" + itos(include_positions[include_positions.size() - 1].line) + ": " + sl.get_error_text();
|
||||
|
||||
const String inc_file = include_positions[include_positions.size() - 1].file;
|
||||
const int inc_line = include_positions[include_positions.size() - 1].line;
|
||||
const String message = sl.get_error_text().replace("[", "[lb]");
|
||||
|
||||
err_text = vformat(TTR("Error at line %d in include %s:%d:"), err_line, inc_file, inc_line) + " " + message;
|
||||
set_error_count(include_positions.size() - 1);
|
||||
} else {
|
||||
// Error in the main file.
|
||||
err_line = sl.get_error_line();
|
||||
err_text = "error(" + itos(err_line) + "): " + sl.get_error_text();
|
||||
|
||||
const String message = sl.get_error_text().replace("[", "[lb]");
|
||||
|
||||
err_text = vformat(TTR("Error at line %d:"), err_line) + " " + message;
|
||||
set_error_count(0);
|
||||
}
|
||||
|
||||
set_error(err_text);
|
||||
set_error_pos(err_line - 1, 0);
|
||||
|
||||
get_text_editor()->set_line_background_color(err_line - 1, marked_line_color);
|
||||
} else {
|
||||
set_error("");
|
||||
@ -624,9 +643,12 @@ void ShaderTextEditor::_update_warning_panel() {
|
||||
for (const ShaderWarning &w : warnings) {
|
||||
if (warning_count == 0) {
|
||||
if (saved_treat_warning_as_errors) {
|
||||
String error_text = "error(" + itos(w.get_line()) + "): " + w.get_message() + " " + TTR("Warnings should be fixed to prevent errors.");
|
||||
set_error_pos(w.get_line() - 1, 0);
|
||||
const String message = (w.get_message() + " " + TTR("Warnings should be fixed to prevent errors.")).replace("[", "[lb]");
|
||||
const String error_text = vformat(TTR("Error at line %d:"), w.get_line()) + " " + message;
|
||||
|
||||
set_error(error_text);
|
||||
set_error_pos(w.get_line() - 1, 0);
|
||||
|
||||
get_text_editor()->set_line_background_color(w.get_line() - 1, marked_line_color);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user