Reqrite project as BEd specific.

This commit is contained in:
2026-08-13 16:17:32 +01:00
parent cc5d475ab8
commit cd13557e15
46 changed files with 1115 additions and 1026 deletions
+115
View File
@@ -0,0 +1,115 @@
#pragma once
#include "definitions.h"
#include "internal/generic.h"
#include "pch.h"
namespace bed::internal::address {
struct address_error : ed_error {
address_error(const char *msg) : ed_error(msg) {}
};
struct Address {
// % refers to range of whatever was resulted from the previous modification.
// it expands in theory to a Num,Num and so can be followed by chaining more adresses the ed way.
// this is handled and resolved by the handle function,
// the constuctor and resolve etc. are also only called in the handle function,
// i.e. handle is the only public facing API from this namespace & class for now.
//
// in case of any issue an instance of address_error(const char *) is thrown.
struct Result {
std::array<uint64_t, 2> data{};
uint8_t size{0};
std::span<const uint64_t> span(uint8_t max = UINT8_MAX) const {
return {data.data(), std::min(size, max)};
}
};
struct None {};
// Posix ed types of addressing.
struct Current {}; // .
struct Last {}; // $
struct Number { // n
uint64_t i;
};
struct Mark { // 'm
char m;
};
struct RegexLine { // /re/ or ?re?
internal::Direction dir;
std::string re;
};
// BEd Extended types of addressing.
struct Regex { // &/re/ or &?re?
internal::Direction dir; // returns next/previous line containing the regex
std::string re; // (not only if it matches full line)
};
struct Diagnostic { // #n# for diagnostic number n. (From lsp.)
uint16_t n;
};
struct DiagnosticNext { // ^ or % for previous/next diagnostic
internal::Direction dir;
};
struct SymbolDefinition { // <sym> goto symbol definition. (From lsp or using internal language parsers)
std::string sym;
};
struct SymbolReference { // <sym:n> goto nth symbol reference
uint16_t n;
std::string sym;
};
struct SymbolReferenceNext { // >sym> or <sym<
internal::Direction dir; // goto next or previous symbol reference
std::string sym;
};
struct Block { // [ or ] goto start/end of containing block.
internal::Direction dir;
};
struct Scripted { // (function_name:arguments)
std::string func; // Calls ruby mapping with name giving the argument as string.
std::string arg; // resolves to line number returned by function (or throws error).
// The mruby runtime also has the full context of the file and extentions etc.
};
std::variant<
std::monostate,
None,
Current,
Last,
Number,
Mark,
RegexLine,
Regex,
Diagnostic,
DiagnosticNext,
SymbolDefinition,
SymbolReference,
SymbolReferenceNext,
Block,
Scripted>
base{};
// they can then be followed by any number of +n or -n etc accumulating in.
int64_t offset = 0;
Address(std::string &cmd, uint64_t &i);
Address() = default;
uint64_t resolve(BEd &ctx);
static Result handle(BEd &ctx, std::string &cmd, uint64_t &i);
};
} // namespace bed::internal::address
+34
View File
@@ -0,0 +1,34 @@
#pragma once
#include "definitions.h"
#include "internal/marks/marks.h"
#include "pch.h"
namespace bed::internal::buffer {
struct Buffer {
internal::vase::Vase vase;
internal::marks::MarksEngine marks;
uint64_t line = 0;
bool modified;
std::filesystem::path save_path = "";
struct {
uint64_t start{0};
uint64_t end{0};
} prev_range;
Buffer();
Buffer(std::string command);
Buffer(std::filesystem::path path);
~Buffer() = default;
void load(std::string command);
void load(std::filesystem::path path);
void jump(uint64_t n_line);
void join(uint64_t start_line, uint64_t end_line);
void remove(uint64_t start_line, uint64_t end_line);
void append(std::string text, uint64_t line);
void print(uint64_t start_line, uint64_t end_line);
std::string list_string(std::string_view s);
};
} // namespace bed::internal::buffer
+30
View File
@@ -0,0 +1,30 @@
#pragma once
#include "definitions.h"
#include "internal/trie/trie.h"
#include "pch.h"
namespace bed::internal::commands {
struct Command {
enum struct AddressMode : uint8_t {
None,
Single,
Range
} address_mode;
enum struct SuffixKind : uint8_t {
None,
Suffix,
Argument,
Continuation
} suffix;
std::string desc;
bool accept_zero;
void (*handle)(BEd &, std::span<const uint64_t>, std::string_view);
static void register_posix(BEd &ctx);
};
} // namespace bed::internal::commands
+13
View File
@@ -0,0 +1,13 @@
#pragma once
#include "definitions.h"
#include "pch.h"
namespace bed::internal::commands {
struct Suffix {
std::string desc;
void (*handle)(BEd &);
static void register_suffixes(BEd &ctx);
};
} // namespace bed::internal::commands
@@ -1,9 +1,8 @@
#pragma once
#include "../shard.h"
#include "pch.h"
namespace crib::internal::vase {
namespace bed::internal {
enum struct Direction : uint8_t {
Forward,
Backward
+7
View File
@@ -0,0 +1,7 @@
#pragma once
#include "pch.h"
namespace bed::internal::marks {
struct MarksEngine {};
} // namespace bed::internal::marks
+246
View File
@@ -0,0 +1,246 @@
#pragma once
#include "pch.h"
namespace bed::internal::trie {
template <typename T = void>
struct Trie {
using V = std::conditional_t<std::is_void_v<T>, std::monostate, T>;
struct Node {
std::string edge;
std::optional<V> value{};
std::vector<Node *> children;
Node(std::string e = {}) : edge(std::move(e)) {}
~Node() {
for (auto *c : children)
delete c;
};
} root;
bool case_sensitive;
Trie(bool cs = true) : case_sensitive(cs) {}
void insert(std::string_view key)
requires std::is_void_v<T>
{
_insert(key, std::monostate{});
}
void insert(std::string_view key, V el)
requires(!std::is_void_v<T>)
{
_insert(key, std::move(el));
}
void _insert(std::string_view key, V &&el) {
Node *current = &root;
uint64_t pos = 0;
while (pos < key.size()) {
Node *child = find_child(*current, key[pos]);
if (!child) {
auto *node = new Node(std::string(key.substr(pos)));
node->value = std::move(el);
current->children.push_back(node);
return;
}
const auto common = common_prefix(child->edge, key.substr(pos));
if (common == child->edge.size()) {
pos += common;
current = child;
continue;
}
auto *split = new Node(child->edge.substr(0, common));
child->edge.erase(0, common);
split->children.push_back(child);
current->children.erase(
std::find(current->children.begin(), current->children.end(), child)
);
current->children.push_back(split);
pos += common;
if (pos == key.size()) {
split->value = std::move(el);
return;
}
auto *node = new Node(std::string(key.substr(pos)));
node->value = std::move(el);
split->children.push_back(node);
return;
}
current->value = std::move(el);
}
void remove(std::string_view key) {
_remove(root, key, 0);
}
bool _remove(Node &node, std::string_view key, uint64_t pos) {
if (pos == key.size()) {
if (!node.value)
return false;
node.value.reset();
return true;
}
Node *child = find_child(node, key[pos]);
if (!child)
return false;
const auto remaining = key.substr(pos);
const auto common = common_prefix(child->edge, remaining);
if (common != child->edge.size())
return false;
const auto child_pos = pos + common;
if (!_remove(*child, key, child_pos))
return false;
if (!child->value && child->children.empty()) {
auto it = std::find(
node.children.begin(),
node.children.end(),
child
);
node.children.erase(it);
delete child;
return true;
}
if (!child->value && child->children.size() == 1) {
Node *grandchild = child->children.front();
child->edge += grandchild->edge;
child->value = std::move(grandchild->value);
child->children = std::move(grandchild->children);
grandchild->children.clear();
delete grandchild;
}
return true;
}
std::vector<std::string> search(std::string_view prefix) {
std::vector<std::string> result;
Node *current = &root;
std::string key;
uint64_t pos = 0;
while (pos < prefix.size()) {
Node *child = find_child(*current, prefix[pos]);
if (!child)
return result;
const auto remaining = prefix.substr(pos);
const auto common = common_prefix(child->edge, remaining);
if (common == 0)
return result;
if (common < child->edge.size()) {
if (common == remaining.size()) {
key += child->edge;
collect(*child, key, result);
return result;
}
return result;
}
key += child->edge;
pos += common;
current = child;
}
collect(*current, key, result);
return result;
}
static void collect(
const Node &node,
std::string &key,
std::vector<std::string> &result
) {
if (node.value)
result.push_back(key);
for (auto *child : node.children) {
const auto old_size = key.size();
key += child->edge;
collect(*child, key, result);
key.resize(old_size);
}
}
uint64_t longest_match(std::string_view input) {
Node *current = &root;
uint64_t pos = 0;
uint64_t longest = 0;
if (current->value)
longest = 0;
while (pos < input.size()) {
Node *child = find_child(*current, input[pos]);
if (!child)
break;
const auto remaining = input.substr(pos);
const auto common = common_prefix(child->edge, remaining);
if (common != child->edge.size())
break;
pos += common;
current = child;
if (current->value)
longest = pos;
}
return longest;
}
bool matches(std::string_view key)
requires(std::is_void_v<T>)
{
Node *current = &root;
uint64_t pos = 0;
while (pos < key.size()) {
Node *child = find_child(*current, key[pos]);
if (!child)
return false;
const auto remaining = key.substr(pos);
const auto common = common_prefix(child->edge, remaining);
if (common != child->edge.size())
return false;
pos += common;
current = child;
}
return current->value.has_value();
}
std::optional<V> get(std::string_view key)
requires(!std::is_void_v<T>)
{
Node *current = &root;
uint64_t pos = 0;
while (pos < key.size()) {
Node *child = find_child(*current, key[pos]);
if (!child)
return std::nullopt;
const auto remaining = key.substr(pos);
const auto common = common_prefix(child->edge, remaining);
if (common != child->edge.size())
return std::nullopt;
pos += common;
current = child;
}
if (!current->value)
return std::nullopt;
return *current->value;
}
bool equal_char(char a, char b) const {
if (case_sensitive)
return a == b;
return std::tolower((unsigned char)a) == std::tolower((unsigned char)b);
}
uint64_t common_prefix(
std::string_view a,
std::string_view b
) {
const auto n = std::min(a.size(), b.size());
uint64_t i = 0;
while (i < n && equal_char(a[i], b[i]))
++i;
return i;
}
Node *find_child(Node &node, char first) {
for (auto *child : node.children)
if (equal_char(child->edge.front(), first))
return child;
return nullptr;
}
};
} // namespace bed::internal::trie
+2 -2
View File
@@ -4,7 +4,7 @@
#include "buffer.h"
#include "pch.h"
namespace crib::internal::vase {
namespace bed::internal::vase {
struct AppendBuffer : Buffer {
char *buf = nullptr;
uint64_t allocated_capacity = 0;
@@ -22,4 +22,4 @@ struct AppendBuffer : Buffer {
private:
void grow(uint64_t len);
};
} // namespace crib::internal::vase
} // namespace bed::internal::vase
+2 -2
View File
@@ -2,10 +2,10 @@
#include "pch.h"
namespace crib::internal::vase {
namespace bed::internal::vase {
struct Buffer {
virtual const char *read(uint64_t pos) = 0;
virtual uint64_t length() = 0;
virtual ~Buffer() = default;
};
} // namespace crib::internal::vase
} // namespace bed::internal::vase
+2 -2
View File
@@ -3,7 +3,7 @@
#include "buffer.h"
#include "pch.h"
namespace crib::internal::vase {
namespace bed::internal::vase {
struct OriginalBuffer : Buffer {
const char *buf;
uint64_t len;
@@ -16,4 +16,4 @@ struct OriginalBuffer : Buffer {
const char *read(uint64_t pos) override;
uint64_t length() override;
};
} // namespace crib::internal::vase
} // namespace bed::internal::vase
+1 -1
View File
@@ -2,6 +2,6 @@
#include "pch.h"
namespace crib::internal::vase {
namespace bed::internal::vase {
constexpr uint64_t PETAL_SIZE_MAX = 32 * 1024;
}
+2 -2
View File
@@ -4,7 +4,7 @@
#include "pch.h"
#include "petal.h"
namespace crib::internal::vase {
namespace bed::internal::vase {
struct LineIterator {
PetalIterator it;
const char *chunk;
@@ -70,4 +70,4 @@ struct Iterator {
private:
LineIterator it;
};
} // namespace crib::internal::vase
} // namespace bed::internal::vase
+3 -3
View File
@@ -1,10 +1,10 @@
#pragma once
#include "../shard.h"
#include "iter.h"
#include "internal/generic.h"
#include "pch.h"
namespace crib::internal::vase {
namespace bed::internal::vase {
struct PetalIterator {
Direction dir;
Shard *root = nullptr;
@@ -26,4 +26,4 @@ struct PetalIterator {
private:
Petal *_next(uint64_t *offset);
};
} // namespace crib::internal::vase
} // namespace bed::internal::vase
+2 -2
View File
@@ -5,7 +5,7 @@
#include "constants.h"
#include "pch.h"
namespace crib::internal::vase {
namespace bed::internal::vase {
struct Shard {
enum struct Kind : uint8_t {
Branch,
@@ -63,4 +63,4 @@ struct Petal : Shard {
source(source), pos(pos) {};
};
} // namespace crib::internal::vase
} // namespace bed::internal::vase
+2 -2
View File
@@ -7,7 +7,7 @@
#include "pch.h"
#include "shard.h"
namespace crib::internal::vase {
namespace bed::internal::vase {
struct Point {
uint64_t row;
uint64_t col;
@@ -114,4 +114,4 @@ private:
std::string_view pattern, Range range, std::string_view options
);
};
} // namespace crib::internal::vase
} // namespace bed::internal::vase