#include "session.h" #include "parser.h" #include "errors.h" #include #include #include void Session::loadConfig(fs::path const &configFile) { m_config = configFile; BSON v = BSON::loadDocumentFromFile(m_config, true, false, "Session"); if(!v.isNull()) { if(v.hasField("recent")) m_recent.deserialize(v["recent"]); } } void Session::saveConfig() const { if(m_config == "") { FxOS_log(WRN, "session cannot be saved as there is no config file"); return; } fs::create_directories(m_config.parent_path()); FILE *fp = fopen(m_config.c_str(), "w"); if(!fp) { FxOS_log(ERR, "cannot open '%s': %m", m_config.c_str()); return; } BSON b = BSON::mkDocument({ {"*", BSON::mkString("Session")}, {"recent", m_recent.serialize()}, }); b.serialize(fp); fclose(fp); } Binary *Session::currentBinary() { if(!m_project || m_currentBinaryName == "") return nullptr; return m_project->getBinary(m_currentBinaryName); } Binary const *Session::currentBinary() const { if(!m_project || m_currentBinaryName == "") return nullptr; return m_project->getBinary(m_currentBinaryName); } void Session::selectBinary(std::string const &name) { if(name != "" && (!m_project || !m_project->getBinary(name))) return; m_currentBinaryName = name; } bool Session::isProjectDirty() const { Project *p = m_project.get(); return p && p->isDirty(); } bool Session::confirmProjectUnload() const { if(!m_project || !isProjectDirty()) return true; fmt::print("Project “{}” is not saved. Discard changes (y/N)? ", m_project->name()); char *line = NULL; size_t n = 0; getline(&line, &n, stdin); n = strlen(line); if(n > 0 && line[n - 1] == '\n') line[n - 1] = '\0'; bool discard = line && (!strcmp(line, "y") || !strcmp(line, "Y")); free(line); return discard; } void Session::switchToNewProject( std::string const &name, std::string const &path) { auto p = std::make_unique(); if(name != "") p->setName(name); if(path != "") p->setPath(path); /* Unload current project - any unsaved data is lost. */ m_project.reset(); m_project = std::move(p); selectBinary(""); } bool Session::loadProject(std::string const &path) { auto p = std::make_unique(); if(!p->load(path)) return false; /* Unload current project - any unsaved data is lost. */ m_project.reset(); m_project = std::move(p); recentProjects().touch(project()); /* Select the first binary in the project, if there is one. */ // TODO: Save the last binary in use auto const &binaries = project().binaries(); selectBinary(binaries.size() ? binaries.begin()->first : ""); return true; } std::string Session::legacyGenerateSpaceName( std::string prefix, bool force_suffix) { if(!force_suffix && this->legacySpaces.count(prefix) == 0) return prefix; int counter = 0; while(1) { std::string name = fmt::format("{}_{}", prefix, counter); if(!this->legacySpaces.count(name)) return name; counter++; } } fs::path Session::file(std::string name) { #define err(...) std::runtime_error(fmt::format(__VA_ARGS__)) fs::path relative_to = lex_last_used_file(); if(name[0] != '/') { fs::path rel = relative_to.parent_path() / name; if(!fs::exists(rel)) throw err("cannot find {} in current directory", name); if(fs::symlink_status(rel).type() != fs::file_type::regular) throw err("{} is neither a file nor a symlink to a file", name); return rel; } fs::path filepath(name.substr(1)); for(auto const &p: this->path) { if(!fs::exists(p / filepath)) continue; /* This file exists, it can be the only one selected */ if(fs::symlink_status(p / filepath).type() != fs::file_type::regular) throw err("{} is neither a file nor a symlink to a file", name); return p / filepath; } throw err("cannot find {} in library", name); #undef err }