diff --git a/README.md b/README.md
index ad5223f..d7451f2 100644
--- a/README.md
+++ b/README.md
@@ -10,12 +10,6 @@ Vase is a avl piece tree like structure which handles loading, insertion, erasur
done.
-#### Ed
-
-Ed is an ed (the posix line editor) implementation using `Vase`.
-
-Mostly done.
-
#### `hl`
`hl` is a stateful super fast syntax highlighter.
@@ -38,10 +32,10 @@ It should support:
Not done yet.
-#### BEd
+### BEd
Better ed.
-An ed implementation but with:
+An ed implementation (mostly posix compliant) but with:
- Lsp support for autocomplete suggetions when in ed text mode.
- Autocomplete for language snippets + other words found near the cursor etc.
- text mode where arrow keys etc. work as expected.
@@ -73,3 +67,10 @@ An ed implementation but with:
- Nerdfonts & themable colorized outputs.
- Better address marking with ranges.
- & A lot more cool stuff.
+
+#### Implementation status:
+
+- Internal buffer:
+ - Super fast and memory efficient buffer implementation done.
+ - Loading from files/subshell commands done.
+- Most of the posix ed commands except regex ones done.
diff --git a/include/commands/ed/ed.h b/include/commands/bed/bed.h
similarity index 88%
rename from include/commands/ed/ed.h
rename to include/commands/bed/bed.h
index afca18c..edfb1ed 100644
--- a/include/commands/ed/ed.h
+++ b/include/commands/bed/bed.h
@@ -3,9 +3,9 @@
#include "internal/vase/vase.h"
#include "pch.h"
-namespace crib::commands::ed {
-struct ed_error : std::runtime_error {
- ed_error(const char *msg) : std::runtime_error(msg) {}
+namespace crib::commands::bed {
+struct bed_error : std::runtime_error {
+ bed_error(const char *msg) : std::runtime_error(msg) {}
};
struct Command {
@@ -58,7 +58,7 @@ struct Command {
std::string argument;
};
-struct Ed {
+struct BEd {
crib::internal::vase::Vase vase;
uint64_t line = 0;
bool modified = false;
@@ -73,7 +73,7 @@ struct Ed {
std::filesystem::path save_path = "";
std::string last_message = "";
- Ed(std::string file_path, bool suppress_mode, std::string prompt_)
+ BEd(std::string file_path, bool suppress_mode, std::string prompt_)
: vase("/tmp"), suppress_mode(suppress_mode), prompt(prompt_) {
if (prompt == "")
prompt = "*";
@@ -96,4 +96,4 @@ struct Ed {
std::string summary();
void help();
void run(std::vector);
-} // namespace crib::commands::ed
+} // namespace crib::commands::bed
diff --git a/src/cli/cli.cc b/src/cli/cli.cc
index 5bcb045..596412b 100644
--- a/src/cli/cli.cc
+++ b/src/cli/cli.cc
@@ -1,12 +1,12 @@
#include "cli.h"
-#include "commands/ed/ed.h"
+#include "commands/bed/bed.h"
namespace crib::cli {
static const std::unordered_map commands = {
- {"ed",
- {crib::commands::ed::run,
- crib::commands::ed::summary,
- crib::commands::ed::help}},
+ {"bed",
+ {crib::commands::bed::run,
+ crib::commands::bed::summary,
+ crib::commands::bed::help}},
};
bool use_color() {
diff --git a/src/commands/ed/ed.cc b/src/commands/bed/bed.cc
similarity index 70%
rename from src/commands/ed/ed.cc
rename to src/commands/bed/bed.cc
index 7f05e4b..0ee9d90 100644
--- a/src/commands/ed/ed.cc
+++ b/src/commands/bed/bed.cc
@@ -1,9 +1,9 @@
-#include "commands/ed/ed.h"
+#include "commands/bed/bed.h"
#include "cli.h"
-namespace crib::commands::ed {
+namespace crib::commands::bed {
std::string summary() {
- return "A POSIX-compliant line editor.";
+ return "Better Ed, a modern take on a posix compliant line editor.";
}
void help() {}
@@ -26,15 +26,15 @@ void run(std::vector args) {
file = args[i];
}
}
- Ed ed(file, suppress, prompt);
+ BEd bed(file, suppress, prompt);
std::string command;
while (true) {
std::string cmd;
- if (ed.prompt_mode)
- std::cout << ed.prompt;
+ if (bed.prompt_mode)
+ std::cout << bed.prompt;
bool eof = !std::getline(std::cin, cmd);
- if (!ed.handle(cmd, eof))
+ if (!bed.handle(cmd, eof))
return;
}
}
-} // namespace crib::commands::ed
+} // namespace crib::commands::bed
diff --git a/src/commands/ed/handle.cc b/src/commands/bed/handle.cc
similarity index 87%
rename from src/commands/ed/handle.cc
rename to src/commands/bed/handle.cc
index ff021df..f9c82c7 100644
--- a/src/commands/ed/handle.cc
+++ b/src/commands/bed/handle.cc
@@ -1,7 +1,7 @@
-#include "commands/ed/ed.h"
+#include "commands/bed/bed.h"
-namespace crib::commands::ed {
-bool Ed::handle(std::string cmd, bool eof) {
+namespace crib::commands::bed {
+bool BEd::handle(std::string cmd, bool eof) {
using namespace crib::internal::vase;
try {
if (line > vase.lines())
@@ -15,7 +15,7 @@ bool Ed::handle(std::string cmd, bool eof) {
case Command::Type::Quit:
if (modified && !was_quitting) {
quitting = true;
- throw ed_error("Buffer modified.");
+ throw bed_error("Buffer modified.");
} else {
return false;
}
@@ -31,15 +31,15 @@ bool Ed::handle(std::string cmd, bool eof) {
line++;
}
if (line == 0)
- throw ed_error("Line 0 is invalid.");
+ throw bed_error("Line 0 is invalid.");
if (line > vase.lines())
- throw ed_error("Line position too high.");
+ throw bed_error("Line position too high.");
Iterator it = vase.iterate(line - 1, Direction::Forward);
it.next();
std::cout << it.line << std::endl;
} break;
case Command::Type::Invalid:
- throw ed_error("Invalid command.");
+ throw bed_error("Invalid command.");
case Command::Type::HelpToggle:
help_mode = !help_mode;
if (help_mode && last_message != "")
@@ -62,9 +62,9 @@ bool Ed::handle(std::string cmd, bool eof) {
resolve_address(command.end, &line_end);
}
if (line_start == 0)
- throw ed_error("Line 0 is invalid.");
+ throw bed_error("Line 0 is invalid.");
if (line_end < line_start)
- throw ed_error("Invalid address range.");
+ throw bed_error("Invalid address range.");
Iterator it = vase.iterate(line_start - 1, Direction::Forward);
while (it.next() && line_start++ <= line_end)
std::cout << it.line << std::endl;
@@ -80,9 +80,9 @@ bool Ed::handle(std::string cmd, bool eof) {
resolve_address(command.end, &line_end);
}
if (line_start == 0)
- throw ed_error("Line 0 is invalid.");
+ throw bed_error("Line 0 is invalid.");
if (line_end < line_start)
- throw ed_error("Invalid address range.");
+ throw bed_error("Invalid address range.");
Iterator it = vase.iterate(line_start - 1, Direction::Forward);
while (it.next() && line_start++ <= line_end)
std::cout << list_string(it.line) << std::endl;
@@ -98,9 +98,9 @@ bool Ed::handle(std::string cmd, bool eof) {
resolve_address(command.end, &line_end);
}
if (line_start == 0)
- throw ed_error("Line 0 is invalid.");
+ throw bed_error("Line 0 is invalid.");
if (line_end < line_start)
- throw ed_error("Invalid address range.");
+ throw bed_error("Invalid address range.");
Iterator it = vase.iterate(line_start - 1, Direction::Forward);
while (it.next() && line_start <= line_end)
std::cout << line_start++ << "\t" << it.line << std::endl;
@@ -171,7 +171,7 @@ bool Ed::handle(std::string cmd, bool eof) {
resolve_address(command.end, &line_end);
}
if (line_end < line_start)
- throw ed_error("Invalid address range.");
+ throw bed_error("Invalid address range.");
std::string text;
std::string cline;
uint64_t line_count = 0;
@@ -203,7 +203,7 @@ bool Ed::handle(std::string cmd, bool eof) {
resolve_address(command.end, &line_end);
}
if (line_end < line_start)
- throw ed_error("Invalid address range.");
+ throw bed_error("Invalid address range.");
vase.snapshot();
vase.erase({{line_start - 1, 0}, {line_end, 0}});
modified = true;
@@ -216,7 +216,7 @@ bool Ed::handle(std::string cmd, bool eof) {
if (path.empty()) {
path = save_path;
if (path.empty())
- throw ed_error("Need file to write to.");
+ throw bed_error("Need file to write to.");
}
uint64_t line_start = 1;
uint64_t line_end = vase.lines();
@@ -229,36 +229,36 @@ bool Ed::handle(std::string cmd, bool eof) {
resolve_address(command.end, &line_end);
}
if (vase.lines() && line_start == 0)
- throw ed_error("Line 0 is invalid.");
+ throw bed_error("Line 0 is invalid.");
if (line_end < line_start)
- throw ed_error("Invalid address range.");
+ throw bed_error("Invalid address range.");
uint64_t bytes = 0;
if (path[0] == '!') {
FILE *pipe = popen(path.c_str() + 1, "w");
if (!pipe)
- throw ed_error("Error starting command.");
+ throw bed_error("Error starting command.");
Iterator it = vase.iterate(line_start - 1, Direction::Forward);
while (it.next() && line_start++ <= line_end) {
it.line += '\n';
bytes += it.line.size();
if (fputs(it.line.c_str(), pipe) == EOF) {
pclose(pipe);
- throw ed_error("Error writing to command.");
+ throw bed_error("Error writing to command.");
}
}
if (pclose(pipe) == -1)
- throw ed_error("Error closing command.");
+ throw bed_error("Error closing command.");
} else {
std::ofstream file(path, std::ios::out | std::ios::trunc);
if (!file)
- throw ed_error("Error writing to file.");
+ throw bed_error("Error writing to file.");
Iterator it = vase.iterate(line_start - 1, Direction::Forward);
while (it.next() && line_start++ <= line_end) {
file << it.line << '\n';
bytes += it.line.size() + 1;
}
if (!file)
- throw ed_error("Error writing to file.");
+ throw bed_error("Error writing to file.");
save_path = path;
modified = false;
}
@@ -275,9 +275,9 @@ bool Ed::handle(std::string cmd, bool eof) {
resolve_address(command.end, &line_end);
}
if (line_end < line_start)
- throw ed_error("Invalid address range.");
+ throw bed_error("Invalid address range.");
if (line_start == 0)
- throw ed_error("Invalid line number given.");
+ throw bed_error("Invalid line number given.");
if (line_end == line_start)
break;
vase.snapshot();
@@ -294,20 +294,20 @@ bool Ed::handle(std::string cmd, bool eof) {
resolve_address(command.start, &mark_line);
}
if (mark_line == 0)
- throw ed_error("Invalid line number given.");
+ throw bed_error("Invalid line number given.");
char mark = command.argument[0];
marks[mark - 'a'] = mark_line;
} break;
case Command::Type::Edit: {
if (modified && !was_editing) {
editing = true;
- throw ed_error("Buffer modified.");
+ throw bed_error("Buffer modified.");
}
std::string path = command.argument;
if (path.empty()) {
path = save_path;
if (path.empty())
- throw ed_error("Need file to read from.");
+ throw bed_error("Need file to read from.");
}
if (path[0] == '!') {
path.erase(1);
@@ -329,7 +329,7 @@ bool Ed::handle(std::string cmd, bool eof) {
if (path.empty()) {
path = save_path;
if (path.empty())
- throw ed_error("Need file to read from.");
+ throw bed_error("Need file to read from.");
}
if (path[0] == '!') {
path.erase(0, 1);
@@ -350,7 +350,7 @@ bool Ed::handle(std::string cmd, bool eof) {
case Command::Type::Filename: {
std::string path = command.argument;
if (path.empty())
- throw ed_error("No filename given.");
+ throw bed_error("No filename given.");
save_path = path;
std::cout << save_path.string() << std::endl;
} break;
@@ -373,7 +373,7 @@ bool Ed::handle(std::string cmd, bool eof) {
break;
}
}
- } catch (ed_error &e) {
+ } catch (bed_error &e) {
last_message = e.what();
std::cout << "?" << std::endl;
if (help_mode)
@@ -381,4 +381,4 @@ bool Ed::handle(std::string cmd, bool eof) {
}
return true;
}
-} // namespace crib::commands::ed
+} // namespace crib::commands::bed
diff --git a/src/commands/ed/helpers.cc b/src/commands/bed/helpers.cc
similarity index 83%
rename from src/commands/ed/helpers.cc
rename to src/commands/bed/helpers.cc
index f24b073..c3c4e57 100644
--- a/src/commands/ed/helpers.cc
+++ b/src/commands/bed/helpers.cc
@@ -1,7 +1,7 @@
-#include "commands/ed/ed.h"
+#include "commands/bed/bed.h"
-namespace crib::commands::ed {
-void Ed::append(std::string text, uint64_t line) {
+namespace crib::commands::bed {
+void BEd::append(std::string text, uint64_t line) {
using namespace crib::internal::vase;
Point p = {line, 0};
if (!vase.lines()) {
@@ -15,15 +15,15 @@ void Ed::append(std::string text, uint64_t line) {
vase.insert(&p, text);
}
-void Ed::remove(uint64_t start_line, uint64_t end_line) {
+void BEd::remove(uint64_t start_line, uint64_t end_line) {
vase.erase({{start_line - 1, 0}, {end_line, 0}});
}
-void Ed::join(uint64_t start_line, uint64_t end_line) {
+void BEd::join(uint64_t start_line, uint64_t end_line) {
vase.regex_search_replace("\\n", {{start_line - 1, 0}, {end_line, 0}}, "", "");
}
-std::string Ed::list_string(std::string_view s) {
+std::string BEd::list_string(std::string_view s) {
uint32_t width = 80;
winsize ws{};
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0 && ws.ws_col != 0)
@@ -80,4 +80,4 @@ std::string Ed::list_string(std::string_view s) {
out += '$';
return out;
}
-} // namespace crib::commands::ed
+} // namespace crib::commands::bed
diff --git a/src/commands/ed/parsers/address.cc b/src/commands/bed/parsers/address.cc
similarity index 90%
rename from src/commands/ed/parsers/address.cc
rename to src/commands/bed/parsers/address.cc
index ee68937..105f77d 100644
--- a/src/commands/ed/parsers/address.cc
+++ b/src/commands/bed/parsers/address.cc
@@ -1,7 +1,7 @@
-#include "commands/ed/ed.h"
+#include "commands/bed/bed.h"
-namespace crib::commands::ed {
-void Ed::parse_address(std::string_view cmd, uint64_t &i, Command::Address &addr) {
+namespace crib::commands::bed {
+void BEd::parse_address(std::string_view cmd, uint64_t &i, Command::Address &addr) {
auto skip_space = [&] {
while (i < cmd.size() && (cmd[i] == ' ' || cmd[i] == '\t'))
++i;
@@ -26,7 +26,7 @@ void Ed::parse_address(std::string_view cmd, uint64_t &i, Command::Address &addr
if (i < cmd.size() && 'a' <= cmd[i] && cmd[i] <= 'z')
i++;
else
- throw ed_error("Invalid mark.");
+ throw bed_error("Invalid mark.");
addr.mark = cmd[i];
break;
case '/': {
@@ -135,7 +135,7 @@ void Ed::parse_address(std::string_view cmd, uint64_t &i, Command::Address &addr
}
}
-void Ed::resolve_address(Command::Address addr, uint64_t *out_line) {
+void BEd::resolve_address(Command::Address addr, uint64_t *out_line) {
switch (addr.type) {
case Command::Address::Type::None:
break;
@@ -153,7 +153,7 @@ void Ed::resolve_address(Command::Address addr, uint64_t *out_line) {
case Command::Address::Type::Mark:
*out_line = marks[addr.mark - 'a'];
if (!*out_line)
- throw ed_error("Unset mark used.");
+ throw bed_error("Unset mark used.");
break;
case Command::Address::Type::SearchForward:
if (addr.regex == "")
@@ -169,10 +169,10 @@ void Ed::resolve_address(Command::Address addr, uint64_t *out_line) {
break;
}
if ((int64_t)*out_line + addr.offset < 0)
- throw ed_error("Line position can't be negative.");
+ throw bed_error("Line position can't be negative.");
else
*out_line += addr.offset;
if (*out_line > vase.lines())
- throw ed_error("Line position too high.");
+ throw bed_error("Line position too high.");
}
-} // namespace crib::commands::ed
+} // namespace crib::commands::bed
diff --git a/src/commands/ed/parsers/command.cc b/src/commands/bed/parsers/command.cc
similarity index 89%
rename from src/commands/ed/parsers/command.cc
rename to src/commands/bed/parsers/command.cc
index e86cd4d..93d414f 100644
--- a/src/commands/ed/parsers/command.cc
+++ b/src/commands/bed/parsers/command.cc
@@ -1,7 +1,7 @@
-#include "commands/ed/ed.h"
+#include "commands/bed/bed.h"
-namespace crib::commands::ed {
-Command Ed::parse(std::string cmd, bool eof) {
+namespace crib::commands::bed {
+Command BEd::parse(std::string cmd, bool eof) {
Command command = {};
if (eof)
return (command.type = Command::Type::Quit, command);
@@ -107,7 +107,7 @@ Command Ed::parse(std::string cmd, bool eof) {
if (cmd[i] == ' ' || cmd[i] == '\t')
skip_space();
else
- throw ed_error("Invalid command.");
+ throw bed_error("Invalid command.");
command.argument = cmd.substr(i);
return command;
case 'e':
@@ -118,7 +118,7 @@ Command Ed::parse(std::string cmd, bool eof) {
if (cmd[i] == ' ' || cmd[i] == '\t')
skip_space();
else
- throw ed_error("Invalid command.");
+ throw bed_error("Invalid command.");
command.argument = cmd.substr(i);
return command;
case 'E':
@@ -129,7 +129,7 @@ Command Ed::parse(std::string cmd, bool eof) {
if (cmd[i] == ' ' || cmd[i] == '\t')
skip_space();
else
- throw ed_error("Invalid command.");
+ throw bed_error("Invalid command.");
command.argument = cmd.substr(i);
return command;
case 'f':
@@ -140,18 +140,18 @@ Command Ed::parse(std::string cmd, bool eof) {
if (cmd[i] == ' ' || cmd[i] == '\t')
skip_space();
else
- throw ed_error("Invalid command.");
+ throw bed_error("Invalid command.");
command.argument = cmd.substr(i);
return command;
case 'k':
command.type = Command::Type::Mark;
i++;
if (i >= cmd.size())
- throw ed_error("Invalid command.");
+ throw bed_error("Invalid command.");
if ('a' <= cmd[i] && cmd[i] <= 'z')
command.argument = cmd[i];
else
- throw ed_error("Invalid mark used.");
+ throw bed_error("Invalid mark used.");
break;
case '#':
command.type = Command::Type::Dump;
@@ -163,8 +163,8 @@ Command Ed::parse(std::string cmd, bool eof) {
command.suffix = cmd[i++];
skip_space();
if (i != cmd.size())
- throw ed_error("Invalid command.");
+ throw bed_error("Invalid command.");
}
return command;
}
-} // namespace crib::commands::ed
+} // namespace crib::commands::bed
diff --git a/src/commands/ed/parsers/regex.cc b/src/commands/bed/parsers/regex.cc
similarity index 100%
rename from src/commands/ed/parsers/regex.cc
rename to src/commands/bed/parsers/regex.cc