Cleanup.
This commit is contained in:
@@ -0,0 +1,73 @@
|
|||||||
|
#include "bed.h"
|
||||||
|
#include "internal/parser/parser.h"
|
||||||
|
|
||||||
|
namespace bed {
|
||||||
|
BEd::BEd(std::vector<std::string> args)
|
||||||
|
: theme(internal::theme::Theme::default_theme()), io(*this) {
|
||||||
|
std::string prompt_ = "";
|
||||||
|
std::string file = "";
|
||||||
|
bool suppress = false;
|
||||||
|
bool color = true;
|
||||||
|
for (size_t i = 1; i < args.size(); i++) {
|
||||||
|
if (args[i] == "-p") {
|
||||||
|
i++;
|
||||||
|
if (i >= args.size())
|
||||||
|
throw fatal_error("Prompt not specified!", 1);
|
||||||
|
prompt_ = args[i];
|
||||||
|
} else if (args[i] == "-s") {
|
||||||
|
suppress = true;
|
||||||
|
} else if (args[i] == "--no-color") {
|
||||||
|
color = false;
|
||||||
|
} else if (args[i] == "-v" || args[i] == "--verbose") {
|
||||||
|
help_mode = true;
|
||||||
|
} else if (args[i] == "-h" || args[i] == "--help") {
|
||||||
|
print_help();
|
||||||
|
throw fatal_error("", 0);
|
||||||
|
} else {
|
||||||
|
if (file.size())
|
||||||
|
throw fatal_error("Invalid arguments given.", 1);
|
||||||
|
file = args[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (prompt_ != "")
|
||||||
|
prompt = [p = std::move(prompt_)](BEd &) { return p; };
|
||||||
|
else
|
||||||
|
prompt_mode = false;
|
||||||
|
suppress_mode = suppress;
|
||||||
|
const char *no_color = getenv("NO_COLOR");
|
||||||
|
if (no_color && *no_color != '\0')
|
||||||
|
color = false;
|
||||||
|
const char *colorterm = getenv("COLORTERM");
|
||||||
|
if (colorterm
|
||||||
|
&& strcmp(colorterm, "truecolor") != 0
|
||||||
|
&& strcmp(colorterm, "24bit") != 0)
|
||||||
|
color = false;
|
||||||
|
color_mode = color;
|
||||||
|
internal::functions::Function::register_posix(*this);
|
||||||
|
internal::functions::Function::register_extented(*this);
|
||||||
|
internal::functions::Suffix::register_suffixes(*this);
|
||||||
|
languages["ruby"] = new internal::syntax::Language(internal::syntax::ruby::lang_ruby());
|
||||||
|
buffers["clip"] = new internal::buffer::ClipBuffer("clip");
|
||||||
|
current() = {"default", 0};
|
||||||
|
try {
|
||||||
|
if (file != "")
|
||||||
|
handle(":default:E " + file, false);
|
||||||
|
} catch (ed_error &e) {
|
||||||
|
io.write_line("?");
|
||||||
|
if (help_mode)
|
||||||
|
io.write_line(e.what());
|
||||||
|
last_help = e.what();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BEd::~BEd() {
|
||||||
|
for (auto &[_, buffer] : buffers)
|
||||||
|
delete buffer;
|
||||||
|
for (auto &[_, lang] : languages)
|
||||||
|
delete lang;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BEd::print_help() {
|
||||||
|
io.write("BEd - A line editor.\n");
|
||||||
|
}
|
||||||
|
} // namespace bed
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
#include "bed.h"
|
||||||
|
#include "internal/parser/parser.h"
|
||||||
|
|
||||||
|
namespace bed {
|
||||||
|
void BEd::run() {
|
||||||
|
while (true) {
|
||||||
|
internal::ui::CommandIO command(*this);
|
||||||
|
auto [cmd, eof] = command.run();
|
||||||
|
try {
|
||||||
|
handle(cmd, eof);
|
||||||
|
} catch (ed_error &e) {
|
||||||
|
io.apply(internal::io::Token::Warning);
|
||||||
|
io.write_line("?");
|
||||||
|
if (help_mode)
|
||||||
|
io.write_line(e.what());
|
||||||
|
io.reset();
|
||||||
|
last_help = e.what();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BEd::handle(std::string_view cmd, bool eof) {
|
||||||
|
if (eof && cmd.empty()) {
|
||||||
|
eof_op.handle(*this, "", nullptr, std::monostate(), nullptr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
internal::parser::Command c = internal::parser::Parser::get_command(cmd, *this);
|
||||||
|
if (c.temp_address) {
|
||||||
|
marks.get(251) = marks.get(250);
|
||||||
|
prev_2 = prev_1;
|
||||||
|
temporary_current = true;
|
||||||
|
}
|
||||||
|
internal::buffer::Address address;
|
||||||
|
switch (c.function->address_kind) {
|
||||||
|
case internal::functions::Function::AddressKind::None: {
|
||||||
|
auto a = internal::parser::AddressPromise::get_line(*this, c.addresses);
|
||||||
|
if (!a.has_value()) {
|
||||||
|
auto vec = internal::parser::Parser::get_addresses(c.function->default_address, *this);
|
||||||
|
a = internal::parser::AddressPromise::get_line(*this, vec);
|
||||||
|
if (!a.has_value())
|
||||||
|
a = current();
|
||||||
|
}
|
||||||
|
address = a->buffername;
|
||||||
|
} break;
|
||||||
|
case internal::functions::Function::AddressKind::Line: {
|
||||||
|
auto a = internal::parser::AddressPromise::get_line(*this, c.addresses);
|
||||||
|
if (!a.has_value()) {
|
||||||
|
auto vec = internal::parser::Parser::get_addresses(c.function->default_address, *this);
|
||||||
|
a = internal::parser::AddressPromise::get_line(*this, vec);
|
||||||
|
if (!a.has_value())
|
||||||
|
a = current();
|
||||||
|
}
|
||||||
|
address = *a;
|
||||||
|
} break;
|
||||||
|
case internal::functions::Function::AddressKind::Range: {
|
||||||
|
auto a = internal::parser::AddressPromise::get_range(*this, c.addresses);
|
||||||
|
if (!a.has_value()) {
|
||||||
|
auto vec = internal::parser::Parser::get_addresses(c.function->default_address, *this);
|
||||||
|
a = internal::parser::AddressPromise::get_range(*this, vec);
|
||||||
|
if (!a.has_value())
|
||||||
|
a = internal::buffer::Range(current(), current());
|
||||||
|
}
|
||||||
|
address = *a;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
if (std::holds_alternative<internal::buffer::Line>(c.argument)) {
|
||||||
|
if (c.argument_addresses.empty())
|
||||||
|
throw ed_error("Function needs address argument.");
|
||||||
|
auto a = internal::parser::AddressPromise::get_line(*this, c.argument_addresses);
|
||||||
|
if (a.has_value())
|
||||||
|
c.argument = *a;
|
||||||
|
else
|
||||||
|
c.argument = current();
|
||||||
|
} else if (std::holds_alternative<internal::buffer::Range>(c.argument)) {
|
||||||
|
if (c.argument_addresses.empty())
|
||||||
|
throw ed_error("Function needs address argument.");
|
||||||
|
auto a = internal::parser::AddressPromise::get_range(*this, c.argument_addresses);
|
||||||
|
if (a.has_value())
|
||||||
|
c.argument = *a;
|
||||||
|
else
|
||||||
|
c.argument = internal::buffer::Range(current(), current());
|
||||||
|
}
|
||||||
|
if (!c.function->accept_zero) {
|
||||||
|
if (std::holds_alternative<internal::buffer::Line>(address)) {
|
||||||
|
if (std::get<internal::buffer::Line>(address).number == 0)
|
||||||
|
throw ed_error("Line number can't be zero.");
|
||||||
|
} else if (std::holds_alternative<internal::buffer::Range>(address)) {
|
||||||
|
auto r = std::get<internal::buffer::Range>(address);
|
||||||
|
if (r.start == 0 || r.end == 0)
|
||||||
|
throw ed_error("Line number can't be zero.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal::vase::Shard *text = nullptr;
|
||||||
|
if (c.function->input_mode == internal::functions::Function::InputMode::Text) {
|
||||||
|
internal::vase::Shard *vase = nullptr;
|
||||||
|
internal::syntax::Language *lang = nullptr;
|
||||||
|
void *state = nullptr;
|
||||||
|
if (c.function->pre_text_mode)
|
||||||
|
std::tie(vase, lang, state) = c.function->pre_text_mode(*this, address, c.argument);
|
||||||
|
internal::ui::text_mode::TextMode tm(*this, vase, lang, state);
|
||||||
|
auto [a, b] = tm.run();
|
||||||
|
if (!b) {
|
||||||
|
text = a;
|
||||||
|
} else {
|
||||||
|
if (a) {
|
||||||
|
auto p = internal::syntax::make_parser(a, a->lines + 1, lang);
|
||||||
|
auto cancel_buf = new internal::buffer::ReadonlyBuffer("cancel", a, p);
|
||||||
|
internal::syntax::release(p);
|
||||||
|
buffers["cancel"] = cancel_buf;
|
||||||
|
cancel_buf->useless = false;
|
||||||
|
internal::vase::Shard::release(a);
|
||||||
|
}
|
||||||
|
throw ed_error("Operation cancelled.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (c.function->handle)
|
||||||
|
c.function->handle(*this, address, text, c.argument, nullptr);
|
||||||
|
if (c.suffix)
|
||||||
|
c.suffix->handle(*this);
|
||||||
|
if (c.temp_address)
|
||||||
|
temporary_current = false;
|
||||||
|
for (auto it = buffers.begin(); it != buffers.end();) {
|
||||||
|
internal::buffer::Buffer *buf = it->second;
|
||||||
|
if (buf->waste()) {
|
||||||
|
delete buf;
|
||||||
|
it = buffers.erase(it);
|
||||||
|
} else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace bed
|
||||||
-180
@@ -2,75 +2,6 @@
|
|||||||
#include "internal/parser/parser.h"
|
#include "internal/parser/parser.h"
|
||||||
|
|
||||||
namespace bed {
|
namespace bed {
|
||||||
BEd::BEd(std::vector<std::string> args)
|
|
||||||
: theme(internal::theme::Theme::default_theme()), io(*this) {
|
|
||||||
std::string prompt_ = "";
|
|
||||||
std::string file = "";
|
|
||||||
bool suppress = false;
|
|
||||||
bool color = true;
|
|
||||||
for (size_t i = 1; i < args.size(); i++) {
|
|
||||||
if (args[i] == "-p") {
|
|
||||||
i++;
|
|
||||||
if (i >= args.size())
|
|
||||||
throw fatal_error("Prompt not specified!", 1);
|
|
||||||
prompt_ = args[i];
|
|
||||||
} else if (args[i] == "-s") {
|
|
||||||
suppress = true;
|
|
||||||
} else if (args[i] == "--no-color") {
|
|
||||||
color = false;
|
|
||||||
} else if (args[i] == "-v" || args[i] == "--verbose") {
|
|
||||||
help_mode = true;
|
|
||||||
} else if (args[i] == "-h" || args[i] == "--help") {
|
|
||||||
print_help();
|
|
||||||
throw fatal_error("", 0);
|
|
||||||
} else {
|
|
||||||
if (file.size())
|
|
||||||
throw fatal_error("Invalid arguments given.", 1);
|
|
||||||
file = args[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (prompt_ != "")
|
|
||||||
prompt = [p = std::move(prompt_)](BEd &) { return p; };
|
|
||||||
else
|
|
||||||
prompt_mode = false;
|
|
||||||
suppress_mode = suppress;
|
|
||||||
const char *no_color = getenv("NO_COLOR");
|
|
||||||
if (no_color && *no_color != '\0')
|
|
||||||
color = false;
|
|
||||||
const char *colorterm = getenv("COLORTERM");
|
|
||||||
if (colorterm
|
|
||||||
&& strcmp(colorterm, "truecolor") != 0
|
|
||||||
&& strcmp(colorterm, "24bit") != 0)
|
|
||||||
color = false;
|
|
||||||
color_mode = color;
|
|
||||||
internal::functions::Function::register_posix(*this);
|
|
||||||
internal::functions::Function::register_extented(*this);
|
|
||||||
internal::functions::Suffix::register_suffixes(*this);
|
|
||||||
languages["ruby"] = new internal::syntax::Language(internal::syntax::ruby::lang_ruby());
|
|
||||||
buffers["clip"] = new internal::buffer::ClipBuffer("clip");
|
|
||||||
current() = {"default", 0};
|
|
||||||
try {
|
|
||||||
if (file != "")
|
|
||||||
handle(":default:E " + file, false);
|
|
||||||
} catch (ed_error &e) {
|
|
||||||
io.write_line("?");
|
|
||||||
if (help_mode)
|
|
||||||
io.write_line(e.what());
|
|
||||||
last_help = e.what();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BEd::~BEd() {
|
|
||||||
for (auto &[_, buffer] : buffers)
|
|
||||||
delete buffer;
|
|
||||||
for (auto &[_, lang] : languages)
|
|
||||||
delete lang;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BEd::print_help() {
|
|
||||||
io.write("BEd - A line editor.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void BEd::run() {
|
void BEd::run() {
|
||||||
while (true) {
|
while (true) {
|
||||||
internal::ui::CommandIO command(*this);
|
internal::ui::CommandIO command(*this);
|
||||||
@@ -88,117 +19,6 @@ void BEd::run() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BEd::handle(std::string_view cmd, bool eof) {
|
|
||||||
if (eof && cmd.empty()) {
|
|
||||||
eof_op.handle(*this, "", nullptr, std::monostate(), nullptr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
internal::parser::Command c = internal::parser::Parser::get_command(cmd, *this);
|
|
||||||
if (c.temp_address) {
|
|
||||||
marks.get(251) = marks.get(250);
|
|
||||||
prev_2 = prev_1;
|
|
||||||
temporary_current = true;
|
|
||||||
}
|
|
||||||
internal::buffer::Address address;
|
|
||||||
switch (c.function->address_kind) {
|
|
||||||
case internal::functions::Function::AddressKind::None: {
|
|
||||||
auto a = internal::parser::AddressPromise::get_line(*this, c.addresses);
|
|
||||||
if (!a.has_value()) {
|
|
||||||
auto vec = internal::parser::Parser::get_addresses(c.function->default_address, *this);
|
|
||||||
a = internal::parser::AddressPromise::get_line(*this, vec);
|
|
||||||
if (!a.has_value())
|
|
||||||
a = current();
|
|
||||||
}
|
|
||||||
address = a->buffername;
|
|
||||||
} break;
|
|
||||||
case internal::functions::Function::AddressKind::Line: {
|
|
||||||
auto a = internal::parser::AddressPromise::get_line(*this, c.addresses);
|
|
||||||
if (!a.has_value()) {
|
|
||||||
auto vec = internal::parser::Parser::get_addresses(c.function->default_address, *this);
|
|
||||||
a = internal::parser::AddressPromise::get_line(*this, vec);
|
|
||||||
if (!a.has_value())
|
|
||||||
a = current();
|
|
||||||
}
|
|
||||||
address = *a;
|
|
||||||
} break;
|
|
||||||
case internal::functions::Function::AddressKind::Range: {
|
|
||||||
auto a = internal::parser::AddressPromise::get_range(*this, c.addresses);
|
|
||||||
if (!a.has_value()) {
|
|
||||||
auto vec = internal::parser::Parser::get_addresses(c.function->default_address, *this);
|
|
||||||
a = internal::parser::AddressPromise::get_range(*this, vec);
|
|
||||||
if (!a.has_value())
|
|
||||||
a = internal::buffer::Range(current(), current());
|
|
||||||
}
|
|
||||||
address = *a;
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
if (std::holds_alternative<internal::buffer::Line>(c.argument)) {
|
|
||||||
if (c.argument_addresses.empty())
|
|
||||||
throw ed_error("Function needs address argument.");
|
|
||||||
auto a = internal::parser::AddressPromise::get_line(*this, c.argument_addresses);
|
|
||||||
if (a.has_value())
|
|
||||||
c.argument = *a;
|
|
||||||
else
|
|
||||||
c.argument = current();
|
|
||||||
} else if (std::holds_alternative<internal::buffer::Range>(c.argument)) {
|
|
||||||
if (c.argument_addresses.empty())
|
|
||||||
throw ed_error("Function needs address argument.");
|
|
||||||
auto a = internal::parser::AddressPromise::get_range(*this, c.argument_addresses);
|
|
||||||
if (a.has_value())
|
|
||||||
c.argument = *a;
|
|
||||||
else
|
|
||||||
c.argument = internal::buffer::Range(current(), current());
|
|
||||||
}
|
|
||||||
if (!c.function->accept_zero) {
|
|
||||||
if (std::holds_alternative<internal::buffer::Line>(address)) {
|
|
||||||
if (std::get<internal::buffer::Line>(address).number == 0)
|
|
||||||
throw ed_error("Line number can't be zero.");
|
|
||||||
} else if (std::holds_alternative<internal::buffer::Range>(address)) {
|
|
||||||
auto r = std::get<internal::buffer::Range>(address);
|
|
||||||
if (r.start == 0 || r.end == 0)
|
|
||||||
throw ed_error("Line number can't be zero.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
internal::vase::Shard *text = nullptr;
|
|
||||||
if (c.function->input_mode == internal::functions::Function::InputMode::Text) {
|
|
||||||
internal::vase::Shard *vase = nullptr;
|
|
||||||
internal::syntax::Language *lang = nullptr;
|
|
||||||
void *state = nullptr;
|
|
||||||
if (c.function->pre_text_mode)
|
|
||||||
std::tie(vase, lang, state) = c.function->pre_text_mode(*this, address, c.argument);
|
|
||||||
internal::ui::text_mode::TextMode tm(*this, vase, lang, state);
|
|
||||||
auto [a, b] = tm.run();
|
|
||||||
if (!b) {
|
|
||||||
text = a;
|
|
||||||
} else {
|
|
||||||
if (a) {
|
|
||||||
auto p = internal::syntax::make_parser(a, a->lines + 1, lang);
|
|
||||||
auto cancel_buf = new internal::buffer::ReadonlyBuffer("cancel", a, p);
|
|
||||||
internal::syntax::release(p);
|
|
||||||
buffers["cancel"] = cancel_buf;
|
|
||||||
cancel_buf->useless = false;
|
|
||||||
internal::vase::Shard::release(a);
|
|
||||||
}
|
|
||||||
throw ed_error("Operation cancelled.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (c.function->handle)
|
|
||||||
c.function->handle(*this, address, text, c.argument, nullptr);
|
|
||||||
if (c.suffix)
|
|
||||||
c.suffix->handle(*this);
|
|
||||||
if (c.temp_address)
|
|
||||||
temporary_current = false;
|
|
||||||
for (auto it = buffers.begin(); it != buffers.end();) {
|
|
||||||
internal::buffer::Buffer *buf = it->second;
|
|
||||||
if (buf->waste()) {
|
|
||||||
delete buf;
|
|
||||||
it = buffers.erase(it);
|
|
||||||
} else {
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal::buffer::Buffer &BEd::buffer(const std::string &name) {
|
internal::buffer::Buffer &BEd::buffer(const std::string &name) {
|
||||||
if (name.empty())
|
if (name.empty())
|
||||||
throw ed_error("Can't have empty buffer name");
|
throw ed_error("Can't have empty buffer name");
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
#include "bed.h"
|
#include "bed.h"
|
||||||
|
|
||||||
namespace bed::internal::ui::text_mode {
|
namespace bed::internal::ui::text_mode {
|
||||||
|
// TODO: make this into a proper layout engine, in order to avoid so many expensive calculations repeatedly.
|
||||||
|
|
||||||
template <typename F>
|
template <typename F>
|
||||||
static void for_each_cluster(std::string_view s, F &&f) {
|
static void for_each_cluster(std::string_view s, F &&f) {
|
||||||
size_t cluster_start = 0;
|
size_t cluster_start = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user