fxos/shell/session.cpp

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, true))
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
}