Skip to content

Commit 604fe63

Browse files
author
Lewis Pollard
committed
feat: if a .jsx script is opened from the editor, and a valid tsconfig.json is found at the project root, try and open the original .tsx in the external editor rather than the compiled .jsx
1 parent 68ba3a5 commit 604fe63

3 files changed

Lines changed: 105 additions & 2 deletions

File tree

ecmascript.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "scene/resources/text_file.h"
99

1010
#define EXT_JSCLASS "jsx"
11+
#define EXT_TSCLASS "tsx"
1112
#define EXT_JSCLASS_BYTECODE EXT_JSCLASS "b"
1213
#define EXT_JSCLASS_ENCRYPTED EXT_JSCLASS "e"
1314
#define EXT_JSMODULE "js"

ecmascript_language.cpp

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
#include "ecmascript_language.h"
22
#include "core/class_db.h"
33
#include "core/os/file_access.h"
4+
#include "editor/plugins/script_editor_plugin.h"
5+
#include "core/os/os.cpp"
6+
#include "core/io/json.h"
47
ECMAScriptLanguage *ECMAScriptLanguage::singleton = NULL;
58

69
void ECMAScriptLanguage::init() {
@@ -221,6 +224,105 @@ void ECMAScriptLanguage::reload_all_scripts() {
221224
#endif
222225
}
223226

227+
/** If trying to open a .jsx class with an external editor, and we detect a .tsx it's compiled from, open that instead */
228+
Error ECMAScriptLanguage::open_in_external_editor(const Ref<Script>& p_script, int p_line, int p_col) {
229+
Ref<ECMAScript> s = p_script;
230+
if (s->get_script_path().ends_with(EXT_JSCLASS)) {
231+
Error f_err;
232+
FileAccessRef f = FileAccess::open("res://tsconfig.json", FileAccess::READ, &f_err);
233+
if (!f) {
234+
print_line("Failed to read tsconfig.json at project root");
235+
return (Error)ERR_UNAVAILABLE;
236+
}
237+
238+
Error json_parse_err;
239+
String json = f->get_as_utf8_string();
240+
String err_txt;
241+
int err_line;
242+
Variant parsed_json;
243+
json_parse_err = JSON::parse(json, parsed_json, err_txt, err_line);
244+
if (json_parse_err != OK) {
245+
print_error("Failed parsing tsconfig.json");
246+
return (Error)ERR_UNAVAILABLE;
247+
}
248+
249+
String ts_root_dir = parsed_json.get("compilerOptions").get("rootDir");
250+
ts_root_dir = ts_root_dir.replace_first(".", "");
251+
String ts_out_dir = parsed_json.get("compilerOptions").get("outDir");
252+
ts_out_dir = ts_out_dir.replace_first(".", "");
253+
254+
255+
String tsx_path = s->get_script_path().replacen(EXT_JSCLASS, EXT_TSCLASS);
256+
tsx_path = tsx_path.replacen(ts_out_dir, ts_root_dir);
257+
258+
if (!FileAccess::exists(tsx_path)) {
259+
print_line("TSX file doesn't exist at:");
260+
print_line(tsx_path);
261+
return (Error)ERR_UNAVAILABLE;
262+
}
263+
264+
String path = EditorSettings::get_singleton()->get("text_editor/external/exec_path");
265+
String flags = EditorSettings::get_singleton()->get("text_editor/external/exec_flags");
266+
267+
List<String> args;
268+
bool has_file_flag = false;
269+
String script_path = ProjectSettings::get_singleton()->globalize_path(tsx_path);
270+
271+
if (flags.size()) {
272+
String project_path = ProjectSettings::get_singleton()->get_resource_path();
273+
274+
flags = flags.replacen("{line}", itos(p_line > 0 ? p_line : 0));
275+
flags = flags.replacen("{col}", itos(p_col));
276+
flags = flags.strip_edges().replace("\\\\", "\\");
277+
278+
int from = 0;
279+
int num_chars = 0;
280+
bool inside_quotes = false;
281+
282+
for (int i = 0; i < flags.size(); i++) {
283+
284+
if (flags[i] == '"' && (!i || flags[i - 1] != '\\')) {
285+
286+
if (!inside_quotes) {
287+
from++;
288+
}
289+
inside_quotes = !inside_quotes;
290+
291+
} else if (flags[i] == '\0' || (!inside_quotes && flags[i] == ' ')) {
292+
293+
String arg = flags.substr(from, num_chars);
294+
if (arg.find("{file}") != -1) {
295+
has_file_flag = true;
296+
}
297+
298+
// do path replacement here, else there will be issues with spaces and quotes
299+
arg = arg.replacen("{project}", project_path);
300+
arg = arg.replacen("{file}", script_path);
301+
args.push_back(arg);
302+
303+
from = i + 1;
304+
num_chars = 0;
305+
} else {
306+
num_chars++;
307+
}
308+
}
309+
}
310+
311+
// Default to passing script path if no {file} flag is specified.
312+
if (!has_file_flag) {
313+
args.push_back(script_path);
314+
}
315+
316+
Error err = OS::get_singleton()->execute(path, args, false);
317+
if (err == OK)
318+
return err;
319+
WARN_PRINT("Couldn't open external text editor, using internal");
320+
}
321+
322+
323+
return (Error)ERR_UNAVAILABLE;
324+
}
325+
224326
void ECMAScriptLanguage::reload_script(const Ref<Script> &p_script, bool p_soft_reload) {
225327
Ref<ECMAScript> s = p_script;
226328
if (s.is_valid()) {

ecmascript_language.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class ECMAScriptLanguage : public ScriptLanguage {
4949
_FORCE_INLINE_ virtual bool supports_builtin_mode() const { return false; }
5050
_FORCE_INLINE_ virtual bool can_inherit_from_file() { return false; }
5151
_FORCE_INLINE_ virtual bool is_using_templates() { return true; }
52-
_FORCE_INLINE_ virtual bool overrides_external_editor() { return false; }
52+
_FORCE_INLINE_ virtual bool overrides_external_editor() { return true; }
5353

5454
virtual void init();
5555
virtual void finish();
@@ -69,7 +69,7 @@ class ECMAScriptLanguage : public ScriptLanguage {
6969

7070
/* TODO */ virtual int find_function(const String &p_function, const String &p_code) const { return -1; }
7171
/* TODO */ virtual String make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const { return ""; }
72-
/* TODO */ virtual Error open_in_external_editor(const Ref<Script> &p_script, int p_line, int p_col) { return ERR_UNAVAILABLE; }
72+
/* TODO */ virtual Error open_in_external_editor(const Ref<Script> &p_script, int p_line, int p_col);
7373

7474
/* TODO */ virtual Error complete_code(const String &p_code, const String &p_base_path, Object *p_owner, List<String> *r_options, bool &r_force, String &r_call_hint) { return ERR_UNAVAILABLE; }
7575
/* TODO */ virtual Error lookup_code(const String &p_code, const String &p_symbol, const String &p_base_path, Object *p_owner, LookupResult &r_result) { return ERR_UNAVAILABLE; }

0 commit comments

Comments
 (0)