170 lines
4.2 KiB
C++
170 lines
4.2 KiB
C++
#include "session.h"
|
|
#include "parser.h"
|
|
#include "errors.h"
|
|
#include <fmt/core.h>
|
|
#include <fxos/util/log.h>
|
|
#include <fxos/util/bson.h>
|
|
|
|
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<Project>();
|
|
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<Project>();
|
|
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
|
|
}
|