114 lines
3.0 KiB
C++
114 lines
3.0 KiB
C++
#include "bed.h"
|
|
#include "internal/parser/parser.h"
|
|
|
|
namespace bed {
|
|
void BEd::run() {
|
|
while (true) {
|
|
internal::ui::CommandIO command(*this);
|
|
auto [cmd, eof] = command.run();
|
|
try {
|
|
handle(cmd, eof);
|
|
} catch (const ed_error &e) {
|
|
io.apply(internal::io::Token::Warning);
|
|
io.write_line("?");
|
|
if (help_mode)
|
|
io.write_line(e.what());
|
|
io.reset();
|
|
last_help = e.what();
|
|
}
|
|
}
|
|
}
|
|
|
|
internal::buffer::Buffer &BEd::buffer(const std::string &name) {
|
|
if (name.empty())
|
|
throw ed_error("Can't have empty buffer name");
|
|
{
|
|
auto it = buffers.find(name);
|
|
if (it != buffers.end())
|
|
return *it->second;
|
|
}
|
|
constexpr std::string_view prefix = "history/";
|
|
if (name == "cancel")
|
|
throw ed_error("Cancel buffer empty.");
|
|
if (name.starts_with(prefix)) {
|
|
std::string_view path{name};
|
|
path.remove_prefix(prefix.size());
|
|
auto slash = path.rfind('_');
|
|
if (slash == std::string_view::npos || slash == 0 || slash == path.size() - 1)
|
|
throw ed_error("invalid history");
|
|
std::string bufname(path.substr(0, slash));
|
|
auto version_str = path.substr(slash + 1);
|
|
std::size_t version;
|
|
try {
|
|
version = std::stoull(std::string(version_str));
|
|
} catch (...) {
|
|
throw ed_error("invalid history version");
|
|
}
|
|
auto it = buffers.find(bufname);
|
|
if (it != buffers.end()) {
|
|
auto &buf_ = *it->second;
|
|
if (buf_.kind != internal::buffer::Buffer::Kind::Generic)
|
|
throw ed_error("Only normal buffers can have history.");
|
|
auto &buf = *(internal::buffer::GenericBuffer *)&buf_;
|
|
auto *history_buf = buf.get_history(version);
|
|
buffers.emplace(name, history_buf);
|
|
return *history_buf;
|
|
}
|
|
throw ed_error("Buffer has no history.");
|
|
}
|
|
for (auto &c : name)
|
|
if (!(('0' <= c && c <= '9')
|
|
|| ('a' <= c && c <= 'z')
|
|
|| ('A' <= c && c <= 'Z')
|
|
|| c == '-' || c == '_'
|
|
|| c == '+' || c == '.'
|
|
|| c == ',' || c == '$'
|
|
|| c == '/' || c == '~'))
|
|
throw ed_error("Invalid buffer name.");
|
|
auto *buf = new internal::buffer::GenericBuffer(name);
|
|
buffers.emplace(name, buf);
|
|
return *buf;
|
|
}
|
|
|
|
internal::buffer::Line &BEd::current() {
|
|
return marks.get(250 + temporary_current);
|
|
}
|
|
|
|
internal::buffer::Range &BEd::prev() {
|
|
if (temporary_current)
|
|
return prev_2;
|
|
else
|
|
return prev_1;
|
|
}
|
|
|
|
void BEd::mark(uint8_t m, internal::buffer::Line line) {
|
|
marks.get(m) = line;
|
|
}
|
|
|
|
bool BEd::escape_command(std::string &cmd, std::string_view filename) {
|
|
bool modified = false;
|
|
if (cmd == "!") {
|
|
cmd = last_shell;
|
|
modified = true;
|
|
}
|
|
last_shell = cmd;
|
|
for (size_t i = 0; i < cmd.size();) {
|
|
if (cmd[i] == '\\') {
|
|
if (i + 1 >= cmd.size())
|
|
break;
|
|
cmd.erase(i++, 1);
|
|
continue;
|
|
}
|
|
if (cmd[i] == '%') {
|
|
cmd.erase(i, 1);
|
|
cmd.insert(i, filename);
|
|
i += filename.size();
|
|
modified = true;
|
|
continue;
|
|
}
|
|
i++;
|
|
}
|
|
return modified;
|
|
}
|
|
} // namespace bed
|