#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() || bufname->empty()) 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; if constexpr (std::is_same_v) { if (line.buffername == ctx.current().buffername) line.number = ctx.current().number; else line.number = buf.lines(); } else if constexpr (std::is_same_v) { if (line.buffername == ctx.current().buffername) line.number = ctx.current().number; else line.number = buf.lines(); } else if constexpr (std::is_same_v) { line.number = buf.lines(); } else if constexpr (std::is_same_v) { line.number = addr.i; } else if constexpr (std::is_same_v) { line = ctx.marks.get(addr.m); if (line.number == UINT64_MAX) throw ed_error("Mark not set."); } else if constexpr (std::is_same_v) { 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 = buf.find_next(re, line.number); else line.number = buf.find_prev(re, line.number); ctx.last_regex = re; } else if constexpr (std::is_same_v) { 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) line.number = buf.next_closing(line.number); else line.number = buf.prev_closing(line.number); } 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 AddressPromise::get_line(BEd &ctx, std::vector &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()) curr.bufname = bufname; else if (curr.bufname->empty()) curr.bufname = bufname = ctx.current().buffername; bool is_final = idx + 1 == list.size(); if (!is_final) { if (std::holds_alternative(curr.base)) { if (!curr.jumping) curr.base = Number(1); else curr.base = Current(); curr.offset = 0; prev_given = false; } else if (std::holds_alternative(curr.base)) { curr.bufname = ctx.prev().buffername; curr.base = Number(ctx.prev().end); prev_given = true; } else { prev_given = true; } buffer::Line resolved = curr.resolve(ctx); if (curr.jumping) ctx.current() = resolved; curr.bufname = resolved.buffername; curr.base = Number(resolved.number); curr.offset = 0; prev = curr; prev_set = true; bufname = *curr.bufname; } else { if (std::holds_alternative(curr.base)) { if (prev_set) { if (prev_given) { curr.base = prev.base; curr.offset = prev.offset; } else { curr.base = Last(); curr.offset = 0; } } } else if (std::holds_alternative(curr.base)) { curr.bufname = ctx.prev().buffername; curr.base = Number(ctx.prev().end); } return curr.resolve(ctx); } } return std::nullopt; } std::optional AddressPromise::get_range(BEd &ctx, std::vector &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()) curr.bufname = bufname; else if (curr.bufname->empty()) curr.bufname = bufname = ctx.current().buffername; bool is_final = idx + 1 == list.size(); if (!is_final) { if (std::holds_alternative(curr.base)) { if (!curr.jumping) curr.base = Number(1); else curr.base = Current(); curr.offset = 0; prev_given = false; } else if (std::holds_alternative(curr.base)) { curr.bufname = ctx.prev().buffername; curr.base = Number(ctx.prev().end); prev_given = true; } else { prev_given = true; } buffer::Line resolved = curr.resolve(ctx); curr.bufname = resolved.buffername; curr.base = Number(resolved.number); curr.offset = 0; if (curr.jumping) ctx.current() = resolved; prev = curr; prev_set = true; bufname = *curr.bufname; } else { if (std::holds_alternative(curr.base)) { if (prev_set) { 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)); } } else if (std::holds_alternative(curr.base)) { auto previous = ctx.prev(); auto &buf = ctx.buffer(previous.buffername); if (curr.offset < 0 && previous.start < (uint64_t)-curr.offset) throw ed_error("Can't have negative addresses"); previous.start += curr.offset; if (previous.start > buf.lines()) throw ed_error("Line number too high."); if (curr.offset < 0 && previous.end < (uint64_t)-curr.offset) throw ed_error("Can't have negative addresses"); previous.end += curr.offset; if (previous.end > buf.lines()) throw ed_error("Line number too high."); return previous; } 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