Major updates:
- A lotta cleanup - BEd command parser rewrite - Vase class removed - Proper IO system. - A lot more.
This commit is contained in:
+19
-20
@@ -2,35 +2,25 @@
|
||||
|
||||
#include "definitions.h"
|
||||
#include "internal/buffer/buffer.h"
|
||||
#include "internal/commands/commands.h"
|
||||
#include "internal/commands/suffixes.h"
|
||||
#include "internal/functions/functions.h"
|
||||
#include "internal/functions/suffixes.h"
|
||||
#include "internal/io/command.h"
|
||||
#include "internal/io/io.h"
|
||||
#include "internal/marks/marks.h"
|
||||
#include "internal/theme/theme.h"
|
||||
#include "internal/ui/autocomp.h"
|
||||
#include "pch.h"
|
||||
|
||||
namespace bed {
|
||||
struct Suggestion {
|
||||
enum : uint8_t {
|
||||
Command,
|
||||
Address,
|
||||
Suffix,
|
||||
History,
|
||||
Regex
|
||||
} type;
|
||||
std::string_view name;
|
||||
std::string_view desc;
|
||||
std::string completion;
|
||||
};
|
||||
|
||||
struct BEd {
|
||||
internal::trie::Trie<internal::commands::Command> commands;
|
||||
internal::commands::Command no_op;
|
||||
internal::commands::Command eof_op;
|
||||
std::array<std::optional<internal::commands::Suffix>, 26> suffixes;
|
||||
internal::trie::Trie<internal::functions::Function> functions;
|
||||
internal::functions::Function no_op;
|
||||
internal::functions::Function eof_op;
|
||||
std::array<std::optional<internal::functions::Suffix>, 26> suffixes;
|
||||
internal::theme::Theme theme;
|
||||
std::unordered_map<std::string, internal::syntax::Language> languages;
|
||||
internal::io::IO &io;
|
||||
internal::vase::AppendStorage append{"/tmp"};
|
||||
|
||||
bool help_mode = false;
|
||||
std::string last_help = "";
|
||||
@@ -38,12 +28,21 @@ struct BEd {
|
||||
std::function<std::string(BEd &)> prompt = nullptr;
|
||||
bool suppress_mode = false;
|
||||
std::string last_regex = "";
|
||||
std::string last_symbol = "";
|
||||
std::string last_replacement = "";
|
||||
|
||||
std::unordered_map<std::string, internal::buffer::Buffer *> buffers;
|
||||
internal::buffer::Buffer *active;
|
||||
|
||||
internal::buffer::Range prev;
|
||||
internal::marks::MarksEngine marks;
|
||||
|
||||
BEd(std::vector<std::string> args, internal::io::IO &io);
|
||||
~BEd();
|
||||
|
||||
internal::buffer::Buffer &buffer(const std::string &);
|
||||
internal::buffer::Line ¤t();
|
||||
void mark(char, internal::buffer::Line);
|
||||
|
||||
void handle(std::string_view cmd, bool eof);
|
||||
void run();
|
||||
void suffix_handle(char s);
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include "pch.h"
|
||||
|
||||
namespace bed {
|
||||
struct BEd;
|
||||
|
||||
struct fatal_error : std::runtime_error {
|
||||
uint8_t code;
|
||||
fatal_error(std::string msg, uint8_t code)
|
||||
@@ -26,6 +28,4 @@ struct Highlight {
|
||||
uint32_t bg;
|
||||
uint8_t flags;
|
||||
};
|
||||
|
||||
struct BEd;
|
||||
} // namespace bed
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
#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,
|
||||
//
|
||||
// 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 Regex { // /re/ or ?re?
|
||||
internal::Direction dir;
|
||||
std::string re;
|
||||
};
|
||||
|
||||
// extended types
|
||||
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,
|
||||
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
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "definitions.h"
|
||||
#include "internal/marks/marks.h"
|
||||
#include "internal/syntax/parser.h"
|
||||
#include "internal/syntax/ruby/parser.h"
|
||||
#include "internal/theme/theme.h"
|
||||
@@ -9,36 +8,67 @@
|
||||
|
||||
namespace bed::internal::buffer {
|
||||
struct Buffer {
|
||||
vase::Vase vase;
|
||||
marks::MarksEngine marks;
|
||||
std::string language;
|
||||
std::optional<syntax::Parser> parser;
|
||||
uint64_t line = 0;
|
||||
bool modified;
|
||||
enum {
|
||||
Unmodified,
|
||||
Modified,
|
||||
Warned
|
||||
} state;
|
||||
std::filesystem::path save_path = "";
|
||||
|
||||
struct {
|
||||
uint64_t start{0};
|
||||
uint64_t end{0};
|
||||
std::span<const uint64_t> values() const {
|
||||
return {&start, 2};
|
||||
}
|
||||
} prev_range;
|
||||
vase::Shard *root;
|
||||
|
||||
Buffer();
|
||||
Buffer(std::string command);
|
||||
Buffer(std::filesystem::path path);
|
||||
std::string name;
|
||||
std::string language;
|
||||
std::optional<syntax::Parser> parser;
|
||||
|
||||
~Buffer() = default;
|
||||
explicit Buffer(std::string name);
|
||||
~Buffer();
|
||||
|
||||
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);
|
||||
uint64_t lines();
|
||||
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
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
#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
|
||||
@@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "definitions.h"
|
||||
#include "pch.h"
|
||||
|
||||
namespace bed::internal::commands {
|
||||
struct Suffix {
|
||||
std::string desc;
|
||||
void (*handle)(BEd &, std::span<const uint64_t>);
|
||||
|
||||
static void register_suffixes(BEd &ctx);
|
||||
};
|
||||
} // namespace bed::internal::commands
|
||||
@@ -0,0 +1,85 @@
|
||||
#pragma once
|
||||
|
||||
#include "definitions.h"
|
||||
#include "internal/buffer/buffer.h"
|
||||
#include "internal/trie/trie.h"
|
||||
#include "pch.h"
|
||||
|
||||
namespace bed::internal::functions {
|
||||
struct Function {
|
||||
struct GlobalArg {
|
||||
char delim;
|
||||
std::string str;
|
||||
};
|
||||
struct RegexArg {
|
||||
std::string expression;
|
||||
std::string replacement;
|
||||
std::string options;
|
||||
};
|
||||
struct ShellArg {
|
||||
std::string cmd;
|
||||
};
|
||||
struct RubyArg {
|
||||
std::string cmd;
|
||||
};
|
||||
using Argument = std::variant<
|
||||
std::monostate,
|
||||
GlobalArg,
|
||||
RegexArg,
|
||||
ShellArg,
|
||||
RubyArg,
|
||||
std::string,
|
||||
std::filesystem::path,
|
||||
int64_t,
|
||||
char,
|
||||
buffer::Range,
|
||||
buffer::Line>;
|
||||
|
||||
enum struct AddressKind {
|
||||
None,
|
||||
Line,
|
||||
Range
|
||||
} address_kind;
|
||||
|
||||
enum struct ArgumentKind {
|
||||
None,
|
||||
Regex,
|
||||
Shell,
|
||||
Ruby,
|
||||
Any,
|
||||
File,
|
||||
Number,
|
||||
Mark,
|
||||
Range,
|
||||
Line,
|
||||
Global
|
||||
} argument_kind;
|
||||
|
||||
enum struct InputMode {
|
||||
None,
|
||||
Text,
|
||||
Interactive,
|
||||
CommandList
|
||||
} input_mode;
|
||||
|
||||
std::string desc;
|
||||
std::string default_address;
|
||||
bool accept_zero;
|
||||
|
||||
std::function<
|
||||
std::tuple<vase::Shard *, syntax::Language *, void *>(
|
||||
BEd &ctx, const buffer::Address &addr, const Argument &arg
|
||||
)>
|
||||
pre_text_mode;
|
||||
|
||||
std::function<
|
||||
void(
|
||||
BEd &ctx, const buffer::Address &addr,
|
||||
vase::Shard *text, const Argument &arg,
|
||||
std::vector<buffer::Line> *marked
|
||||
)>
|
||||
handle;
|
||||
|
||||
static void register_posix(BEd &ctx);
|
||||
};
|
||||
} // namespace bed::internal::functions
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "definitions.h"
|
||||
#include "internal/buffer/buffer.h"
|
||||
#include "pch.h"
|
||||
|
||||
namespace bed::internal::functions {
|
||||
struct Suffix {
|
||||
std::string desc;
|
||||
std::function<void(BEd &)> handle;
|
||||
|
||||
static void register_suffixes(BEd &ctx);
|
||||
};
|
||||
} // namespace bed::internal::functions
|
||||
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include "internal/io/io.h"
|
||||
#include "internal/ui/autocomp.h"
|
||||
#include "pch.h"
|
||||
|
||||
namespace bed::internal::io {
|
||||
struct Token {
|
||||
enum struct Type : uint8_t {
|
||||
TempCurrent, // @
|
||||
AddressSeperator, // ; ,
|
||||
Address, // . $ % [ ] ^ ~
|
||||
Offset, // +N -N + -
|
||||
AddressRegex, // /re/ ?re?
|
||||
AddressSymbol, // >s> <s< <s>
|
||||
Number, // 10
|
||||
Mark, // 'm
|
||||
RubyFunction, // (func:arg)
|
||||
RubyArg,
|
||||
Function,
|
||||
Any,
|
||||
Shell,
|
||||
Ruby,
|
||||
File,
|
||||
Regex,
|
||||
Replacement,
|
||||
Suffix
|
||||
} type;
|
||||
uint16_t start;
|
||||
uint16_t end;
|
||||
};
|
||||
|
||||
struct CommandIO {
|
||||
std::string cmd;
|
||||
uint16_t cursor;
|
||||
std::string prompt;
|
||||
uint16_t start;
|
||||
uint16_t height;
|
||||
uint16_t term_height;
|
||||
uint16_t term_width;
|
||||
BEd &bed;
|
||||
IO &io;
|
||||
|
||||
CommandIO(BEd &, IO &);
|
||||
std::pair<std::string, bool> run();
|
||||
void redraw();
|
||||
};
|
||||
} // namespace bed::internal::io
|
||||
@@ -11,7 +11,7 @@ struct KeyEvent {
|
||||
RESIZE
|
||||
};
|
||||
enum struct KeyType {
|
||||
NONE,
|
||||
EOF_,
|
||||
CHAR,
|
||||
SPECIAL,
|
||||
MOUSE,
|
||||
@@ -38,7 +38,7 @@ struct KeyEvent {
|
||||
RELEASE
|
||||
};
|
||||
|
||||
KeyType type = KeyType::NONE;
|
||||
KeyType type = KeyType::EOF_;
|
||||
std::string text;
|
||||
|
||||
SpecialKey special_key = SpecialKey::UNKNOWN;
|
||||
@@ -67,6 +67,8 @@ struct IO {
|
||||
std::pair<std::string, bool> get_text(BEd &);
|
||||
|
||||
KeyEvent read_key();
|
||||
void write(const char *, uint64_t);
|
||||
void write(std::string_view);
|
||||
|
||||
private:
|
||||
static termios orig_termios;
|
||||
|
||||
@@ -1,55 +1,58 @@
|
||||
#pragma once
|
||||
|
||||
#include "internal/buffer/buffer.h"
|
||||
#include "pch.h"
|
||||
|
||||
namespace bed::internal::marks {
|
||||
struct MarksEngine {
|
||||
uint64_t marks[256];
|
||||
buffer::Line marks[256];
|
||||
|
||||
MarksEngine() {
|
||||
for (auto &m : marks)
|
||||
m = UINT64_MAX;
|
||||
m = {"", UINT64_MAX};
|
||||
}
|
||||
|
||||
uint64_t get(uint8_t m) {
|
||||
buffer::Line &get(uint8_t m) {
|
||||
return marks[m];
|
||||
}
|
||||
|
||||
void set(uint8_t m, uint64_t line) {
|
||||
marks[m] = line;
|
||||
}
|
||||
|
||||
void insert(uint64_t start, uint64_t count) {
|
||||
void insert(std::string bufname, uint64_t start, uint64_t count) {
|
||||
for (uint16_t i = 0; i <= UINT8_MAX; ++i) {
|
||||
if (marks[i] == UINT64_MAX)
|
||||
if (marks[i].buffername != bufname)
|
||||
continue;
|
||||
if (marks[i] >= start)
|
||||
marks[i] += count;
|
||||
if (marks[i].number == UINT64_MAX)
|
||||
continue;
|
||||
if (marks[i].number >= start)
|
||||
marks[i].number += count;
|
||||
}
|
||||
}
|
||||
|
||||
void erase(uint64_t start, uint64_t count) {
|
||||
void erase(std::string bufname, uint64_t start, uint64_t count) {
|
||||
for (uint16_t i = 0; i <= UINT8_MAX; ++i) {
|
||||
if (marks[i] == UINT64_MAX)
|
||||
if (marks[i].buffername != bufname)
|
||||
continue;
|
||||
if (marks[i] >= start) {
|
||||
if (marks[i] < start + count)
|
||||
marks[i] = UINT64_MAX;
|
||||
if (marks[i].number == UINT64_MAX)
|
||||
continue;
|
||||
if (marks[i].number >= start) {
|
||||
if (marks[i].number < start + count)
|
||||
marks[i].number = UINT64_MAX;
|
||||
else
|
||||
marks[i] -= count;
|
||||
marks[i].number -= count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void collapse(uint64_t start, uint64_t count) {
|
||||
void collapse(std::string bufname, uint64_t start, uint64_t count) {
|
||||
for (uint16_t i = 0; i <= UINT8_MAX; ++i) {
|
||||
if (marks[i] == UINT64_MAX)
|
||||
if (marks[i].buffername != bufname)
|
||||
continue;
|
||||
if (marks[i] >= start) {
|
||||
if (marks[i] < start + count)
|
||||
marks[i] = start;
|
||||
if (marks[i].number == UINT64_MAX)
|
||||
continue;
|
||||
if (marks[i].number >= start) {
|
||||
if (marks[i].number < start + count)
|
||||
marks[i].number = start;
|
||||
else
|
||||
marks[i] -= count;
|
||||
marks[i].number -= count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
#pragma once
|
||||
|
||||
#include "internal/functions/functions.h"
|
||||
#include "internal/functions/suffixes.h"
|
||||
#include "internal/io/command.h"
|
||||
#include "pch.h"
|
||||
|
||||
namespace bed::internal::parser {
|
||||
struct AddressPromise {
|
||||
struct None {}; //
|
||||
struct Current {}; // .
|
||||
struct Last {}; // $
|
||||
struct Number { // n
|
||||
uint64_t i;
|
||||
};
|
||||
struct Mark { // 'm
|
||||
char m;
|
||||
};
|
||||
struct Regex { // /re/ or ?re?
|
||||
internal::Direction dir;
|
||||
std::string re;
|
||||
};
|
||||
struct Diagnostic { // ^ 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> 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.
|
||||
};
|
||||
struct LastRange {}; // % , refers to last used range
|
||||
|
||||
std::optional<std::string> bufname;
|
||||
std::variant<
|
||||
None,
|
||||
Current,
|
||||
Last,
|
||||
Number,
|
||||
Mark,
|
||||
Regex,
|
||||
Diagnostic,
|
||||
SymbolDefinition,
|
||||
SymbolReference,
|
||||
Block,
|
||||
Scripted,
|
||||
LastRange>
|
||||
base{};
|
||||
int64_t offset = 0;
|
||||
bool jumping{false}; // ; == jumping and , == non jumping
|
||||
buffer::Line resolve(BEd &ctx);
|
||||
static std::optional<buffer::Line> get_line(BEd &ctx, std::vector<AddressPromise> &);
|
||||
static std::optional<buffer::Range> get_range(BEd &ctx, std::vector<AddressPromise> &);
|
||||
};
|
||||
|
||||
struct Command {
|
||||
bool temp_address{false};
|
||||
std::vector<AddressPromise> addresses{};
|
||||
functions::Function *function;
|
||||
functions::Function::Argument argument;
|
||||
std::vector<AddressPromise> argument_addresses{};
|
||||
functions::Suffix *suffix;
|
||||
};
|
||||
|
||||
struct CompletionContext {
|
||||
enum {
|
||||
Error,
|
||||
Valid,
|
||||
Incomplete
|
||||
} error;
|
||||
// TODO: store a state of typing context to think about possible completions.
|
||||
};
|
||||
|
||||
struct Parser {
|
||||
BEd &bed;
|
||||
std::string_view cmd;
|
||||
uint16_t i;
|
||||
Command *command;
|
||||
std::vector<io::Token> *tokens;
|
||||
CompletionContext *completion;
|
||||
|
||||
explicit Parser(
|
||||
std::string_view cmd, BEd &bed, Command *command,
|
||||
std::vector<io::Token> *tokens, CompletionContext *completion
|
||||
);
|
||||
|
||||
char peek(uint16_t = 0); // == \0 if at eof.
|
||||
std::string_view peek_str(uint16_t = UINT16_MAX);
|
||||
void advance(uint16_t = 1);
|
||||
|
||||
void skip_ws();
|
||||
|
||||
void locator(AddressPromise &);
|
||||
int64_t offset();
|
||||
void address(AddressPromise &addr);
|
||||
void addresses(std::vector<AddressPromise> &addresses);
|
||||
|
||||
void operation();
|
||||
|
||||
void parse();
|
||||
|
||||
static Command get_command(std::string_view, BEd &);
|
||||
static std::vector<AddressPromise> get_addresses(std::string_view cmd, BEd &bed);
|
||||
};
|
||||
} // namespace bed::internal::parser
|
||||
@@ -13,15 +13,15 @@ struct Parser {
|
||||
ParseState *root;
|
||||
Language lang;
|
||||
|
||||
Parser(vase::Vase &, uint64_t, Language);
|
||||
Parser(vase::Shard *, uint64_t, Language);
|
||||
~Parser();
|
||||
Parser(const Parser &) = delete;
|
||||
Parser &operator=(const Parser &) = delete;
|
||||
|
||||
void reset(vase::Vase &, uint64_t, Language);
|
||||
void erase(vase::Vase &, uint64_t, uint64_t);
|
||||
void insert(vase::Vase &, uint64_t, uint64_t);
|
||||
void modify(vase::Vase &, uint64_t, uint64_t);
|
||||
void reset(vase::Shard *, uint64_t, Language);
|
||||
void erase(vase::Shard *, uint64_t, uint64_t);
|
||||
void insert(vase::Shard *, uint64_t, uint64_t);
|
||||
void modify(vase::Shard *, uint64_t, uint64_t);
|
||||
|
||||
uint64_t next_closing(uint64_t line);
|
||||
uint64_t prev_opening(uint64_t line);
|
||||
@@ -36,7 +36,7 @@ struct Parser {
|
||||
uint64_t at;
|
||||
std::vector<Token> tokens;
|
||||
std::vector<ParseEvent> events;
|
||||
Iterator(uint64_t, Parser *, vase::Vase &);
|
||||
Iterator(uint64_t, Parser *, vase::Shard *);
|
||||
~Iterator();
|
||||
Iterator(const Iterator &) = delete;
|
||||
Iterator &operator=(const Iterator &) = delete;
|
||||
@@ -44,6 +44,6 @@ struct Parser {
|
||||
Iterator &operator=(Iterator &&other);
|
||||
void next();
|
||||
};
|
||||
std::optional<Iterator> get_hl(vase::Vase &, uint64_t);
|
||||
std::optional<Iterator> get_hl(vase::Shard *, uint64_t);
|
||||
};
|
||||
} // namespace bed::internal::syntax
|
||||
|
||||
@@ -147,7 +147,7 @@ struct Trie {
|
||||
}
|
||||
|
||||
static void collect(
|
||||
const Node &node,
|
||||
Node &node,
|
||||
std::string &key,
|
||||
std::vector<SearchResult> &result
|
||||
) {
|
||||
@@ -228,6 +228,44 @@ struct Trie {
|
||||
return *current->value;
|
||||
}
|
||||
|
||||
V *get_ptr(std::string_view key) {
|
||||
Node *current = &root;
|
||||
uint64_t pos = 0;
|
||||
while (pos < key.size()) {
|
||||
Node *child = find_child(*current, key[pos]);
|
||||
if (!child)
|
||||
return nullptr;
|
||||
const auto remaining = key.substr(pos);
|
||||
const auto common = common_prefix(child->edge, remaining);
|
||||
if (common != child->edge.size())
|
||||
return nullptr;
|
||||
pos += common;
|
||||
current = child;
|
||||
}
|
||||
if (!current->value)
|
||||
return nullptr;
|
||||
return &*current->value;
|
||||
}
|
||||
|
||||
const V *get_ptr(std::string_view key) const {
|
||||
const Node *current = &root;
|
||||
uint64_t pos = 0;
|
||||
while (pos < key.size()) {
|
||||
const Node *child = find_child(*current, key[pos]);
|
||||
if (!child)
|
||||
return nullptr;
|
||||
const auto remaining = key.substr(pos);
|
||||
const auto common = common_prefix(child->edge, remaining);
|
||||
if (common != child->edge.size())
|
||||
return nullptr;
|
||||
pos += common;
|
||||
current = child;
|
||||
}
|
||||
if (!current->value)
|
||||
return nullptr;
|
||||
return &*current->value;
|
||||
}
|
||||
|
||||
bool equal_char(char a, char b) const {
|
||||
if (case_sensitive)
|
||||
return a == b;
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "buffer.h"
|
||||
#include "pch.h"
|
||||
|
||||
namespace bed::internal::vase {
|
||||
struct OriginalBuffer : Buffer {
|
||||
const char *buf;
|
||||
uint64_t len;
|
||||
int fd = -1;
|
||||
|
||||
OriginalBuffer(std::filesystem::path base_dir);
|
||||
~OriginalBuffer();
|
||||
|
||||
void initialize();
|
||||
const char *read(uint64_t pos) override;
|
||||
uint64_t length() override;
|
||||
};
|
||||
} // namespace bed::internal::vase
|
||||
@@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "buffer/buffer.h"
|
||||
#include "buffer/original.h"
|
||||
#include "constants.h"
|
||||
#include "pch.h"
|
||||
#include "storage/original.h"
|
||||
#include "storage/storage.h"
|
||||
|
||||
namespace bed::internal::vase {
|
||||
struct Shard {
|
||||
@@ -24,9 +24,10 @@ struct Shard {
|
||||
static void retain(Shard *n);
|
||||
static void release(Shard *n);
|
||||
|
||||
static Shard *from_file(std::filesystem::path &path, OriginalBuffer *b, bool posix_ending);
|
||||
static Shard *from_command(const char *cmd, OriginalBuffer *o, bool posix_ending);
|
||||
static std::vector<Shard *> from_swap(std::filesystem::path &path, OriginalBuffer *b);
|
||||
static Shard *from_file(const std::filesystem::path &path, bool posix_ending);
|
||||
static Shard *from_string(const char *data, uint64_t len, bool posix_ending);
|
||||
static Shard *from_command(const char *cmd, bool posix_ending);
|
||||
// static std::vector<Shard *> from_swap(std::filesystem::path &path, OriginalStorage *b);
|
||||
|
||||
static std::pair<Shard *, Shard *> split(Shard *n, uint64_t offset);
|
||||
static Shard *concat(Shard *a, Shard *b);
|
||||
@@ -54,12 +55,14 @@ struct Branch : Shard {
|
||||
};
|
||||
|
||||
struct Petal : Shard {
|
||||
Buffer *source;
|
||||
Storage *source;
|
||||
uint64_t pos;
|
||||
|
||||
Petal(uint64_t length, uint64_t lines, Buffer *source, uint64_t pos)
|
||||
Petal(uint64_t length, uint64_t lines, Storage *source, uint64_t pos)
|
||||
: Shard(Kind::Petal, length, lines, 1),
|
||||
source(source), pos(pos) {};
|
||||
source(source), pos(pos) {
|
||||
source->retain();
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace bed::internal::vase
|
||||
|
||||
@@ -1,24 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include "../constants.h"
|
||||
#include "buffer.h"
|
||||
#include "pch.h"
|
||||
#include "storage.h"
|
||||
|
||||
namespace bed::internal::vase {
|
||||
struct AppendBuffer : Buffer {
|
||||
struct AppendStorage : Storage {
|
||||
char *buf = nullptr;
|
||||
uint64_t allocated_capacity = 0;
|
||||
uint64_t current_size = 0;
|
||||
int fd = -1;
|
||||
|
||||
AppendBuffer(std::filesystem::path base_dir);
|
||||
~AppendBuffer();
|
||||
AppendStorage(std::filesystem::path base_dir);
|
||||
~AppendStorage();
|
||||
|
||||
uint64_t append(const char c);
|
||||
uint64_t append(const char *text, uint64_t len);
|
||||
const char *read(uint64_t pos) override;
|
||||
uint64_t length() override;
|
||||
|
||||
void retain() override {}
|
||||
void release() override {}
|
||||
|
||||
private:
|
||||
void grow(uint64_t len);
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include "pch.h"
|
||||
#include "storage.h"
|
||||
|
||||
namespace bed::internal::vase {
|
||||
struct OriginalStorage : Storage {
|
||||
std::atomic_uint64_t refs{0};
|
||||
const char *buf = nullptr;
|
||||
uint64_t len = 0;
|
||||
int fd = -1;
|
||||
|
||||
OriginalStorage(std::filesystem::path base_dir);
|
||||
~OriginalStorage();
|
||||
|
||||
void initialize();
|
||||
const char *read(uint64_t pos) override;
|
||||
uint64_t length() override;
|
||||
|
||||
void retain() override {
|
||||
refs++;
|
||||
}
|
||||
|
||||
void release() override {
|
||||
if (--refs > 0)
|
||||
return;
|
||||
delete this;
|
||||
}
|
||||
};
|
||||
} // namespace bed::internal::vase
|
||||
@@ -3,9 +3,11 @@
|
||||
#include "pch.h"
|
||||
|
||||
namespace bed::internal::vase {
|
||||
struct Buffer {
|
||||
struct Storage {
|
||||
virtual const char *read(uint64_t pos) = 0;
|
||||
virtual uint64_t length() = 0;
|
||||
virtual ~Buffer() = default;
|
||||
virtual ~Storage() = default;
|
||||
virtual void retain() = 0;
|
||||
virtual void release() = 0;
|
||||
};
|
||||
} // namespace bed::internal::vase
|
||||
+54
-100
@@ -1,12 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "buffer/append.h"
|
||||
#include "buffer/original.h"
|
||||
#include "constants.h"
|
||||
#include "definitions.h"
|
||||
#include "iterators/line.h"
|
||||
#include "pch.h"
|
||||
#include "shard.h"
|
||||
#include "storage/append.h"
|
||||
#include "storage/original.h"
|
||||
|
||||
namespace bed::internal::vase {
|
||||
struct Point {
|
||||
@@ -19,103 +19,57 @@ struct Range {
|
||||
Point end;
|
||||
};
|
||||
|
||||
struct Vase {
|
||||
struct RegexGroup {
|
||||
uint64_t start{0};
|
||||
uint64_t end{0};
|
||||
};
|
||||
|
||||
struct RegexMatch {
|
||||
uint64_t start;
|
||||
uint64_t end;
|
||||
RegexGroup groups[9]{};
|
||||
};
|
||||
|
||||
struct ReplacePart {
|
||||
enum struct PartType {
|
||||
FullMatch,
|
||||
CaptureGroup,
|
||||
Constant
|
||||
} type;
|
||||
|
||||
std::variant<uint8_t, Shard *> value;
|
||||
};
|
||||
|
||||
OriginalBuffer *original;
|
||||
AppendBuffer *append;
|
||||
Shard *root;
|
||||
|
||||
#ifdef _WIN32
|
||||
bool posix_ending = false;
|
||||
bool using_crlf = true;
|
||||
#else
|
||||
bool posix_ending = true;
|
||||
bool using_crlf = false;
|
||||
#endif
|
||||
|
||||
std::filesystem::path path;
|
||||
std::filesystem::path swapdir;
|
||||
|
||||
Vase(std::filesystem::path path, std::filesystem::path swapdir);
|
||||
Vase(std::string cmd, std::filesystem::path swapdir);
|
||||
Vase(std::filesystem::path swapdir);
|
||||
~Vase();
|
||||
Vase(Vase &&other) noexcept;
|
||||
Vase &operator=(Vase &&other) noexcept;
|
||||
Vase(const Vase &) = delete;
|
||||
Vase &operator=(const Vase &) = delete;
|
||||
|
||||
uint64_t length();
|
||||
uint64_t lines();
|
||||
std::string to_string();
|
||||
std::string to_string(Range range);
|
||||
|
||||
Iterator iterate(uint64_t line, Direction dir);
|
||||
|
||||
void insert(Point *point, char key);
|
||||
void insert(Point *point, std::string_view str);
|
||||
void insert(Point *point, const char *data, uint64_t len);
|
||||
void erase(Point *point, uint64_t amount, Direction dir);
|
||||
void erase(Range range);
|
||||
void replace(Range range, std::string_view str);
|
||||
void replace(Range range, const char *data, uint64_t len);
|
||||
|
||||
void move_clusters(Point *point, uint64_t amount, Direction dir);
|
||||
void move_lines(Point *point, uint64_t amount, Direction dir);
|
||||
void clamp(Point *point);
|
||||
|
||||
void regex_search_replace(
|
||||
std::string_view pattern, Range range,
|
||||
std::string_view replace, std::string_view options
|
||||
);
|
||||
|
||||
std::vector<Range> regex_search(
|
||||
std::string_view pattern, Range range, std::string_view options
|
||||
);
|
||||
|
||||
uint64_t find_next(std::string_view pattern, uint64_t start);
|
||||
uint64_t find_prev(std::string_view pattern, uint64_t start);
|
||||
|
||||
bool undo();
|
||||
bool redo();
|
||||
void snapshot();
|
||||
void prune_history(uint64_t n);
|
||||
|
||||
bool save();
|
||||
bool save_swap();
|
||||
|
||||
uint64_t offset_of(Point point);
|
||||
Point point_of(uint64_t offset);
|
||||
|
||||
private:
|
||||
std::vector<Shard *> history;
|
||||
uint64_t history_top;
|
||||
|
||||
void _insert(Point *point, const char *data, uint64_t len);
|
||||
|
||||
std::vector<ReplacePart> parse_replace(std::string_view s);
|
||||
std::vector<RegexMatch> _regex_search(
|
||||
std::string_view pattern, Range range, std::string_view options
|
||||
);
|
||||
struct RegexGroup {
|
||||
uint64_t start{0};
|
||||
uint64_t end{0};
|
||||
};
|
||||
|
||||
struct RegexMatch {
|
||||
uint64_t start;
|
||||
uint64_t end;
|
||||
RegexGroup groups[9]{};
|
||||
};
|
||||
|
||||
struct ReplacePart {
|
||||
enum struct PartType {
|
||||
FullMatch,
|
||||
CaptureGroup,
|
||||
Constant
|
||||
} type;
|
||||
std::variant<uint8_t, Shard *> value;
|
||||
};
|
||||
|
||||
uint64_t offset_of(Shard *root, uint64_t line);
|
||||
uint64_t offset_of(Shard *root, Point point);
|
||||
Point point_of(Shard *root, uint64_t offset);
|
||||
|
||||
std::string to_string(Shard *root);
|
||||
std::string to_string(Shard *root, Range range);
|
||||
|
||||
Shard *insert(AppendStorage *ap, Shard *root, Shard *text, uint64_t line);
|
||||
Shard *erase(Shard *root, uint64_t start, uint64_t end);
|
||||
Shard *copy(Shard *root, uint64_t start, uint64_t end);
|
||||
|
||||
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);
|
||||
|
||||
Shard *substitute(
|
||||
AppendStorage *ap, Shard *root,
|
||||
std::string_view pattern, uint64_t start, uint64_t end,
|
||||
std::string_view replace, std::string_view options
|
||||
);
|
||||
|
||||
// internal
|
||||
|
||||
void _insert(AppendStorage *ap, Shard **root, Point *point, const char *data, uint64_t len);
|
||||
Shard *insert(AppendStorage *ap, Shard *root, Point *point, char key);
|
||||
Shard *insert(AppendStorage *ap, Shard *root, Point *point, const char *data, uint64_t len);
|
||||
|
||||
Shard *erase(Shard *root, Range range);
|
||||
Shard *replace(AppendStorage *ap, Shard *root, Range range, const char *data, uint64_t len);
|
||||
|
||||
std::vector<ReplacePart> parse_replace(AppendStorage *ap, std::string_view s);
|
||||
std::vector<RegexMatch> _regex_search(
|
||||
Shard *root, std::string_view pattern, uint64_t start_offset, uint64_t end_offset, std::string_view options
|
||||
);
|
||||
} // namespace bed::internal::vase
|
||||
|
||||
Reference in New Issue
Block a user