7#include "absl/strings/match.h"
8#include "absl/strings/str_format.h"
9#include "absl/strings/str_split.h"
13#include "imgui/imgui.h"
32 ImGui::SetNextWindowSize(ImVec2(900, 700), ImGuiCond_FirstUseEver);
33 if (!ImGui::Begin(absl::StrFormat(
"%s Project Editor###ProjectFileEditor",
42 if (ImGui::BeginTable(
"ProjectEditorToolbar", 10,
43 ImGuiTableFlags_SizingFixedFit)) {
44 ImGui::TableNextColumn();
49 ImGui::TableNextColumn();
62 ImGui::TableNextColumn();
65 ImGui::BeginDisabled();
66 if (ImGui::Button(absl::StrFormat(
"%s Save",
ICON_MD_SAVE).c_str())) {
77 ImGui::TableNextColumn();
78 if (ImGui::Button(absl::StrFormat(
"%s Save As",
ICON_MD_SAVE_AS).c_str())) {
92 ImGui::TableNextColumn();
95 ImGui::TableNextColumn();
98 absl::StrFormat(
"%s Import Labels",
ICON_MD_LABEL).c_str())) {
104 std::string(status.message().data(), status.message().size()),
108 if (ImGui::IsItemHovered()) {
109 ImGui::SetTooltip(
"Import labels from ZScream DefaultNames.txt");
112 ImGui::TableNextColumn();
119 ImGui::TableNextColumn();
122 ImGui::TableNextColumn();
124 ImGui::TextDisabled(
"%s",
filepath_.c_str());
126 ImGui::TextDisabled(
"No file loaded");
136 ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.3f, 0.2f, 0.2f, 0.5f));
137 if (ImGui::BeginChild(
"ValidationErrors", ImVec2(0, 100),
true)) {
138 ImGui::TextColored(ImVec4(1.0f, 0.4f, 0.4f, 1.0f),
141 ImGui::BulletText(
"%s", error.c_str());
145 ImGui::PopStyleColor();
149 ImVec2 editor_size = ImGui::GetContentRegionAvail();
157 std::string key = std::filesystem::path(
filepath).stem().string();
161 auto storage_or = platform::WasmStorage::LoadProject(key);
162 if (storage_or.ok()) {
167 return absl::OkStatus();
172 if (!file.is_open()) {
173 return absl::InvalidArgumentError(
174 absl::StrFormat(
"Cannot open file: %s",
filepath));
177 std::stringstream buffer;
178 buffer << file.rdbuf();
187 return absl::OkStatus();
192 return absl::InvalidArgumentError(
"No file path specified");
201 if (!absl::EndsWith(final_path,
".yaze")) {
202 final_path +=
".yaze";
206 std::string key = std::filesystem::path(final_path).stem().string();
210 auto storage_status =
212 if (!storage_status.ok()) {
213 return storage_status;
220 return absl::OkStatus();
222 std::ofstream file(final_path);
223 if (!file.is_open()) {
224 return absl::InvalidArgumentError(
225 absl::StrFormat(
"Cannot create file: %s", final_path));
239 return absl::OkStatus();
245 const char* template_content = R
"(# yaze Project File
264ollama_host=http://localhost:11434
265use_custom_prompt=false
269rom_backup_folder=backups
272patches_folder=patches
273labels_filename=labels.txt
274symbols_filename=symbols.txt
279# REMOVED: kLogInstructions - DisassemblyViewer is always active
281kSaveGraphicsSheet=true
282kLoadCustomOverworld=false
287autosave_interval_secs=300
294asm_entry_point=asm/main.asm
300persist_custom_music=true
320 std::vector<std::string> lines = absl::StrSplit(content,
'\n');
322 std::string current_section;
325 for (
const auto& line : lines) {
327 std::string trimmed = std::string(absl::StripAsciiWhitespace(line));
330 if (trimmed.empty() || trimmed[0] ==
'#')
334 if (trimmed[0] ==
'[' && trimmed[trimmed.size() - 1] ==
']') {
335 current_section = trimmed.substr(1, trimmed.size() - 2);
338 if (current_section !=
"project" && current_section !=
"files" &&
339 current_section !=
"feature_flags" &&
340 current_section !=
"workspace" &&
341 current_section !=
"workspace_settings" &&
342 current_section !=
"build" && current_section !=
"agent_settings" &&
343 current_section !=
"music" && current_section !=
"keybindings" &&
344 current_section !=
"editor_visibility") {
346 "Line %d: Unknown section [%s]", line_num, current_section));
352 size_t equals_pos = trimmed.find(
'=');
353 if (equals_pos == std::string::npos) {
355 "Line %d: Invalid format, expected key=value", line_num));
369 ImGui::TextColored(ImVec4(1.0f, 0.3f, 0.3f, 1.0f),
"Validation Errors:");
371 ImGui::BulletText(
"%s", error.c_str());
377 return absl::UnimplementedError(
378 "File-based label import is not supported in the web build");
381 return absl::FailedPreconditionError(
382 "No project loaded. Open a project first.");
388 return absl::CancelledError(
"No file selected");
392 std::ifstream input_file(file);
393 if (!input_file.is_open()) {
394 return absl::InvalidArgumentError(
395 absl::StrFormat(
"Cannot open file: %s", file));
398 std::stringstream buffer;
399 buffer << input_file.rdbuf();
void SetShowWhitespaces(bool aValue)
std::string GetText() const
void Render(const char *aTitle, const ImVec2 &aSize=ImVec2(), bool aBorder=false)
void SetText(const std::string &aText)
void SetTabSize(int aValue)
void SetLanguageDefinition(const LanguageDefinition &aLanguageDef)
void ApplySyntaxHighlighting()
ToastManager * toast_manager_
absl::Status SaveFileAs(const std::string &filepath)
Save to a new file path.
absl::Status LoadFile(const std::string &filepath)
Load a project file into the editor.
void NewFile()
Create a new empty project file.
bool IsModified() const
Get whether the file has unsaved changes.
std::vector< std::string > validation_errors_
absl::Status SaveFile()
Save the current editor contents to disk.
absl::Status ImportLabelsFromZScream()
Import labels from a ZScream DefaultNames.txt file.
project::YazeProject * project_
void ShowValidationErrors()
const std::string & filepath() const
Get the current filepath.
void Show(const std::string &message, ToastType type=ToastType::kInfo, float ttl_seconds=3.0f)
static RecentFilesManager & GetInstance()
static std::string ShowSaveFileDialog(const std::string &default_name="", const std::string &default_extension="")
ShowSaveFileDialog opens a save file dialog and returns the selected filepath. Uses global feature fl...
static std::string ShowOpenFileDialog()
ShowOpenFileDialog opens a file dialog and returns the selected filepath. Uses global feature flag to...
#define ICON_MD_FOLDER_OPEN
#define ICON_MD_CHECK_CIRCLE
#define ICON_MD_DESCRIPTION
static const LanguageDefinition & C()
absl::Status ImportLabelsFromZScreamContent(const std::string &content)
Import labels from ZScream format content directly.