Skip to content

Commit edceae1

Browse files
committed
Open source code errors in external editor
1 parent 0870525 commit edceae1

File tree

3 files changed

+82
-65
lines changed

3 files changed

+82
-65
lines changed

editor/editor_log.cpp

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -200,20 +200,30 @@ void EditorLog::_load_state() {
200200
}
201201

202202
void EditorLog::_meta_clicked(const String &p_meta) {
203-
Ref<RegExMatch> uri_match = RegEx(R"(^([a-zA-Z][a-zA-Z0-9+.-]*):(?://)?(.+?)(?::([0-9]+))?$)").search(p_meta);
204-
if (uri_match.is_null()) {
203+
if (!p_meta.contains_char(':')) {
205204
return;
206205
}
206+
const PackedStringArray parts = p_meta.rsplit(":", true, 1);
207+
String path = parts[0];
208+
const int line = parts[1].to_int() - 1;
207209

208-
String scheme = uri_match->get_string(1);
209-
if (scheme == "res") {
210-
String file = uri_match->get_string(2);
211-
int line = (int)uri_match->get_string(3).to_int();
212-
if (ResourceLoader::exists(file)) {
213-
Ref<Resource> res = ResourceLoader::load(file);
214-
ScriptEditor::get_singleton()->edit(res, line - 1, 0);
210+
if (path.begins_with("res://")) {
211+
if (ResourceLoader::exists(path)) {
212+
const Ref<Resource> res = ResourceLoader::load(path);
213+
ScriptEditor::get_singleton()->edit(res, line, 0);
215214
InspectorDock::get_singleton()->edit_resource(res);
216215
}
216+
} else if (path.has_extension("cpp") || path.has_extension("h") || path.has_extension("mm") || path.has_extension("hpp")) {
217+
// Godot source file. Try to open it in external editor.
218+
if (path.begins_with("./") || path.begins_with(".\\")) {
219+
// Relative path. Convert to absolute, using executable path as reference.
220+
path = path.trim_prefix("./").trim_prefix(".\\");
221+
path = OS::get_singleton()->get_executable_path().get_base_dir().get_base_dir().path_join(path);
222+
}
223+
224+
if (!ScriptEditorPlugin::open_in_external_editor(path, line, -1, true)) {
225+
OS::get_singleton()->shell_open(path);
226+
}
217227
} else {
218228
OS::get_singleton()->shell_open(p_meta);
219229
}

editor/script/script_editor_plugin.cpp

Lines changed: 61 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -2554,63 +2554,11 @@ bool ScriptEditor::edit(const Ref<Resource> &p_resource, int p_line, int p_col,
25542554
if (use_external_editor &&
25552555
(EditorDebuggerNode::get_singleton()->get_dump_stack_script() != p_resource || EditorDebuggerNode::get_singleton()->get_debug_with_external_editor()) &&
25562556
p_resource->get_path().is_resource_file()) {
2557-
String path = EDITOR_GET("text_editor/external/exec_path");
2558-
String flags = EDITOR_GET("text_editor/external/exec_flags");
2559-
2560-
List<String> args;
2561-
bool has_file_flag = false;
2562-
String script_path = ProjectSettings::get_singleton()->globalize_path(p_resource->get_path());
2563-
2564-
if (flags.size()) {
2565-
String project_path = ProjectSettings::get_singleton()->get_resource_path();
2566-
2567-
flags = flags.replacen("{line}", itos(MAX(p_line + 1, 1)));
2568-
flags = flags.replacen("{col}", itos(p_col + 1));
2569-
flags = flags.strip_edges().replace("\\\\", "\\");
2570-
2571-
int from = 0;
2572-
int num_chars = 0;
2573-
bool inside_quotes = false;
2574-
2575-
for (int i = 0; i < flags.size(); i++) {
2576-
if (flags[i] == '"' && (!i || flags[i - 1] != '\\')) {
2577-
if (!inside_quotes) {
2578-
from++;
2579-
}
2580-
inside_quotes = !inside_quotes;
2581-
2582-
} else if (flags[i] == '\0' || (!inside_quotes && flags[i] == ' ')) {
2583-
String arg = flags.substr(from, num_chars);
2584-
if (arg.contains("{file}")) {
2585-
has_file_flag = true;
2586-
}
2587-
2588-
// do path replacement here, else there will be issues with spaces and quotes
2589-
arg = arg.replacen("{project}", project_path);
2590-
arg = arg.replacen("{file}", script_path);
2591-
args.push_back(arg);
2592-
2593-
from = i + 1;
2594-
num_chars = 0;
2595-
} else {
2596-
num_chars++;
2597-
}
2598-
}
2599-
}
2600-
2601-
// Default to passing script path if no {file} flag is specified.
2602-
if (!has_file_flag) {
2603-
args.push_back(script_path);
2604-
}
2605-
2606-
if (!path.is_empty()) {
2607-
Error err = OS::get_singleton()->create_process(path, args);
2608-
if (err == OK) {
2609-
return false;
2610-
}
2557+
if (ScriptEditorPlugin::open_in_external_editor(ProjectSettings::get_singleton()->globalize_path(p_resource->get_path()), p_line, p_col)) {
2558+
return false;
2559+
} else {
2560+
ERR_PRINT("Couldn't open external text editor, falling back to the internal editor. Review your `text_editor/external/` editor settings.");
26112561
}
2612-
2613-
ERR_PRINT("Couldn't open external text editor, falling back to the internal editor. Review your `text_editor/external/` editor settings.");
26142562
}
26152563

26162564
for (int i = 0; i < tab_container->get_tab_count(); i++) {
@@ -4629,6 +4577,63 @@ void ScriptEditorPlugin::_notification(int p_what) {
46294577
}
46304578
}
46314579

4580+
bool ScriptEditorPlugin::open_in_external_editor(const String &p_path, int p_line, int p_col, bool p_ignore_project) {
4581+
const String path = EDITOR_GET("text_editor/external/exec_path");
4582+
if (path.is_empty()) {
4583+
return false;
4584+
}
4585+
4586+
String flags = EDITOR_GET("text_editor/external/exec_flags");
4587+
4588+
List<String> args;
4589+
bool has_file_flag = false;
4590+
4591+
if (!flags.is_empty()) {
4592+
flags = flags.replacen("{line}", itos(MAX(p_line + 1, 1)));
4593+
flags = flags.replacen("{col}", itos(p_col + 1));
4594+
flags = flags.strip_edges().replace("\\\\", "\\");
4595+
4596+
int from = 0;
4597+
int num_chars = 0;
4598+
bool inside_quotes = false;
4599+
4600+
for (int i = 0; i < flags.size(); i++) {
4601+
if (flags[i] == '"' && (!i || flags[i - 1] != '\\')) {
4602+
if (!inside_quotes) {
4603+
from++;
4604+
}
4605+
inside_quotes = !inside_quotes;
4606+
4607+
} else if (flags[i] == '\0' || (!inside_quotes && flags[i] == ' ')) {
4608+
String arg = flags.substr(from, num_chars);
4609+
if (arg.contains("{file}")) {
4610+
has_file_flag = true;
4611+
}
4612+
4613+
// Do path replacement here, else there will be issues with spaces and quotes
4614+
if (p_ignore_project) {
4615+
arg = arg.replacen("{project}", String());
4616+
} else {
4617+
arg = arg.replacen("{project}", ProjectSettings::get_singleton()->get_resource_path());
4618+
}
4619+
arg = arg.replacen("{file}", p_path);
4620+
args.push_back(arg);
4621+
4622+
from = i + 1;
4623+
num_chars = 0;
4624+
} else {
4625+
num_chars++;
4626+
}
4627+
}
4628+
}
4629+
4630+
// Default to passing script path if no {file} flag is specified.
4631+
if (!has_file_flag) {
4632+
args.push_back(p_path);
4633+
}
4634+
return OS::get_singleton()->create_process(path, args) == OK;
4635+
}
4636+
46324637
void ScriptEditorPlugin::edit(Object *p_object) {
46334638
if (Object::cast_to<Script>(p_object)) {
46344639
Script *p_script = Object::cast_to<Script>(p_object);

editor/script/script_editor_plugin.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,8 @@ class ScriptEditorPlugin : public EditorPlugin {
644644
void _notification(int p_what);
645645

646646
public:
647+
static bool open_in_external_editor(const String &p_path, int p_line, int p_col, bool p_ignore_project = false);
648+
647649
virtual String get_plugin_name() const override { return TTRC("Script"); }
648650
bool has_main_screen() const override { return true; }
649651
virtual void edit(Object *p_object) override;

0 commit comments

Comments
 (0)