[olympic/studio] Add new project menu, make file creation open file
	
		
			
	
		
	
	
		
	
		
			Some checks failed
		
		
	
	
		
			
				
	
				Build / build (push) Failing after 2m7s
				
			
		
		
	
	
				
					
				
			
		
			Some checks failed
		
		
	
	Build / build (push) Failing after 2m7s
				
			This commit is contained in:
		@@ -5,6 +5,7 @@ add_library(
 | 
			
		||||
		filedialogmanager.cpp
 | 
			
		||||
		main.cpp
 | 
			
		||||
		newmenu.cpp
 | 
			
		||||
		newproject.cpp
 | 
			
		||||
		projectexplorer.cpp
 | 
			
		||||
		projecttreemodel.cpp
 | 
			
		||||
		studioapp.cpp
 | 
			
		||||
 
 | 
			
		||||
@@ -115,12 +115,12 @@ void NewMenu::drawLastPageButtons(turbine::Context &ctx) noexcept {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NewMenu::finish(turbine::Context &ctx) noexcept {
 | 
			
		||||
	auto const err = m_types[static_cast<std::size_t>(m_selectedType)]->write(ctx, m_itemName);
 | 
			
		||||
	auto const [path, err] = m_types[static_cast<std::size_t>(m_selectedType)]->write(ctx, m_itemName);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		oxLogError(err);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	finished.emit("");
 | 
			
		||||
	finished.emit(path);
 | 
			
		||||
	m_stage = Stage::Closed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										95
									
								
								src/olympic/studio/applib/src/newproject.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								src/olympic/studio/applib/src/newproject.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,95 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <imgui.h>
 | 
			
		||||
 | 
			
		||||
#include <studio/imguiuitl.hpp>
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
#include "filedialogmanager.hpp"
 | 
			
		||||
#include "newproject.hpp"
 | 
			
		||||
 | 
			
		||||
namespace studio {
 | 
			
		||||
 | 
			
		||||
NewProject::NewProject(ox::String projectDatadir) noexcept: m_projectDataDir(std::move(projectDatadir)) {
 | 
			
		||||
	setTitle(ox::String("New Project"));
 | 
			
		||||
	setSize({230, 140});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NewProject::open() noexcept {
 | 
			
		||||
	m_stage = Stage::Opening;
 | 
			
		||||
	m_projectPath = "";
 | 
			
		||||
	m_projectName = "";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NewProject::close() noexcept {
 | 
			
		||||
	m_stage = Stage::Closed;
 | 
			
		||||
	m_open = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool NewProject::isOpen() const noexcept {
 | 
			
		||||
	return m_open;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NewProject::draw(turbine::Context &ctx) noexcept {
 | 
			
		||||
	switch (m_stage) {
 | 
			
		||||
		case Stage::Opening:
 | 
			
		||||
			ImGui::OpenPopup(title().c_str());
 | 
			
		||||
			m_stage = Stage::NewItemName;
 | 
			
		||||
			m_open = true;
 | 
			
		||||
			[[fallthrough]];
 | 
			
		||||
		case Stage::NewItemName:
 | 
			
		||||
			drawNewProjectName(ctx);
 | 
			
		||||
			break;
 | 
			
		||||
		case Stage::Closed:
 | 
			
		||||
			m_open = false;
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NewProject::drawNewProjectName(turbine::Context &ctx) noexcept {
 | 
			
		||||
	drawWindow(ctx, &m_open, [this, &ctx] {
 | 
			
		||||
		ImGui::InputText("Name", m_projectName.data(), m_projectName.cap());
 | 
			
		||||
		ImGui::Text("Path: %s", m_projectPath.c_str());
 | 
			
		||||
		if (ImGui::Button("Browse")) {
 | 
			
		||||
			oxLogError(studio::chooseDirectory().moveTo(m_projectPath));
 | 
			
		||||
		}
 | 
			
		||||
		drawLastPageButtons(ctx);
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NewProject::drawFirstPageButtons() noexcept {
 | 
			
		||||
	ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 130);
 | 
			
		||||
	ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetContentRegionAvail().y - 20);
 | 
			
		||||
	auto const btnSz = ImVec2(60, 20);
 | 
			
		||||
	if (ImGui::Button("Next", btnSz)) {
 | 
			
		||||
		m_stage = Stage::NewItemName;
 | 
			
		||||
	}
 | 
			
		||||
	ImGui::SameLine();
 | 
			
		||||
	if (ImGui::Button("Cancel", btnSz)) {
 | 
			
		||||
		ImGui::CloseCurrentPopup();
 | 
			
		||||
		m_stage = Stage::Closed;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NewProject::drawLastPageButtons(turbine::Context&) noexcept {
 | 
			
		||||
	ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 95);
 | 
			
		||||
	ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetContentRegionAvail().y - 20);
 | 
			
		||||
	if (ImGui::Button("Finish")) {
 | 
			
		||||
		finish();
 | 
			
		||||
	}
 | 
			
		||||
	ImGui::SameLine();
 | 
			
		||||
	if (ImGui::Button("Quit")) {
 | 
			
		||||
		ImGui::CloseCurrentPopup();
 | 
			
		||||
		m_stage = Stage::Closed;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NewProject::finish() noexcept {
 | 
			
		||||
	auto projectPath = ox::sfmt("{}/{}", m_projectPath, m_projectName);
 | 
			
		||||
	finished.emit(projectPath);
 | 
			
		||||
	m_stage = Stage::Closed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										58
									
								
								src/olympic/studio/applib/src/newproject.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/olympic/studio/applib/src/newproject.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <ox/claw/claw.hpp>
 | 
			
		||||
#include <ox/event/signal.hpp>
 | 
			
		||||
#include <ox/std/string.hpp>
 | 
			
		||||
 | 
			
		||||
#include <studio/itemmaker.hpp>
 | 
			
		||||
#include <studio/popup.hpp>
 | 
			
		||||
 | 
			
		||||
namespace studio {
 | 
			
		||||
 | 
			
		||||
class NewProject: public studio::Popup {
 | 
			
		||||
	public:
 | 
			
		||||
		enum class Stage {
 | 
			
		||||
			Closed,
 | 
			
		||||
			Opening,
 | 
			
		||||
			NewItemName,
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		// emits path parameter
 | 
			
		||||
		ox::Signal<ox::Error(ox::StringView)> finished;
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		Stage m_stage = Stage::Closed;
 | 
			
		||||
		ox::String const m_projectDataDir;
 | 
			
		||||
		ox::String m_projectPath;
 | 
			
		||||
		ox::BString<255> m_projectName;
 | 
			
		||||
		ox::Vector<ox::UniquePtr<studio::ItemMaker>> m_types;
 | 
			
		||||
		bool m_open = false;
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		NewProject(ox::String projectDatadir) noexcept;
 | 
			
		||||
 | 
			
		||||
		void open() noexcept override;
 | 
			
		||||
 | 
			
		||||
		void close() noexcept override;
 | 
			
		||||
 | 
			
		||||
		[[nodiscard]]
 | 
			
		||||
		bool isOpen() const noexcept override;
 | 
			
		||||
 | 
			
		||||
		void draw(turbine::Context &ctx) noexcept override;
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		void drawNewProjectName(turbine::Context &ctx) noexcept;
 | 
			
		||||
 | 
			
		||||
		void drawFirstPageButtons() noexcept;
 | 
			
		||||
 | 
			
		||||
		void drawLastPageButtons(turbine::Context &ctx) noexcept;
 | 
			
		||||
 | 
			
		||||
		void finish() noexcept;
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -2,6 +2,8 @@
 | 
			
		||||
 * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <filesystem>
 | 
			
		||||
 | 
			
		||||
#include <imgui.h>
 | 
			
		||||
 | 
			
		||||
#include <keel/media.hpp>
 | 
			
		||||
@@ -42,15 +44,18 @@ StudioUI::StudioUI(turbine::Context &ctx, ox::StringView projectDataDir) noexcep
 | 
			
		||||
		m_ctx(ctx),
 | 
			
		||||
		m_projectDataDir(projectDataDir),
 | 
			
		||||
		m_projectExplorer(m_ctx),
 | 
			
		||||
		m_newProject(ox::String(projectDataDir)),
 | 
			
		||||
		m_aboutPopup(m_ctx) {
 | 
			
		||||
	m_projectExplorer.fileChosen.connect(this, &StudioUI::openFile);
 | 
			
		||||
	m_newProject.finished.connect(this, &StudioUI::createOpenProject);
 | 
			
		||||
	m_newMenu.finished.connect(this, &StudioUI::openFile);
 | 
			
		||||
	ImGui::GetIO().IniFilename = nullptr;
 | 
			
		||||
	loadModules();
 | 
			
		||||
	// open project and files
 | 
			
		||||
	auto const [config, err] = studio::readConfig<StudioConfig>(keelCtx(m_ctx));
 | 
			
		||||
	m_showProjectExplorer = config.showProjectExplorer;
 | 
			
		||||
	if (!err) {
 | 
			
		||||
		auto const openProjErr = openProject(config.projectPath);
 | 
			
		||||
		auto const openProjErr = openProjectPath(config.projectPath);
 | 
			
		||||
		if (!openProjErr) {
 | 
			
		||||
			for (auto const&f: config.openFiles) {
 | 
			
		||||
				auto openFileErr = openFileActiveTab(f, config.activeTabItemName == f);
 | 
			
		||||
@@ -95,10 +100,14 @@ void StudioUI::handleKeyEvent(turbine::Key key, bool down) noexcept {
 | 
			
		||||
				}
 | 
			
		||||
				break;
 | 
			
		||||
			case turbine::Key::Alpha_N:
 | 
			
		||||
				m_newMenu.open();
 | 
			
		||||
				if (turbine::buttonDown(m_ctx, turbine::Key::Mod_Shift)) {
 | 
			
		||||
					m_newProject.open();
 | 
			
		||||
				} else {
 | 
			
		||||
					m_newMenu.open();
 | 
			
		||||
				}
 | 
			
		||||
				break;
 | 
			
		||||
			case turbine::Key::Alpha_O:
 | 
			
		||||
				m_taskRunner.add(*ox::make<FileDialogManager>(this, &StudioUI::openProject));
 | 
			
		||||
				m_taskRunner.add(*ox::make<FileDialogManager>(this, &StudioUI::openProjectPath));
 | 
			
		||||
				break;
 | 
			
		||||
			case turbine::Key::Alpha_Q:
 | 
			
		||||
				turbine::requestShutdown(m_ctx);
 | 
			
		||||
@@ -168,8 +177,11 @@ void StudioUI::drawMenu() noexcept {
 | 
			
		||||
			if (ImGui::MenuItem("New...", "Ctrl+N")) {
 | 
			
		||||
				m_newMenu.open();
 | 
			
		||||
			}
 | 
			
		||||
			if (ImGui::MenuItem("New Project...", "Ctrl+Shift+N")) {
 | 
			
		||||
				m_newProject.open();
 | 
			
		||||
			}
 | 
			
		||||
			if (ImGui::MenuItem("Open Project...", "Ctrl+O")) {
 | 
			
		||||
				m_taskRunner.add(*ox::make<FileDialogManager>(this, &StudioUI::openProject));
 | 
			
		||||
				m_taskRunner.add(*ox::make<FileDialogManager>(this, &StudioUI::openProjectPath));
 | 
			
		||||
			}
 | 
			
		||||
			if (ImGui::MenuItem("Save", "Ctrl+S", false, m_activeEditor && m_activeEditor->unsavedChanges())) {
 | 
			
		||||
				m_activeEditor->save();
 | 
			
		||||
@@ -317,19 +329,27 @@ void StudioUI::save() noexcept {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ox::Error StudioUI::openProject(ox::CRStringView path) noexcept {
 | 
			
		||||
ox::Error StudioUI::createOpenProject(ox::CRStringView path) noexcept {
 | 
			
		||||
	std::error_code ec;
 | 
			
		||||
	std::filesystem::create_directories(toStdStringView(path), ec);
 | 
			
		||||
	oxReturnError(OxError(ec.value() != 0, "Could not create project directory"));
 | 
			
		||||
	oxReturnError(openProjectPath(path));
 | 
			
		||||
	return m_project->writeAllTypeDescriptors();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ox::Error StudioUI::openProjectPath(ox::CRStringView path) noexcept {
 | 
			
		||||
	oxRequireM(fs, keel::loadRomFs(path));
 | 
			
		||||
	oxReturnError(keel::setRomFs(keelCtx(m_ctx), std::move(fs)));
 | 
			
		||||
	turbine::setWindowTitle(m_ctx, ox::sfmt("{} - {}", keelCtx(m_ctx).appName, path));
 | 
			
		||||
	m_project = ox::make_unique<studio::Project>(keelCtx(m_ctx), ox::String(path), m_projectDataDir);
 | 
			
		||||
	auto sctx = applicationData<studio::StudioContext>(m_ctx);
 | 
			
		||||
	auto const sctx = applicationData<studio::StudioContext>(m_ctx);
 | 
			
		||||
	sctx->project = m_project.get();
 | 
			
		||||
	turbine::setWindowTitle(m_ctx, ox::sfmt("{} - {}", keelCtx(m_ctx).appName, m_project->projectPath()));
 | 
			
		||||
	m_project->fileAdded.connect(&m_projectExplorer, &ProjectExplorer::refreshProjectTreeModel);
 | 
			
		||||
	m_project->fileDeleted.connect(&m_projectExplorer, &ProjectExplorer::refreshProjectTreeModel);
 | 
			
		||||
	m_openFiles.clear();
 | 
			
		||||
	m_editors.clear();
 | 
			
		||||
	studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&](StudioConfig *config) {
 | 
			
		||||
		config->projectPath = ox::String(path);
 | 
			
		||||
		config->projectPath = ox::String(m_project->projectPath());
 | 
			
		||||
		config->openFiles.clear();
 | 
			
		||||
	});
 | 
			
		||||
	return m_projectExplorer.refreshProjectTreeModel();
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,7 @@
 | 
			
		||||
#include <studio/task.hpp>
 | 
			
		||||
#include "aboutpopup.hpp"
 | 
			
		||||
#include "newmenu.hpp"
 | 
			
		||||
#include "newproject.hpp"
 | 
			
		||||
#include "projectexplorer.hpp"
 | 
			
		||||
#include "projecttreemodel.hpp"
 | 
			
		||||
 | 
			
		||||
@@ -36,9 +37,11 @@ class StudioUI: public ox::SignalHandler {
 | 
			
		||||
		studio::BaseEditor *m_activeEditor = nullptr;
 | 
			
		||||
		studio::BaseEditor *m_activeEditorUpdatePending = nullptr;
 | 
			
		||||
		NewMenu m_newMenu;
 | 
			
		||||
		NewProject m_newProject;
 | 
			
		||||
		AboutPopup m_aboutPopup;
 | 
			
		||||
		ox::Array<studio::Popup*, 2> const m_popups = {
 | 
			
		||||
			&m_newMenu,
 | 
			
		||||
			&m_newProject,
 | 
			
		||||
			&m_aboutPopup
 | 
			
		||||
		};
 | 
			
		||||
		bool m_showProjectExplorer = true;
 | 
			
		||||
@@ -79,7 +82,9 @@ class StudioUI: public ox::SignalHandler {
 | 
			
		||||
 | 
			
		||||
		void save() noexcept;
 | 
			
		||||
 | 
			
		||||
		ox::Error openProject(ox::CRStringView path) noexcept;
 | 
			
		||||
		ox::Error createOpenProject(ox::CRStringView path) noexcept;
 | 
			
		||||
 | 
			
		||||
		ox::Error openProjectPath(ox::CRStringView path) noexcept;
 | 
			
		||||
 | 
			
		||||
		ox::Error openFile(ox::CRStringView path) noexcept;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,14 @@ class ItemMaker {
 | 
			
		||||
			fileExt(pFileExt) {
 | 
			
		||||
		}
 | 
			
		||||
		virtual ~ItemMaker() noexcept = default;
 | 
			
		||||
		virtual ox::Error write(turbine::Context &ctx, ox::CRStringView pName) const noexcept = 0;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Returns path of the file created.
 | 
			
		||||
		 * @param ctx
 | 
			
		||||
		 * @param pName
 | 
			
		||||
		 * @return path of file or error in Result
 | 
			
		||||
		 */
 | 
			
		||||
		virtual ox::Result<ox::String> write(turbine::Context &ctx, ox::CRStringView pName) const noexcept = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template<typename T>
 | 
			
		||||
@@ -61,11 +68,12 @@ class ItemMakerT: public ItemMaker {
 | 
			
		||||
			 m_item(std::move(pItem)),
 | 
			
		||||
			 m_fmt(pFmt) {
 | 
			
		||||
		}
 | 
			
		||||
		ox::Error write(turbine::Context &ctx, ox::CRStringView pName) const noexcept override {
 | 
			
		||||
		ox::Result<ox::String> write(turbine::Context &ctx, ox::CRStringView pName) const noexcept override {
 | 
			
		||||
			auto const path = ox::sfmt("/{}/{}.{}", parentDir, pName, fileExt);
 | 
			
		||||
			auto sctx = turbine::applicationData<studio::StudioContext>(ctx);
 | 
			
		||||
			keel::createUuidMapping(keelCtx(ctx), path, ox::UUID::generate().unwrap());
 | 
			
		||||
			return sctx->project->writeObj(path, m_item, m_fmt);
 | 
			
		||||
			oxReturnError(sctx->project->writeObj(path, m_item, m_fmt));
 | 
			
		||||
			return path;
 | 
			
		||||
		}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -50,6 +50,7 @@ class Project {
 | 
			
		||||
		keel::Context &m_ctx;
 | 
			
		||||
		ox::String m_path;
 | 
			
		||||
		ox::String m_projectDataDir;
 | 
			
		||||
		ox::String m_typeDescPath;
 | 
			
		||||
		mutable keel::TypeStore m_typeStore;
 | 
			
		||||
		ox::FileSystem &m_fs;
 | 
			
		||||
		ox::HashMap<ox::String, ox::Vector<ox::String>> m_fileExtFileMap;
 | 
			
		||||
@@ -59,6 +60,9 @@ class Project {
 | 
			
		||||
 | 
			
		||||
		ox::Error create() noexcept;
 | 
			
		||||
 | 
			
		||||
		[[nodiscard]]
 | 
			
		||||
		ox::String const&projectPath() const noexcept;
 | 
			
		||||
 | 
			
		||||
		[[nodiscard]]
 | 
			
		||||
		ox::FileSystem *romFs() noexcept;
 | 
			
		||||
 | 
			
		||||
@@ -87,6 +91,8 @@ class Project {
 | 
			
		||||
		[[nodiscard]]
 | 
			
		||||
		ox::Vector<ox::String> const&fileList(ox::CRStringView ext) noexcept;
 | 
			
		||||
 | 
			
		||||
		ox::Error writeAllTypeDescriptors() noexcept;
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		void buildFileIndex() noexcept;
 | 
			
		||||
 | 
			
		||||
@@ -123,21 +129,10 @@ ox::Error Project::writeObj(ox::CRStringView path, T const&obj, ox::ClawFormat f
 | 
			
		||||
	if (m_typeStore.get<T>().error) {
 | 
			
		||||
		oxReturnError(ox::buildTypeDef(&m_typeStore, &obj));
 | 
			
		||||
	}
 | 
			
		||||
	// write out type store
 | 
			
		||||
	auto const descPath = ox::sfmt("/{}/type_descriptors", m_projectDataDir);
 | 
			
		||||
	oxRequire(desc, m_typeStore.get<T>());
 | 
			
		||||
	auto const descExists = m_fs.stat(ox::sfmt("{}/{}", descPath, buildTypeId(*desc))).error != 0;
 | 
			
		||||
	auto const descExists = m_fs.stat(ox::sfmt("{}/{}", m_typeDescPath, buildTypeId(*desc))).error != 0;
 | 
			
		||||
	if (!descExists || ox::defines::Debug) {
 | 
			
		||||
		// write all descriptors because we don't know which types T depends on
 | 
			
		||||
		oxReturnError(mkdir(descPath));
 | 
			
		||||
		for (auto const &t: m_typeStore.typeList()) {
 | 
			
		||||
			oxRequireM(typeOut, ox::writeClaw(*t, ox::ClawFormat::Organic));
 | 
			
		||||
			// replace garbage last character with new line
 | 
			
		||||
			*typeOut.back().value = '\n';
 | 
			
		||||
			// write to FS
 | 
			
		||||
			auto const typePath = ox::sfmt("/{}/{}", descPath, buildTypeId(*t));
 | 
			
		||||
			oxReturnError(writeBuff(typePath, typeOut));
 | 
			
		||||
		}
 | 
			
		||||
		oxReturnError(writeAllTypeDescriptors());
 | 
			
		||||
	}
 | 
			
		||||
	oxReturnError(keel::setAsset(m_ctx, path, obj));
 | 
			
		||||
	fileUpdated.emit(path);
 | 
			
		||||
 
 | 
			
		||||
@@ -30,6 +30,7 @@ Project::Project(keel::Context &ctx, ox::String path, ox::CRStringView projectDa
 | 
			
		||||
	m_ctx(ctx),
 | 
			
		||||
	m_path(std::move(path)),
 | 
			
		||||
	m_projectDataDir(projectDataDir),
 | 
			
		||||
	m_typeDescPath(ox::sfmt("/{}/type_descriptors", m_projectDataDir)),
 | 
			
		||||
	m_typeStore(*m_ctx.rom, ox::sfmt("/{}/type_descriptors", projectDataDir)),
 | 
			
		||||
	m_fs(*m_ctx.rom) {
 | 
			
		||||
	oxTracef("studio", "Project: {}", m_path);
 | 
			
		||||
@@ -43,6 +44,10 @@ ox::Error Project::create() noexcept {
 | 
			
		||||
	return OxError(static_cast<ox::ErrorCode>(ec.value()), "PassThroughFS: mkdir failed");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ox::String const&Project::projectPath() const noexcept {
 | 
			
		||||
	return m_path;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ox::FileSystem *Project::romFs() noexcept {
 | 
			
		||||
	return &m_fs;
 | 
			
		||||
}
 | 
			
		||||
@@ -65,6 +70,20 @@ ox::Vector<ox::String> const&Project::fileList(ox::CRStringView ext) noexcept {
 | 
			
		||||
	return m_fileExtFileMap[ext];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ox::Error Project::writeAllTypeDescriptors() noexcept {
 | 
			
		||||
	// write all descriptors because we don't know which types T depends on
 | 
			
		||||
	oxReturnError(mkdir(m_typeDescPath));
 | 
			
		||||
	for (auto const &t: m_typeStore.typeList()) {
 | 
			
		||||
		oxRequireM(typeOut, ox::writeClaw(*t, ox::ClawFormat::Organic));
 | 
			
		||||
		// replace garbage last character with new line
 | 
			
		||||
		*typeOut.back().value = '\n';
 | 
			
		||||
		// write to FS
 | 
			
		||||
		auto const typePath = ox::sfmt("{}/{}", m_typeDescPath, buildTypeId(*t));
 | 
			
		||||
		oxReturnError(writeBuff(typePath, typeOut));
 | 
			
		||||
	}
 | 
			
		||||
	return {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Project::buildFileIndex() noexcept {
 | 
			
		||||
	auto [files, err] = listFiles();
 | 
			
		||||
	if (err) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user