From 81bb65b7cff33392f059a7fb3cb65fa18335c1b8 Mon Sep 17 00:00:00 2001 From: Syed Daanish Date: Sun, 30 Aug 2026 19:18:26 +0100 Subject: [PATCH] Add clipboard buffer. --- include/internal/buffer/buffer.h | 76 +-------- include/internal/buffer/clip.h | 35 ++++ include/internal/buffer/decl.h | 88 ++++++++++ include/internal/buffer/generic.h | 39 +++++ src/bed/run.cc | 6 +- src/internal/buffer/buffer.cc | 125 ++++++++++++-- src/internal/buffer/special/clip.cc | 218 +++++++++++++++++++++++++ src/internal/functions/functions.cc | 43 ++--- src/internal/parser/address_promise.cc | 30 +--- src/internal/vase/regex/api.cc | 4 + src/internal/vase/vase.cc | 1 - 11 files changed, 519 insertions(+), 146 deletions(-) create mode 100644 include/internal/buffer/clip.h create mode 100644 include/internal/buffer/decl.h create mode 100644 include/internal/buffer/generic.h create mode 100644 src/internal/buffer/special/clip.cc diff --git a/include/internal/buffer/buffer.h b/include/internal/buffer/buffer.h index 9423430..1bb96e6 100644 --- a/include/internal/buffer/buffer.h +++ b/include/internal/buffer/buffer.h @@ -1,76 +1,6 @@ #pragma once -#include "definitions.h" -#include "internal/syntax/parser.h" -#include "internal/syntax/ruby/parser.h" -#include "internal/theme/theme.h" +#include "clip.h" +#include "decl.h" +#include "generic.h" #include "pch.h" - -namespace bed::internal::buffer { -struct Buffer { - enum { - Unmodified, - Modified, - Warned - } state; - std::filesystem::path save_path = ""; - - vase::Shard *root; - - std::string name; - std::string language; - std::optional parser; - - explicit Buffer(std::string name); - ~Buffer(); - - uint64_t lines(); - uint64_t bytes(); - void load(BEd &ctx, vase::Shard *text); - vase::Shard *copy(uint64_t start_line, uint64_t end_line); - void substitute( - BEd &ctx, uint64_t start_line, uint64_t end_line, - std::string ®ex, std::string &replacement, std::string &options - ); - void join(BEd &ctx, uint64_t start_line, uint64_t end_line); - void remove(BEd &ctx, uint64_t start_line, uint64_t end_line); - void append(BEd &ctx, vase::Shard *text, uint64_t line); - void print(BEd &ctx, uint64_t start_line, uint64_t end_line); - void number_print(BEd &ctx, uint64_t start_line, uint64_t end_line); - std::string list_string(std::string_view s); -}; - -struct Line { - std::string buffername; - uint64_t number; -}; - -struct Range { - std::string buffername; - uint64_t start; - uint64_t end; - - explicit Range(const Line &a, const Line &b) { - if (a.buffername != b.buffername) - throw ed_error("Invalid range."); - if (a.number > b.number) - throw ed_error("Invalid range."); - buffername = a.buffername; - start = a.number; - end = b.number; - }; - - explicit Range(std::string buffername, uint64_t start, uint64_t end) - : buffername(buffername), start(start), end(end) { - if (start > end) - throw ed_error("Invalid range."); - }; - - explicit Range() : buffername("default"), start(0), end(0) {}; -}; - -using Address = std::variant< - std::string, - buffer::Range, - buffer::Line>; -} // namespace bed::internal::buffer diff --git a/include/internal/buffer/clip.h b/include/internal/buffer/clip.h new file mode 100644 index 0000000..48216ed --- /dev/null +++ b/include/internal/buffer/clip.h @@ -0,0 +1,35 @@ +#pragma once + +#include "decl.h" +#include "pch.h" + +namespace bed::internal::buffer { +struct ClipBuffer : Buffer { + ClipBuffer(std::string name) + : Buffer(name, Kind::Clip) {}; + ~ClipBuffer(); + + void clip_write(vase::Shard *text); + bool waste() override; + uint64_t lines() override; + uint64_t bytes() override; + void load(BEd &ctx) override; + void load(BEd &ctx, vase::Shard *text) override; + void load(BEd &ctx, const char *cmd) override; + void load(BEd &ctx, std::filesystem::path path) override; + vase::Shard *copy(uint64_t start_line, uint64_t end_line) override; + void substitute( + BEd &ctx, uint64_t start_line, uint64_t end_line, + std::string ®ex, std::string &replacement, std::string &options + ) override; + void join(BEd &ctx, uint64_t start_line, uint64_t end_line) override; + void remove(BEd &ctx, uint64_t start_line, uint64_t end_line) override; + void append(BEd &ctx, vase::Shard *text, uint64_t line) override; + void print(BEd &ctx, uint64_t start_line, uint64_t end_line) override; + void number_print(BEd &ctx, uint64_t start_line, uint64_t end_line) override; + uint64_t next_closing(uint64_t start) override; + uint64_t prev_closing(uint64_t start) override; + uint64_t find_next(std::string_view pattern, uint64_t start) override; + uint64_t find_prev(std::string_view pattern, uint64_t start) override; +}; +} // namespace bed::internal::buffer diff --git a/include/internal/buffer/decl.h b/include/internal/buffer/decl.h new file mode 100644 index 0000000..643a786 --- /dev/null +++ b/include/internal/buffer/decl.h @@ -0,0 +1,88 @@ +#pragma once + +#include "definitions.h" +#include "internal/syntax/parser.h" +#include "internal/syntax/ruby/parser.h" +#include "internal/theme/theme.h" +#include "pch.h" + +namespace bed::internal::buffer { +struct Buffer { + enum struct Kind : uint8_t { + Generic, + Null, + Clip, + Cancel, + Shell, + } kind; + + enum : uint8_t { + Special, + Unmodified, + Modified, + Warned + } state; + + std::string name; + + explicit Buffer(std::string name, Kind kind) + : kind(kind), state(Unmodified), name(name) {}; + virtual ~Buffer() = default; + + virtual bool waste() = 0; + virtual uint64_t lines() = 0; + virtual uint64_t bytes() = 0; + virtual void load(BEd &ctx, vase::Shard *text) = 0; + virtual void load(BEd &ctx, const char *cmd) = 0; + virtual void load(BEd &ctx, std::filesystem::path path) = 0; + virtual void load(BEd &ctx) = 0; + virtual vase::Shard *copy(uint64_t start_line, uint64_t end_line) = 0; + virtual void substitute( + BEd &ctx, uint64_t start_line, uint64_t end_line, + std::string ®ex, std::string &replacement, std::string &options + ) = 0; + virtual void join(BEd &ctx, uint64_t start_line, uint64_t end_line) = 0; + virtual void remove(BEd &ctx, uint64_t start_line, uint64_t end_line) = 0; + virtual void append(BEd &ctx, vase::Shard *text, uint64_t line) = 0; + virtual void print(BEd &ctx, uint64_t start_line, uint64_t end_line) = 0; + virtual void number_print(BEd &ctx, uint64_t start_line, uint64_t end_line) = 0; + virtual uint64_t find_next(std::string_view pattern, uint64_t start) = 0; + virtual uint64_t find_prev(std::string_view pattern, uint64_t start) = 0; + virtual uint64_t next_closing(uint64_t start) = 0; + virtual uint64_t prev_closing(uint64_t start) = 0; +}; + +struct Line { + std::string buffername; + uint64_t number; +}; + +struct Range { + std::string buffername; + uint64_t start; + uint64_t end; + + explicit Range(const Line &a, const Line &b) { + if (a.buffername != b.buffername) + throw ed_error("Invalid range."); + if (a.number > b.number) + throw ed_error("Invalid range."); + buffername = a.buffername; + start = a.number; + end = b.number; + }; + + explicit Range(std::string buffername, uint64_t start, uint64_t end) + : buffername(buffername), start(start), end(end) { + if (start > end) + throw ed_error("Invalid range."); + }; + + explicit Range() : buffername("default"), start(0), end(0) {}; +}; + +using Address = std::variant< + std::string, + buffer::Range, + buffer::Line>; +} // namespace bed::internal::buffer diff --git a/include/internal/buffer/generic.h b/include/internal/buffer/generic.h new file mode 100644 index 0000000..9c2be19 --- /dev/null +++ b/include/internal/buffer/generic.h @@ -0,0 +1,39 @@ +#pragma once + +#include "decl.h" +#include "pch.h" + +namespace bed::internal::buffer { +struct GenericBuffer : Buffer { + vase::Shard *root; + std::filesystem::path save_path{}; + std::string language{}; + std::optional parser{}; + + GenericBuffer(std::string name) + : Buffer(name, Kind::Generic), root(nullptr) {}; + ~GenericBuffer(); + + bool waste() override; + uint64_t lines() override; + uint64_t bytes() override; + void load(BEd &ctx) override; + void load(BEd &ctx, vase::Shard *text) override; + void load(BEd &ctx, const char *cmd) override; + void load(BEd &ctx, std::filesystem::path path) override; + vase::Shard *copy(uint64_t start_line, uint64_t end_line) override; + void substitute( + BEd &ctx, uint64_t start_line, uint64_t end_line, + std::string ®ex, std::string &replacement, std::string &options + ) override; + void join(BEd &ctx, uint64_t start_line, uint64_t end_line) override; + void remove(BEd &ctx, uint64_t start_line, uint64_t end_line) override; + void append(BEd &ctx, vase::Shard *text, uint64_t line) override; + void print(BEd &ctx, uint64_t start_line, uint64_t end_line) override; + void number_print(BEd &ctx, uint64_t start_line, uint64_t end_line) override; + uint64_t next_closing(uint64_t start) override; + uint64_t prev_closing(uint64_t start) override; + uint64_t find_next(std::string_view pattern, uint64_t start) override; + uint64_t find_prev(std::string_view pattern, uint64_t start) override; +}; +} // namespace bed::internal::buffer diff --git a/src/bed/run.cc b/src/bed/run.cc index 1990454..bfc1858 100644 --- a/src/bed/run.cc +++ b/src/bed/run.cc @@ -28,6 +28,7 @@ BEd::BEd(std::vector args, internal::io::IO &io) else prompt_mode = false; suppress_mode = suppress; + buffers["clip"] = new internal::buffer::ClipBuffer("clip"); try { if (file != "") handle(":default:E " + file, false); @@ -141,8 +142,7 @@ void BEd::handle(std::string_view cmd, bool eof) { temporary_current = false; for (auto it = buffers.begin(); it != buffers.end();) { internal::buffer::Buffer *buf = it->second; - if (buf->save_path.empty() - && buf->root == nullptr) { + if (buf->waste()) { delete buf; it = buffers.erase(it); } else { @@ -157,7 +157,7 @@ internal::buffer::Buffer &BEd::buffer(const std::string &name) { auto it = buffers.find(name); if (it != buffers.end()) return *it->second; - auto *buf = new internal::buffer::Buffer(name); + auto *buf = new internal::buffer::GenericBuffer(name); buffers.emplace(name, buf); return *buf; } diff --git a/src/internal/buffer/buffer.cc b/src/internal/buffer/buffer.cc index ef0484a..3c0e0bc 100644 --- a/src/internal/buffer/buffer.cc +++ b/src/internal/buffer/buffer.cc @@ -2,31 +2,34 @@ #include "bed.h" namespace bed::internal::buffer { -Buffer::Buffer(std::string name) - : state(Unmodified), root(nullptr), name(name) { -} - -Buffer::~Buffer() { +GenericBuffer::~GenericBuffer() { vase::Shard::release(root); } -uint64_t Buffer::lines() { +bool GenericBuffer::waste() { + return save_path.empty() + && root == nullptr; +} + +uint64_t GenericBuffer::lines() { if (root) return root->lines + 1; return 0; } -uint64_t Buffer::bytes() { +uint64_t GenericBuffer::bytes() { if (root) return root->length + 1; return 0; } -void Buffer::load(BEd &ctx, vase::Shard *text) { +void GenericBuffer::load(BEd &ctx, vase::Shard *text) { try { + if (lines()) + ctx.marks.erase(name, 1, lines()); vase::Shard::release(root); root = text; - state = buffer::Buffer::Unmodified; + state = buffer::GenericBuffer::Unmodified; if (!text) { ctx.prev().buffername = name; ctx.prev().start = 0; @@ -43,7 +46,61 @@ void Buffer::load(BEd &ctx, vase::Shard *text) { } } -void Buffer::append(BEd &ctx, vase::Shard *text, uint64_t line) { +void GenericBuffer::load(BEd &ctx) { + if (save_path.empty()) + throw ed_error("File cannot be implied."); + load(ctx, save_path); +} + +void GenericBuffer::load(BEd &ctx, const char *cmd) { + auto text = vase::Shard::from_command(cmd, true); + try { + if (lines()) + ctx.marks.erase(name, 1, lines()); + vase::Shard::release(root); + root = text; + state = buffer::GenericBuffer::Unmodified; + if (!text) { + ctx.prev().buffername = name; + ctx.prev().start = 0; + ctx.prev().end = 0; + } else { + ctx.prev().buffername = name; + ctx.prev().start = 1; + ctx.prev().end = text->lines + 1; + } + parser.emplace(root, lines(), syntax::ruby::lang_ruby()); + } catch (...) { + vase::Shard::release(text); + throw; + } +} + +void GenericBuffer::load(BEd &ctx, std::filesystem::path path) { + auto text = vase::Shard::from_file(path, true); + try { + if (lines()) + ctx.marks.erase(name, 1, lines()); + vase::Shard::release(root); + root = text; + state = buffer::GenericBuffer::Unmodified; + if (!text) { + ctx.prev().buffername = name; + ctx.prev().start = 0; + ctx.prev().end = 0; + } else { + ctx.prev().buffername = name; + ctx.prev().start = 1; + ctx.prev().end = text->lines + 1; + } + parser.emplace(root, lines(), syntax::ruby::lang_ruby()); + } catch (...) { + vase::Shard::release(text); + throw; + } +} + +void GenericBuffer::append(BEd &ctx, vase::Shard *text, uint64_t line) { ctx.prev().buffername = name; ctx.prev().start = line + 1; ctx.prev().end = line + text->lines + 1; @@ -54,7 +111,7 @@ void Buffer::append(BEd &ctx, vase::Shard *text, uint64_t line) { state = Modified; } -void Buffer::remove(BEd &ctx, uint64_t start_line, uint64_t end_line) { +void GenericBuffer::remove(BEd &ctx, uint64_t start_line, uint64_t end_line) { root = vase::erase(root, start_line, end_line); ctx.prev().buffername = name; ctx.prev().start = lines() ? 1 : 0; @@ -65,7 +122,7 @@ void Buffer::remove(BEd &ctx, uint64_t start_line, uint64_t end_line) { state = Modified; } -void Buffer::join(BEd &ctx, uint64_t start_line, uint64_t end_line) { +void GenericBuffer::join(BEd &ctx, uint64_t start_line, uint64_t end_line) { root = vase::join(root, start_line, end_line); ctx.prev().buffername = name; ctx.prev().start = start_line; @@ -76,7 +133,7 @@ void Buffer::join(BEd &ctx, uint64_t start_line, uint64_t end_line) { state = Modified; } -void Buffer::substitute( +void GenericBuffer::substitute( BEd &ctx, uint64_t start_line, uint64_t end_line, std::string ®ex, std::string &replacement, std::string &options ) { @@ -112,10 +169,42 @@ void Buffer::substitute( state = Modified; } -vase::Shard *Buffer::copy(uint64_t start_line, uint64_t end_line) { +vase::Shard *GenericBuffer::copy(uint64_t start_line, uint64_t end_line) { return vase::copy(root, start_line, end_line); } +uint64_t GenericBuffer::find_next(std::string_view pattern, uint64_t start) { + return vase::find_next(root, pattern, start); +} + +uint64_t GenericBuffer::find_prev(std::string_view pattern, uint64_t start) { + return vase::find_prev(root, pattern, start); +} + +uint64_t GenericBuffer::next_closing(uint64_t start) { + if (parser.has_value()) { + uint64_t closing = parser->next_closing(start - 1); + if (closing == UINT64_MAX) + return lines(); + return closing + 1; + } else { + start += 10; + if (start > lines()) + return lines(); + return start; + } +} + +uint64_t GenericBuffer::prev_closing(uint64_t start) { + if (parser.has_value()) { + return parser->prev_opening(start - 1) + 1; + } else { + if (start > 10) + return start - 10; + return 0; + } +} + inline void apply(std::ostream &out, const Highlight &hl) { out << "\x1b[0m"; const uint8_t r = (hl.fg >> 16) & 0xff; @@ -148,7 +237,7 @@ inline void reset(std::ostream &out) { out << "\x1b[0m"; } -void Buffer::print(BEd &ctx, uint64_t start_line, uint64_t end_line) { +void GenericBuffer::print(BEd &ctx, uint64_t start_line, uint64_t end_line) { ctx.prev().buffername = name; ctx.prev().start = start_line; ctx.prev().end = end_line; @@ -191,7 +280,7 @@ void Buffer::print(BEd &ctx, uint64_t start_line, uint64_t end_line) { } } -void Buffer::number_print(BEd &ctx, uint64_t start_line, uint64_t end_line) { +void GenericBuffer::number_print(BEd &ctx, uint64_t start_line, uint64_t end_line) { ctx.prev().buffername = name; ctx.prev().start = start_line; ctx.prev().end = end_line; @@ -238,7 +327,7 @@ void Buffer::number_print(BEd &ctx, uint64_t start_line, uint64_t end_line) { } } -std::string Buffer::list_string(std::string_view s) { +/*std::string GenericBuffer::list_string(std::string_view s) { uint32_t width = 80; winsize ws{}; if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0 && ws.ws_col != 0) @@ -294,5 +383,5 @@ std::string Buffer::list_string(std::string_view s) { } out += '$'; return out; -} +}*/ } // namespace bed::internal::buffer diff --git a/src/internal/buffer/special/clip.cc b/src/internal/buffer/special/clip.cc new file mode 100644 index 0000000..385020f --- /dev/null +++ b/src/internal/buffer/special/clip.cc @@ -0,0 +1,218 @@ +#include "bed.h" +#include "internal/buffer/buffer.h" + +namespace bed::internal::buffer { +ClipBuffer::~ClipBuffer() {} + +bool ClipBuffer::waste() { + return false; +} + +uint64_t ClipBuffer::lines() { + auto s = vase::Shard::from_command("xclip -selection clipboard -o", true); + uint64_t lines = s ? s->lines + 1 : 0; + vase::Shard::release(s); + return lines; +} + +uint64_t ClipBuffer::bytes() { + auto s = vase::Shard::from_command("xclip -selection clipboard -o", true); + uint64_t length = s ? s->length + 1 : 0; + vase::Shard::release(s); + return length; +} + +void ClipBuffer::clip_write(vase::Shard *text) { + FILE *pipe = popen("xclip -selection clipboard -i", "w"); + if (!pipe) + throw ed_error("can't access clipboard"); + auto s = vase::to_string(text); + fwrite(s.data(), 1, s.length(), pipe); + if (pclose(pipe) != 0) + throw ed_error("can't write clipboard"); +} + +void ClipBuffer::load(BEd &ctx, vase::Shard *text) { + try { + clip_write(text); + if (!text) { + ctx.prev().buffername = name; + ctx.prev().start = 0; + ctx.prev().end = 0; + } else { + ctx.prev().buffername = name; + ctx.prev().start = 1; + ctx.prev().end = text->lines + 1; + } + vase::Shard::release(text); + } catch (...) { + vase::Shard::release(text); + throw; + } +} + +void ClipBuffer::load(BEd &) { + throw ed_error("File cannot be implied."); +} + +void ClipBuffer::load(BEd &ctx, const char *cmd) { + auto text = vase::Shard::from_command(cmd, true); + try { + clip_write(text); + if (!text) { + ctx.prev().buffername = name; + ctx.prev().start = 0; + ctx.prev().end = 0; + } else { + ctx.prev().buffername = name; + ctx.prev().start = 1; + ctx.prev().end = text->lines + 1; + } + vase::Shard::release(text); + } catch (...) { + vase::Shard::release(text); + throw; + } +} + +void ClipBuffer::load(BEd &ctx, std::filesystem::path path) { + auto text = vase::Shard::from_file(path, true); + try { + clip_write(text); + if (!text) { + ctx.prev().buffername = name; + ctx.prev().start = 0; + ctx.prev().end = 0; + } else { + ctx.prev().buffername = name; + ctx.prev().start = 1; + ctx.prev().end = text->lines + 1; + } + vase::Shard::release(text); + } catch (...) { + vase::Shard::release(text); + throw; + } +} + +void ClipBuffer::append(BEd &ctx, vase::Shard *text, uint64_t line) { + ctx.prev().buffername = name; + ctx.prev().start = line + 1; + ctx.prev().end = line + text->lines + 1; + auto s = vase::Shard::from_command("xclip -selection clipboard -o", true); + s = vase::insert(&ctx.append, s, text, line); + clip_write(s); + vase::Shard::release(s); + ctx.marks.insert(name, ctx.prev().start, ctx.prev().end); +} + +void ClipBuffer::remove(BEd &ctx, uint64_t start_line, uint64_t end_line) { + auto s = vase::Shard::from_command("xclip -selection clipboard -o", true); + s = vase::erase(s, start_line, end_line); + clip_write(s); + ctx.prev().buffername = name; + ctx.prev().start = (s ? s->length + 1 : 0) ? 1 : 0; + ctx.prev().end = s ? s->length + 1 : 0; + vase::Shard::release(s); + ctx.marks.erase(name, start_line, end_line - start_line + 1); +} + +void ClipBuffer::join(BEd &ctx, uint64_t start_line, uint64_t end_line) { + auto s = vase::Shard::from_command("xclip -selection clipboard -o", true); + s = vase::join(s, start_line, end_line); + clip_write(s); + vase::Shard::release(s); + ctx.prev().buffername = name; + ctx.prev().start = start_line; + ctx.prev().end = start_line; + ctx.marks.collapse(name, start_line, end_line - start_line); +} + +void ClipBuffer::substitute( + BEd &ctx, uint64_t start_line, uint64_t end_line, + std::string ®ex, std::string &replacement, std::string &options +) { + ctx.prev().buffername = name; + ctx.prev().start = start_line; + ctx.prev().end = end_line; + auto s = vase::Shard::from_command("xclip -selection clipboard -o", true); + s = vase::substitute( + &ctx.append, + s, + regex, + start_line, + end_line, + replacement, + options, + [&](uint64_t line, uint64_t old_lines, uint64_t new_lines) { + if (old_lines) + ctx.marks.erase(name, line, old_lines); + if (new_lines) + ctx.marks.insert(name, line, line + new_lines - 1); + } + ); + clip_write(s); + vase::Shard::release(s); + ctx.prev().buffername = name; +} + +vase::Shard *ClipBuffer::copy(uint64_t start_line, uint64_t end_line) { + auto s = vase::Shard::from_command("xclip -selection clipboard -o", true); + vase::Shard *o = vase::copy(s, start_line, end_line); + vase::Shard::release(s); + return o; +} + +uint64_t ClipBuffer::find_next(std::string_view pattern, uint64_t start) { + auto s = vase::Shard::from_command("xclip -selection clipboard -o", true); + uint64_t line = vase::find_next(s, pattern, start); + vase::Shard::release(s); + return line; +} + +uint64_t ClipBuffer::find_prev(std::string_view pattern, uint64_t start) { + auto s = vase::Shard::from_command("xclip -selection clipboard -o", true); + uint64_t line = vase::find_prev(s, pattern, start); + vase::Shard::release(s); + return line; +} + +uint64_t ClipBuffer::next_closing(uint64_t start) { + start += 10; + uint64_t line = lines(); + if (start > line) + return line; + return start; +} + +uint64_t ClipBuffer::prev_closing(uint64_t start) { + if (start > 10) + return start - 10; + return 0; +} + +void ClipBuffer::print(BEd &ctx, uint64_t start_line, uint64_t end_line) { + ctx.prev().buffername = name; + ctx.prev().start = start_line; + ctx.prev().end = end_line; + auto s = vase::Shard::from_command("xclip -selection clipboard -o", true); + vase::Iterator it(s, start_line - 1, Direction::Forward); + while (it.next() && start_line++ <= end_line) + std::cout << it.line << std::endl; + vase::Shard::release(s); +} + +void ClipBuffer::number_print(BEd &ctx, uint64_t start_line, uint64_t end_line) { + ctx.prev().buffername = name; + ctx.prev().start = start_line; + ctx.prev().end = end_line; + uint8_t width = 1; + for (uint64_t n = end_line; n >= 10; n /= 10) + ++width; + auto s = vase::Shard::from_command("xclip -selection clipboard -o", true); + vase::Iterator it(s, start_line - 1, Direction::Forward); + while (it.next() && start_line <= end_line) + std::cout << std::setw(width) << start_line++ << "\t" << it.line << std::endl; + vase::Shard::release(s); +} +} // namespace bed::internal::buffer diff --git a/src/internal/functions/functions.cc b/src/internal/functions/functions.cc index 86e1e01..d967c98 100644 --- a/src/internal/functions/functions.cc +++ b/src/internal/functions/functions.cc @@ -280,19 +280,12 @@ void Function::register_posix(BEd &ctx) { buf.state = buffer::Buffer::Warned; throw ed_error("Buffer modified."); } - vase::Shard *s = nullptr; - if (std::holds_alternative(arg)) { - s = vase::Shard::from_file(std::get(arg), true); - buf.save_path = std::get(arg); - } else if (std::holds_alternative(arg)) { - s = vase::Shard::from_command(std::get(arg).cmd.c_str(), true); - } else if (std::holds_alternative(arg)) { - if (buf.save_path != "") - s = vase::Shard::from_file(buf.save_path, true); - else - throw ed_error("Need filename to load."); - } - buf.load(ctx, s); + if (std::holds_alternative(arg)) + buf.load(ctx, std::get(arg)); + else if (std::holds_alternative(arg)) + buf.load(ctx, std::get(arg).cmd.c_str()); + else if (std::holds_alternative(arg)) + buf.load(ctx); std::cout << buf.bytes() << std::endl; ctx.current() = {addr, buf.lines()}; } @@ -310,20 +303,16 @@ void Function::register_posix(BEd &ctx) { .pre_text_mode = nullptr, .handle = [](BEd &ctx, const buffer::Address &addr_, vase::Shard *, const Argument &arg, std::vector *) { auto &addr = std::get(addr_); - auto &buf = ctx.buffer(addr); - vase::Shard *s = nullptr; - if (std::holds_alternative(arg)) { - s = vase::Shard::from_file(std::get(arg), true); - buf.save_path = std::get(arg); - } else if (std::holds_alternative(arg)) { - s = vase::Shard::from_command(std::get(arg).cmd.c_str(), true); - } else if (std::holds_alternative(arg)) { - if (buf.save_path != "") - s = vase::Shard::from_file(buf.save_path, true); - else - throw ed_error("Need filename to load."); - } - buf.load(ctx, s); + auto &buf_ = ctx.buffer(addr); + if (buf_.kind != buffer::Buffer::Kind::Generic) + return; + auto &buf = *(buffer::GenericBuffer *)&buf_; + if (std::holds_alternative(arg)) + buf.load(ctx, std::get(arg)); + else if (std::holds_alternative(arg)) + buf.load(ctx, std::get(arg).cmd.c_str()); + else if (std::holds_alternative(arg)) + buf.load(ctx); std::cout << buf.bytes() << std::endl; ctx.current() = {addr, buf.lines()}; } diff --git a/src/internal/parser/address_promise.cc b/src/internal/parser/address_promise.cc index 27971d1..7287f2f 100644 --- a/src/internal/parser/address_promise.cc +++ b/src/internal/parser/address_promise.cc @@ -44,9 +44,9 @@ buffer::Line AddressPromise::resolve(BEd &ctx) { 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); + line.number = buf.find_next(re, line.number); else - line.number = vase::find_prev(buf.root, re, line.number); + 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) @@ -55,28 +55,10 @@ buffer::Line AddressPromise::resolve(BEd &ctx) { 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; - } - } + 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."); } diff --git a/src/internal/vase/regex/api.cc b/src/internal/vase/regex/api.cc index e36447d..121107d 100644 --- a/src/internal/vase/regex/api.cc +++ b/src/internal/vase/regex/api.cc @@ -179,6 +179,8 @@ Shard *substitute( } uint64_t find_next(Shard *root, std::string_view pattern, uint64_t start) { + if (!root) + throw ed_error("Invalid line number."); if (start == 0 || start > root->lines + 1) throw ed_error("Invalid line number."); start--; @@ -241,6 +243,8 @@ uint64_t find_next(Shard *root, std::string_view pattern, uint64_t start) { } uint64_t find_prev(Shard *root, std::string_view pattern, uint64_t start) { + if (!root) + throw ed_error("Invalid line number."); if (start == 0 || start > root->lines + 1) throw ed_error("Invalid line number."); start--; diff --git a/src/internal/vase/vase.cc b/src/internal/vase/vase.cc index e000cf5..bc71ec9 100644 --- a/src/internal/vase/vase.cc +++ b/src/internal/vase/vase.cc @@ -273,7 +273,6 @@ Shard *copy(Shard *root, uint64_t start, uint64_t end) { Shard::release(left); Shard::release(rest); Shard::release(right); - Shard::release(root); return middle; } } // namespace bed::internal::vase