#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; if constexpr (std::is_same_v) { throw ed_error("no address"); } 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 = 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) { 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 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()) { 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(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; } 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(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 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()) { 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(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; } 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(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