Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support editing JSON in ScriptEditor #72259

Merged
merged 1 commit into from
Feb 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 72 additions & 10 deletions editor/plugins/script_editor_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "core/config/project_settings.h"
#include "core/input/input.h"
#include "core/io/file_access.h"
#include "core/io/json.h"
#include "core/io/resource_loader.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
Expand Down Expand Up @@ -209,6 +210,27 @@ Ref<EditorSyntaxHighlighter> EditorPlainTextSyntaxHighlighter::_create() const {
return syntax_highlighter;
}

////

void EditorJSONSyntaxHighlighter::_update_cache() {
highlighter->set_text_edit(text_edit);
highlighter->clear_keyword_colors();
highlighter->clear_member_keyword_colors();
highlighter->clear_color_regions();

highlighter->set_symbol_color(EDITOR_GET("text_editor/theme/highlighting/symbol_color"));
highlighter->set_number_color(EDITOR_GET("text_editor/theme/highlighting/number_color"));

const Color string_color = EDITOR_GET("text_editor/theme/highlighting/string_color");
highlighter->add_color_region("\"", "\"", string_color);
}

Ref<EditorSyntaxHighlighter> EditorJSONSyntaxHighlighter::_create() const {
Ref<EditorJSONSyntaxHighlighter> syntax_highlighter;
syntax_highlighter.instantiate();
return syntax_highlighter;
}

////////////////////////////////////////////////////////////////////////////////

/*** SCRIPT EDITOR ****/
Expand Down Expand Up @@ -702,9 +724,10 @@ void ScriptEditor::_open_recent_script(int p_idx) {
if (FileAccess::exists(path)) {
List<String> extensions;
ResourceLoader::get_recognized_extensions_for_type("Script", &extensions);
ResourceLoader::get_recognized_extensions_for_type("JSON", &extensions);

if (extensions.find(path.get_extension())) {
Ref<Script> scr = ResourceLoader::load(path);
Ref<Resource> scr = ResourceLoader::load(path);
if (scr.is_valid()) {
edit(scr, true);
return;
Expand Down Expand Up @@ -1182,6 +1205,7 @@ void ScriptEditor::_menu_option(int p_option) {

List<String> extensions;
ResourceLoader::get_recognized_extensions_for_type("Script", &extensions);
ResourceLoader::get_recognized_extensions_for_type("JSON", &extensions);
bool built_in = !path.is_resource_file();

if (extensions.find(path.get_extension()) || built_in) {
Expand All @@ -1196,7 +1220,7 @@ void ScriptEditor::_menu_option(int p_option) {
}
}

Ref<Script> scr = ResourceLoader::load(path);
Ref<Resource> scr = ResourceLoader::load(path);
if (!scr.is_valid()) {
EditorNode::get_singleton()->show_warning(TTR("Could not load file at:") + "\n\n" + path, TTR("Error!"));
file_dialog_option = -1;
Expand Down Expand Up @@ -2319,12 +2343,23 @@ bool ScriptEditor::edit(const Ref<Resource> &p_resource, int p_line, int p_col,
}
se->add_syntax_highlighter(highlighter);

if (scr != nullptr && !highlighter_set) {
PackedStringArray languages = highlighter->_get_supported_languages();
if (highlighter_set) {
continue;
}

PackedStringArray languages = highlighter->_get_supported_languages();
// If script try language, else use extension.
if (scr != nullptr) {
if (languages.has(scr->get_language()->get_name())) {
se->set_syntax_highlighter(highlighter);
highlighter_set = true;
}
continue;
}

if (languages.has(p_resource->get_path().get_extension())) {
se->set_syntax_highlighter(highlighter);
highlighter_set = true;
}
}

Expand Down Expand Up @@ -2536,6 +2571,14 @@ void ScriptEditor::reload_scripts(bool p_refresh_only) {
scr->reload(true);
}

Ref<JSON> json = edited_res;
if (json != nullptr) {
Ref<JSON> rel_json = ResourceLoader::load(json->get_path(), json->get_class(), ResourceFormatLoader::CACHE_MODE_IGNORE);
ERR_CONTINUE(!rel_json.is_valid());
json->parse(rel_json->get_parsed_text(), true);
json->set_last_modified_time(rel_json->get_last_modified_time());
}

Ref<TextFile> text_file = edited_res;
if (text_file != nullptr) {
Error err;
Expand Down Expand Up @@ -2568,8 +2611,9 @@ void ScriptEditor::open_text_file_create_dialog(const String &p_base_path, const
Ref<Resource> ScriptEditor::open_file(const String &p_file) {
List<String> extensions;
ResourceLoader::get_recognized_extensions_for_type("Script", &extensions);
ResourceLoader::get_recognized_extensions_for_type("JSON", &extensions);
if (extensions.find(p_file.get_extension())) {
Ref<Script> scr = ResourceLoader::load(p_file);
Ref<Resource> scr = ResourceLoader::load(p_file);
if (!scr.is_valid()) {
EditorNode::get_singleton()->show_warning(TTR("Could not load file at:") + "\n\n" + p_file, TTR("Error!"));
return Ref<Resource>();
Expand Down Expand Up @@ -2870,8 +2914,8 @@ bool ScriptEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data
if (file.is_empty() || !FileAccess::exists(file)) {
continue;
}
if (ResourceLoader::exists(file, "Script")) {
Ref<Script> scr = ResourceLoader::load(file);
if (ResourceLoader::exists(file, "Script") || ResourceLoader::exists(file, "JSON")) {
Ref<Resource> scr = ResourceLoader::load(file);
if (scr.is_valid()) {
return true;
}
Expand Down Expand Up @@ -2951,7 +2995,7 @@ void ScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Co
continue;
}

if (!ResourceLoader::exists(file, "Script") && !textfile_extensions.has(file.get_extension())) {
if (!ResourceLoader::exists(file, "Script") && !ResourceLoader::exists(file, "JSON") && !textfile_extensions.has(file.get_extension())) {
continue;
}

Expand Down Expand Up @@ -3109,6 +3153,7 @@ void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) {
HashSet<String> loaded_scripts;
List<String> extensions;
ResourceLoader::get_recognized_extensions_for_type("Script", &extensions);
ResourceLoader::get_recognized_extensions_for_type("JSON", &extensions);

for (int i = 0; i < scripts.size(); i++) {
String path = scripts[i];
Expand All @@ -3127,7 +3172,7 @@ void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) {
loaded_scripts.insert(path);

if (extensions.find(path.get_extension())) {
Ref<Script> scr = ResourceLoader::load(path);
Ref<Resource> scr = ResourceLoader::load(path);
if (!scr.is_valid()) {
continue;
}
Expand Down Expand Up @@ -3481,6 +3526,12 @@ void ScriptEditor::_open_script_request(const String &p_path) {
return;
}

Ref<JSON> json = ResourceLoader::load(p_path);
if (json.is_valid()) {
script_editor->edit(json, false);
return;
}

Error err;
Ref<TextFile> text_file = script_editor->_load_text_file(p_path, &err);
if (text_file.is_valid()) {
Expand Down Expand Up @@ -3543,7 +3594,8 @@ void ScriptEditor::_on_find_in_files_result_selected(String fpath, int line_numb
return;
} else {
Ref<Script> scr = res;
if (scr.is_valid()) {
Ref<JSON> json = res;
if (scr.is_valid() || json.is_valid()) {
edit(scr);

ScriptTextEditor *ste = Object::cast_to<ScriptTextEditor>(_get_current_editor());
Expand Down Expand Up @@ -3946,6 +3998,10 @@ ScriptEditor::ScriptEditor() {

add_theme_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox(SNAME("ScriptEditorPanel"), SNAME("EditorStyles")));
tab_container->add_theme_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox(SNAME("ScriptEditor"), SNAME("EditorStyles")));

Ref<EditorJSONSyntaxHighlighter> json_syntax_highlighter;
json_syntax_highlighter.instantiate();
register_syntax_highlighter(json_syntax_highlighter);
}

ScriptEditor::~ScriptEditor() {
Expand All @@ -3967,6 +4023,8 @@ void ScriptEditorPlugin::edit(Object *p_object) {
}
}
script_editor->edit(p_script);
} else if (Object::cast_to<JSON>(p_object)) {
script_editor->edit(Object::cast_to<JSON>(p_object));
} else if (Object::cast_to<TextFile>(p_object)) {
script_editor->edit(Object::cast_to<TextFile>(p_object));
}
Expand All @@ -3981,6 +4039,10 @@ bool ScriptEditorPlugin::handles(Object *p_object) const {
return true;
}

if (Object::cast_to<JSON>(p_object)) {
return true;
}

return p_object->is_class("Script");
}

Expand Down
18 changes: 18 additions & 0 deletions editor/plugins/script_editor_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,24 @@ class EditorPlainTextSyntaxHighlighter : public EditorSyntaxHighlighter {
virtual Ref<EditorSyntaxHighlighter> _create() const override;
};

class EditorJSONSyntaxHighlighter : public EditorSyntaxHighlighter {
GDCLASS(EditorJSONSyntaxHighlighter, EditorSyntaxHighlighter)

private:
Ref<CodeHighlighter> highlighter;

public:
virtual void _update_cache() override;
virtual Dictionary _get_line_syntax_highlighting_impl(int p_line) override { return highlighter->get_line_syntax_highlighting(p_line); }

virtual PackedStringArray _get_supported_languages() const override { return PackedStringArray{ "json" }; }
virtual String _get_name() const override { return TTR("JSON"); }

virtual Ref<EditorSyntaxHighlighter> _create() const override;

EditorJSONSyntaxHighlighter() { highlighter.instantiate(); }
};

///////////////////////////////////////////////////////////////////////////////

class ScriptEditorQuickOpen : public ConfirmationDialog {
Expand Down
71 changes: 58 additions & 13 deletions editor/plugins/text_editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

#include "text_editor.h"

#include "core/io/json.h"
#include "core/os/keyboard.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
Expand Down Expand Up @@ -67,12 +68,12 @@ void TextEditor::_load_theme_settings() {
String TextEditor::get_name() {
String name;

name = text_file->get_path().get_file();
name = edited_res->get_path().get_file();
if (name.is_empty()) {
// This appears for newly created built-in text_files before saving the scene.
name = TTR("[unsaved]");
} else if (text_file->is_built_in()) {
const String &text_file_name = text_file->get_name();
} else if (edited_res->is_built_in()) {
const String &text_file_name = edited_res->get_name();
if (!text_file_name.is_empty()) {
// If the built-in text_file has a custom resource name defined,
// display the built-in text_file name as follows: `ResourceName (scene_file.tscn)`
Expand All @@ -88,20 +89,29 @@ String TextEditor::get_name() {
}

Ref<Texture2D> TextEditor::get_theme_icon() {
return EditorNode::get_singleton()->get_object_icon(text_file.ptr(), "");
return EditorNode::get_singleton()->get_object_icon(edited_res.ptr(), "TextFile");
}

Ref<Resource> TextEditor::get_edited_resource() const {
return text_file;
return edited_res;
}

void TextEditor::set_edited_resource(const Ref<Resource> &p_res) {
ERR_FAIL_COND(text_file.is_valid());
ERR_FAIL_COND(edited_res.is_valid());
ERR_FAIL_COND(p_res.is_null());

text_file = p_res;
edited_res = p_res;

Ref<TextFile> text_file = edited_res;
if (text_file != nullptr) {
code_editor->get_text_editor()->set_text(text_file->get_text());
}

Ref<JSON> json_file = edited_res;
if (json_file != nullptr) {
code_editor->get_text_editor()->set_text(json_file->get_parsed_text());
}

code_editor->get_text_editor()->set_text(text_file->get_text());
code_editor->get_text_editor()->clear_undo_history();
code_editor->get_text_editor()->tag_saved_version();

Expand All @@ -118,6 +128,8 @@ void TextEditor::enable_editor(Control *p_shortcut_context) {

_load_theme_settings();

_validate_script();

if (p_shortcut_context) {
for (int i = 0; i < edit_hb->get_child_count(); ++i) {
Control *c = cast_to<Control>(edit_hb->get_child(i));
Expand All @@ -143,15 +155,24 @@ PackedInt32Array TextEditor::get_breakpoints() {
}

void TextEditor::reload_text() {
ERR_FAIL_COND(text_file.is_null());
ERR_FAIL_COND(edited_res.is_null());

CodeEdit *te = code_editor->get_text_editor();
int column = te->get_caret_column();
int row = te->get_caret_line();
int h = te->get_h_scroll();
int v = te->get_v_scroll();

te->set_text(text_file->get_text());
Ref<TextFile> text_file = edited_res;
if (text_file != nullptr) {
te->set_text(text_file->get_text());
}

Ref<JSON> json_file = edited_res;
if (json_file != nullptr) {
te->set_text(json_file->get_parsed_text());
}

te->set_caret_line(row);
te->set_caret_column(column);
te->set_h_scroll(h);
Expand All @@ -166,6 +187,20 @@ void TextEditor::reload_text() {
void TextEditor::_validate_script() {
emit_signal(SNAME("name_changed"));
emit_signal(SNAME("edited_script_changed"));

Ref<JSON> json_file = edited_res;
if (json_file != nullptr) {
CodeEdit *te = code_editor->get_text_editor();

te->set_line_background_color(code_editor->get_error_pos().x, Color(0, 0, 0, 0));
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_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"));
}
}
}

void TextEditor::_update_bookmark_list() {
Expand Down Expand Up @@ -204,13 +239,22 @@ void TextEditor::_bookmark_item_pressed(int p_idx) {
}

void TextEditor::apply_code() {
text_file->set_text(code_editor->get_text_editor()->get_text());
Ref<TextFile> text_file = edited_res;
if (text_file != nullptr) {
text_file->set_text(code_editor->get_text_editor()->get_text());
}

Ref<JSON> json_file = edited_res;
if (json_file != nullptr) {
json_file->parse(code_editor->get_text_editor()->get_text(), true);
}
code_editor->get_text_editor()->get_syntax_highlighter()->update_cache();
}

bool TextEditor::is_unsaved() {
const bool unsaved =
code_editor->get_text_editor()->get_version() != code_editor->get_text_editor()->get_saved_version() ||
text_file->get_path().is_empty(); // In memory.
edited_res->get_path().is_empty(); // In memory.
return unsaved;
}

Expand Down Expand Up @@ -431,7 +475,7 @@ void TextEditor::_convert_case(CodeTextEditor::CaseStyle p_case) {
}

static ScriptEditorBase *create_editor(const Ref<Resource> &p_resource) {
if (Object::cast_to<TextFile>(*p_resource)) {
if (Object::cast_to<TextFile>(*p_resource) || Object::cast_to<JSON>(*p_resource)) {
return memnew(TextEditor);
}
return nullptr;
Expand Down Expand Up @@ -656,4 +700,5 @@ TextEditor::~TextEditor() {
}

void TextEditor::validate() {
this->code_editor->validate_script();
}
2 changes: 1 addition & 1 deletion editor/plugins/text_editor.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class TextEditor : public ScriptEditorBase {
private:
CodeTextEditor *code_editor = nullptr;

Ref<TextFile> text_file;
Ref<Resource> edited_res;
bool editor_enabled = false;

HBoxContainer *edit_hb = nullptr;
Expand Down