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"
|
||||
|
||||
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() {
|
||||
while (true) {
|
||||
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) {
|
||||
if (name.empty())
|
||||
throw ed_error("Can't have empty buffer name");
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
#include "bed.h"
|
||||
|
||||
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>
|
||||
static void for_each_cluster(std::string_view s, F &&f) {
|
||||
size_t cluster_start = 0;
|
||||
|
||||
Reference in New Issue
Block a user