- A lotta cleanup - BEd command parser rewrite - Vase class removed - Proper IO system. - A lot more.
216 lines
6.8 KiB
C++
216 lines
6.8 KiB
C++
#include "bed.h"
|
|
#include "internal/parser/parser.h"
|
|
#include "internal/vase/vase.h"
|
|
|
|
namespace bed::internal::parser {
|
|
buffer::Line AddressPromise::resolve(BEd &ctx) {
|
|
buffer::Line result = std::visit(
|
|
[&](auto const &addr) -> buffer::Line {
|
|
if (!bufname.has_value())
|
|
throw ed_error("Buffer name can't be empty.");
|
|
buffer::Line line = {*bufname, 0};
|
|
auto &buf = ctx.buffer(line.buffername);
|
|
using T = std::decay_t<decltype(addr)>;
|
|
if constexpr (std::is_same_v<T, None>) {
|
|
throw ed_error("no address");
|
|
} else if constexpr (std::is_same_v<T, Current>) {
|
|
if (line.buffername == ctx.current().buffername)
|
|
line.number = ctx.current().number;
|
|
else
|
|
line.number = buf.lines();
|
|
} else if constexpr (std::is_same_v<T, Last>) {
|
|
line.number = buf.lines();
|
|
} else if constexpr (std::is_same_v<T, Number>) {
|
|
line.number = addr.i;
|
|
} else if constexpr (std::is_same_v<T, Mark>) {
|
|
line = ctx.marks.get(addr.m);
|
|
if (line.number == UINT64_MAX)
|
|
throw ed_error("Mark not set.");
|
|
} else if constexpr (std::is_same_v<T, Regex>) {
|
|
if (line.buffername == ctx.current().buffername)
|
|
line.number = ctx.current().number;
|
|
else
|
|
line.number = buf.lines();
|
|
if (buf.lines() > 0 && line.number == 0)
|
|
line.number = 1;
|
|
if (line.number == 0)
|
|
throw ed_error("Can't search empty buffer.");
|
|
std::string_view re = addr.re;
|
|
if (re.size() == 0)
|
|
re = ctx.last_regex;
|
|
if (re.size() == 0)
|
|
throw ed_error("No regex given.");
|
|
if (addr.dir == Direction::Forward)
|
|
line.number = vase::find_next(buf.root, re, line.number);
|
|
else
|
|
line.number = vase::find_prev(buf.root, re, line.number);
|
|
ctx.last_regex = re;
|
|
} else if constexpr (std::is_same_v<T, Block>) {
|
|
if (line.buffername == ctx.current().buffername)
|
|
line.number = ctx.current().number;
|
|
else
|
|
line.number = buf.lines();
|
|
if (buf.lines() > 0 && line.number == 0)
|
|
line.number = 1;
|
|
if (addr.dir == Direction::Forward) {
|
|
if (buf.parser.has_value()) {
|
|
uint64_t closing = buf.parser->next_closing(line.number - 1);
|
|
if (closing == UINT64_MAX)
|
|
line.number = buf.lines();
|
|
else
|
|
line.number = closing + 1;
|
|
} else {
|
|
line.number += 10;
|
|
if (line.number > buf.lines())
|
|
line.number = buf.lines();
|
|
}
|
|
} else {
|
|
if (buf.parser.has_value()) {
|
|
line.number = buf.parser->prev_opening(line.number - 1) + 1;
|
|
} else {
|
|
if (line.number > 10)
|
|
line.number -= 10;
|
|
else
|
|
line.number = 0;
|
|
}
|
|
}
|
|
} else {
|
|
throw ed_error("Unhandled address given.");
|
|
}
|
|
if (offset < 0 && line.number < (uint64_t)-offset)
|
|
throw ed_error("Can't have negative addresses");
|
|
line.number += offset;
|
|
if (line.number > ctx.buffer(line.buffername).lines())
|
|
throw ed_error("Line number too high.");
|
|
return line;
|
|
},
|
|
base
|
|
);
|
|
return result;
|
|
}
|
|
|
|
std::optional<buffer::Line> AddressPromise::get_line(BEd &ctx, std::vector<AddressPromise> &list) {
|
|
std::string bufname = ctx.current().buffername;
|
|
bool prev_given = false;
|
|
bool prev_set = false;
|
|
AddressPromise prev;
|
|
for (std::size_t idx = 0; idx < list.size(); idx++) {
|
|
AddressPromise &curr = list[idx];
|
|
if (curr.bufname.has_value()) {
|
|
if (curr.bufname->empty()) {
|
|
bufname = ctx.current().buffername;
|
|
curr.bufname = bufname;
|
|
} else {
|
|
bufname = *curr.bufname;
|
|
}
|
|
} else {
|
|
curr.bufname = bufname;
|
|
}
|
|
bool is_final = idx + 1 == list.size();
|
|
if (!is_final) {
|
|
if (std::holds_alternative<None>(curr.base)) {
|
|
if (!curr.jumping)
|
|
curr.base = Number(1);
|
|
else
|
|
curr.base = Current();
|
|
curr.offset = 0;
|
|
prev_given = false;
|
|
} else if (std::holds_alternative<LastRange>(curr.base)) {
|
|
curr.bufname = ctx.prev.buffername;
|
|
curr.base = Number(ctx.prev.end);
|
|
prev_given = true;
|
|
} else {
|
|
prev_given = true;
|
|
}
|
|
if (curr.jumping) {
|
|
buffer::Line resolved = curr.resolve(ctx);
|
|
ctx.current() = resolved;
|
|
curr.bufname = resolved.buffername;
|
|
curr.base = Number(resolved.number);
|
|
curr.offset = 0;
|
|
}
|
|
prev = curr;
|
|
prev_set = true;
|
|
} else {
|
|
if (std::holds_alternative<None>(curr.base)) {
|
|
if (!prev_set)
|
|
return std::nullopt;
|
|
if (prev_given) {
|
|
curr.base = prev.base;
|
|
curr.offset = prev.offset;
|
|
} else {
|
|
curr.base = Last();
|
|
curr.offset = 0;
|
|
}
|
|
}
|
|
return curr.resolve(ctx);
|
|
}
|
|
}
|
|
return std::nullopt;
|
|
}
|
|
|
|
std::optional<buffer::Range> AddressPromise::get_range(BEd &ctx, std::vector<AddressPromise> &list) {
|
|
std::string bufname = ctx.current().buffername;
|
|
bool prev_given = false;
|
|
bool prev_set = false;
|
|
AddressPromise prev;
|
|
for (std::size_t idx = 0; idx < list.size(); idx++) {
|
|
AddressPromise &curr = list[idx];
|
|
if (curr.bufname.has_value()) {
|
|
if (curr.bufname->empty()) {
|
|
bufname = ctx.current().buffername;
|
|
curr.bufname = bufname;
|
|
} else {
|
|
bufname = *curr.bufname;
|
|
}
|
|
} else {
|
|
curr.bufname = bufname;
|
|
}
|
|
bool is_final = idx + 1 == list.size();
|
|
if (!is_final) {
|
|
if (std::holds_alternative<None>(curr.base)) {
|
|
if (!curr.jumping)
|
|
curr.base = Number(1);
|
|
else
|
|
curr.base = Current();
|
|
curr.offset = 0;
|
|
prev_given = false;
|
|
} else if (std::holds_alternative<LastRange>(curr.base)) {
|
|
curr.bufname = ctx.prev.buffername;
|
|
curr.base = Number(ctx.prev.end);
|
|
prev_given = true;
|
|
} else {
|
|
prev_given = true;
|
|
}
|
|
if (curr.jumping) {
|
|
buffer::Line resolved = curr.resolve(ctx);
|
|
ctx.current() = resolved;
|
|
curr.bufname = resolved.buffername;
|
|
curr.base = Number(resolved.number);
|
|
curr.offset = 0;
|
|
}
|
|
prev = curr;
|
|
prev_set = true;
|
|
} else {
|
|
if (std::holds_alternative<None>(curr.base)) {
|
|
if (!prev_set)
|
|
return std::nullopt;
|
|
if (prev_given) {
|
|
curr.base = prev.base;
|
|
curr.offset = prev.offset;
|
|
} else {
|
|
curr.base = Last();
|
|
curr.offset = 0;
|
|
}
|
|
return buffer::Range(prev.resolve(ctx), curr.resolve(ctx));
|
|
}
|
|
if (prev_given)
|
|
return buffer::Range(prev.resolve(ctx), curr.resolve(ctx));
|
|
buffer::Line only = curr.resolve(ctx);
|
|
return buffer::Range(only, only);
|
|
}
|
|
}
|
|
return std::nullopt;
|
|
}
|
|
} // namespace bed::internal::parser
|