diff --git a/README.md b/README.md
index e854d69..9881b34 100644
--- a/README.md
+++ b/README.md
@@ -59,4 +59,5 @@ It should support:
### TODO:
- Make "g" command work.
-- properly handle escapes for %q ' etc in ruby parser (rn everything is escapable.)
+- Switch to proper posix style Shard objects (to distinguish 1 empty line from no lines.)
+- Use proper ruby binding context to keep locals across
`
function calls.
diff --git a/include/bed.h b/include/bed.h
index 4c04832..fc5ab9e 100644
--- a/include/bed.h
+++ b/include/bed.h
@@ -20,6 +20,8 @@ struct BEd {
internal::functions::Function eof_op;
std::array, 26> suffixes;
internal::theme::Theme theme;
+ std::unordered_map extention_to_language;
+ std::unordered_map filename_to_language;
std::unordered_map languages;
internal::io::IO io;
internal::vase::AppendStorage append{"/tmp"};
diff --git a/include/internal/buffer/decl.h b/include/internal/buffer/decl.h
index 8438698..bb78a55 100644
--- a/include/internal/buffer/decl.h
+++ b/include/internal/buffer/decl.h
@@ -33,7 +33,7 @@ struct Buffer {
virtual bool waste() = 0;
virtual uint64_t lines() = 0;
virtual uint64_t bytes() = 0;
- virtual void set_filename(std::filesystem::path path) = 0;
+ virtual void set_filename(BEd &ctx, std::filesystem::path path) = 0;
virtual std::filesystem::path filename() = 0;
virtual void saved_hook() = 0;
virtual void load(BEd &ctx, vase::Shard *text) = 0;
diff --git a/include/internal/buffer/types/clip.h b/include/internal/buffer/types/clip.h
index 361f841..4785c38 100644
--- a/include/internal/buffer/types/clip.h
+++ b/include/internal/buffer/types/clip.h
@@ -14,7 +14,7 @@ struct ClipBuffer : Buffer {
uint64_t lines() override;
uint64_t bytes() override;
void load(BEd &ctx, vase::Shard *text) override;
- void set_filename(std::filesystem::path path) override;
+ void set_filename(BEd &ctx, std::filesystem::path path) override;
std::filesystem::path filename() override;
vase::Shard *copy(uint64_t start_line, uint64_t end_line) override;
void substitute(
diff --git a/include/internal/buffer/types/generic.h b/include/internal/buffer/types/generic.h
index 4d43247..95fcb33 100644
--- a/include/internal/buffer/types/generic.h
+++ b/include/internal/buffer/types/generic.h
@@ -34,7 +34,7 @@ struct GenericBuffer : ShardBuffer {
void saved_hook() override;
bool waste() override;
void load(BEd &ctx, vase::Shard *text) override;
- void set_filename(std::filesystem::path path) override;
+ void set_filename(BEd &ctx, std::filesystem::path path) override;
std::filesystem::path filename() override;
void substitute(
BEd &ctx, uint64_t start_line, uint64_t end_line,
diff --git a/include/internal/buffer/types/readonly.h b/include/internal/buffer/types/readonly.h
index f9b52fd..2c8429b 100644
--- a/include/internal/buffer/types/readonly.h
+++ b/include/internal/buffer/types/readonly.h
@@ -19,7 +19,7 @@ struct ReadonlyBuffer : ShardBuffer {
void load(BEd &, vase::Shard *) override {
throw ed_error("This buffer is read-only.");
}
- void set_filename(std::filesystem::path) override {}
+ void set_filename(BEd &, std::filesystem::path) override {}
std::filesystem::path filename() override {
return {};
}
diff --git a/include/internal/vase/shard.h b/include/internal/vase/shard.h
index 7c297eb..db5eb65 100644
--- a/include/internal/vase/shard.h
+++ b/include/internal/vase/shard.h
@@ -6,6 +6,9 @@
#include "storage/storage.h"
namespace bed::internal::vase {
+// TODO: rewrite with invariant, text ends with a newline, as right now both 1 real and empty line and no text mean teh same thing,
+// which causes a ton of issues.
+
struct Shard {
enum struct Kind : uint8_t {
Branch,
diff --git a/src/bed/bed.cc b/src/bed/bed.cc
index 3995e8b..9f92f89 100644
--- a/src/bed/bed.cc
+++ b/src/bed/bed.cc
@@ -47,7 +47,14 @@ BEd::BEd(std::vector args)
internal::functions::Suffix::register_suffixes(*this);
internal::scripting::register_basic(*this);
languages["ruby"] = new internal::syntax::Language(internal::syntax::ruby::lang_ruby());
+ extention_to_language[".rb"] = "ruby";
languages["c"] = new internal::syntax::Language(internal::syntax::c::lang_c());
+ extention_to_language[".h"] = "c";
+ extention_to_language[".hh"] = "c";
+ extention_to_language[".h++"] = "c";
+ extention_to_language[".c"] = "c";
+ extention_to_language[".cc"] = "c";
+ extention_to_language[".c++"] = "c";
buffers["clip"] = new internal::buffer::ClipBuffer("clip");
current() = {"default", 0};
try {
diff --git a/src/internal/buffer/generic.cc b/src/internal/buffer/generic.cc
index a0c035c..8bfde6f 100644
--- a/src/internal/buffer/generic.cc
+++ b/src/internal/buffer/generic.cc
@@ -249,11 +249,17 @@ void GenericBuffer::load(BEd &ctx, vase::Shard *text) {
ctx.prev().end = text->lines + 1;
}
ctx.current() = {name, lines()};
+ syntax::Language *lang = parse.lang;
syntax::release(parse);
- parse = syntax::make_parser(root, lines(), nullptr);
+ if (save_path.has_extension()) {
+ auto it = ctx.extention_to_language.find(save_path.extension().string());
+ if (it != ctx.extention_to_language.end())
+ lang = ctx.languages[it->second];
+ }
+ parse = syntax::make_parser(root, lines(), lang);
}
-void GenericBuffer::set_filename(std::filesystem::path path) {
+void GenericBuffer::set_filename(BEd &, std::filesystem::path path) {
save_path = path;
}
diff --git a/src/internal/buffer/special/clip.cc b/src/internal/buffer/special/clip.cc
index 670be23..60c645e 100644
--- a/src/internal/buffer/special/clip.cc
+++ b/src/internal/buffer/special/clip.cc
@@ -47,7 +47,7 @@ void ClipBuffer::load(BEd &ctx, vase::Shard *text) {
}
}
-void ClipBuffer::set_filename(std::filesystem::path) {}
+void ClipBuffer::set_filename(BEd &, std::filesystem::path) {}
std::filesystem::path ClipBuffer::filename() {
return "";
diff --git a/src/internal/functions/posix.cc b/src/internal/functions/posix.cc
index 90d0648..8a63fd9 100644
--- a/src/internal/functions/posix.cc
+++ b/src/internal/functions/posix.cc
@@ -145,7 +145,7 @@ void Function::register_posix(BEd &ctx) {
if (std::holds_alternative(arg)) {
auto path = std::get(arg);
s = vase::Shard::from_file(path);
- buf.set_filename(path);
+ buf.set_filename(ctx, path);
} else if (std::holds_alternative(arg)) {
auto cmd = std::get(arg).cmd;
ctx.escape_command(cmd, buf.filename().string());
@@ -191,7 +191,7 @@ void Function::register_posix(BEd &ctx) {
if (std::holds_alternative(arg)) {
auto path = std::get(arg);
s = vase::Shard::from_file(path);
- buf.set_filename(path);
+ buf.set_filename(ctx, path);
} else if (std::holds_alternative(arg)) {
auto cmd = std::get(arg).cmd;
ctx.escape_command(cmd, buf.filename().string());
@@ -234,7 +234,7 @@ void Function::register_posix(BEd &ctx) {
auto &addr = std::get(addr_);
auto &buf = ctx.buffer(addr);
if (std::holds_alternative(arg))
- buf.set_filename(std::get(arg));
+ buf.set_filename(ctx, std::get(arg));
else if (std::holds_alternative(arg))
throw ed_error("Can't save shell command as save path.");
if (buf.filename().empty())
@@ -590,7 +590,7 @@ void Function::register_posix(BEd &ctx) {
auto path = std::get(arg);
s = vase::Shard::from_file(path);
if (buf.filename().empty())
- buf.set_filename(path);
+ buf.set_filename(ctx, path);
} else if (std::holds_alternative(arg)) {
auto cmd = std::get(arg).cmd;
ctx.escape_command(cmd, buf.filename().string());
@@ -740,7 +740,7 @@ void Function::register_posix(BEd &ctx) {
if (std::holds_alternative(arg)) {
auto path = std::get(arg);
vase::write_file(path, text);
- buf.set_filename(path);
+ buf.set_filename(ctx, path);
} else if (std::holds_alternative(arg)) {
auto cmd = std::get(arg).cmd;
ctx.escape_command(cmd, buf.filename().string());
diff --git a/src/internal/syntax/c/parse.cc b/src/internal/syntax/c/parse.cc
index e27de8d..fa91bf1 100644
--- a/src/internal/syntax/c/parse.cc
+++ b/src/internal/syntax/c/parse.cc
@@ -106,6 +106,197 @@ void handle_string(CParser &p, std::vector *tokens, bool string) {
}
}
+void handle_number(CParser &p, std::vector *tokens) {
+ bool integer = true;
+ uint32_t start = p.i;
+ if (p.peek() == '0') {
+ p.advance();
+ if (p.peek() == 'x' || p.peek() == 'X') {
+ p.advance();
+ if (!(is_hex(p.peek()) || p.peek() == '.'))
+ return;
+ while (is_hex(p.peek())) {
+ p.advance();
+ if (p.peek() == '\'') {
+ p.advance();
+ if (!(is_hex(p.peek())))
+ return;
+ }
+ }
+ bool need_p = false;
+ if (p.peek() == '.') {
+ need_p = true;
+ p.advance();
+ }
+ while (is_hex(p.peek())) {
+ p.advance();
+ if (p.peek() == '\'') {
+ p.advance();
+ if (!(is_hex(p.peek())))
+ return;
+ }
+ }
+ if (p.peek() == 'p' || p.peek() == 'P') {
+ integer = false;
+ p.advance();
+ if (p.peek() == '-' || p.peek() == '+')
+ p.advance();
+ if (!('0' <= p.peek() && p.peek() <= '9'))
+ return;
+ p.advance();
+ while ('0' <= p.peek() && p.peek() <= '9') {
+ p.advance();
+ if (p.peek() == '\'') {
+ p.advance();
+ if (!('0' <= p.peek() && p.peek() <= '9'))
+ return;
+ }
+ }
+ } else if (need_p) {
+ return;
+ }
+ } else if (p.peek() == 'b' || p.peek() == 'B') {
+ p.advance();
+ if (p.peek() != '0' && p.peek() != '1')
+ return;
+ p.advance();
+ while (p.peek() == '0' || p.peek() == '1') {
+ p.advance();
+ if (p.peek() == '\'') {
+ p.advance();
+ if (!(p.peek() == '0' || p.peek() == '1'))
+ return;
+ }
+ }
+ } else {
+ while ('0' <= p.peek() && p.peek() <= '7') {
+ p.advance();
+ if (p.peek() == '\'') {
+ p.advance();
+ if (!('0' <= p.peek() && p.peek() <= '7'))
+ return;
+ }
+ }
+ if (p.peek() == '.') {
+ integer = false;
+ p.advance();
+ }
+ while ('0' <= p.peek() && p.peek() <= '7') {
+ p.advance();
+ if (p.peek() == '\'') {
+ p.advance();
+ if (!('0' <= p.peek() && p.peek() <= '7'))
+ return;
+ }
+ }
+ if (p.peek() == 'e' || p.peek() == 'E') {
+ integer = false;
+ p.advance();
+ if (p.peek() == '-' || p.peek() == '+')
+ p.advance();
+ if (!('0' <= p.peek() && p.peek() <= '9'))
+ return;
+ p.advance();
+ while ('0' <= p.peek() && p.peek() <= '9') {
+ p.advance();
+ if (p.peek() == '\'') {
+ p.advance();
+ if (!('0' <= p.peek() && p.peek() <= '9'))
+ return;
+ }
+ }
+ }
+ }
+ } else if (p.peek() == '.') {
+ integer = false;
+ p.advance();
+ goto after_decimal;
+ } else {
+ p.advance();
+ while ('0' <= p.peek() && p.peek() <= '9') {
+ p.advance();
+ if (p.peek() == '\'') {
+ p.advance();
+ if (!('0' <= p.peek() && p.peek() <= '9'))
+ return;
+ }
+ }
+ if (p.peek() == '.') {
+ integer = false;
+ p.advance();
+ }
+ after_decimal:
+ while ('0' <= p.peek() && p.peek() <= '9') {
+ p.advance();
+ if (p.peek() == '\'') {
+ p.advance();
+ if (!('0' <= p.peek() && p.peek() <= '9'))
+ return;
+ }
+ }
+ if (p.peek() == 'e' || p.peek() == 'E') {
+ integer = false;
+ p.advance();
+ if (p.peek() == '-' || p.peek() == '+')
+ p.advance();
+ if (!('0' <= p.peek() && p.peek() <= '9'))
+ return;
+ p.advance();
+ while ('0' <= p.peek() && p.peek() <= '9') {
+ p.advance();
+ if (p.peek() == '\'') {
+ p.advance();
+ if (!('0' <= p.peek() && p.peek() <= '9'))
+ return;
+ }
+ }
+ }
+ }
+ if (integer) {
+ if (p.peek() == 'u' || p.peek() == 'U') {
+ p.advance();
+ if (p.peek() == 'w') {
+ p.advance();
+ if (p.peek() != 'b')
+ return;
+ p.advance();
+ }
+ if (p.peek() == 'W') {
+ p.advance();
+ if (p.peek() != 'B')
+ return;
+ p.advance();
+ }
+ if (p.peek() == 'l' || p.peek() == 'L')
+ p.advance();
+ if (p.peek() == 'l' || p.peek() == 'L')
+ p.advance();
+ } else if (p.peek() == 'l' || p.peek() == 'L') {
+ p.advance();
+ if (p.peek() == 'l' || p.peek() == 'L')
+ p.advance();
+ if (p.peek() == 'u' || p.peek() == 'U')
+ p.advance();
+ } else if (p.peek_str(2) == "wb" || p.peek_str(2) == "WB") {
+ p.advance(2);
+ } else if (p.peek() == 'f' || p.peek() == 'F' || p.peek() == 'l' || p.peek() == 'L') {
+ p.advance();
+ } else if ((p.peek() == 'd' || p.peek() == 'D')
+ && (p.peek(1) == 'f' || p.peek(1) == 'F' || p.peek(1) == 'd' || p.peek(1) == 'D' || p.peek(1) == 'l' || p.peek(1) == 'L')) {
+ p.advance(2);
+ }
+ } else {
+ if (p.peek() == 'f' || p.peek() == 'F' || p.peek() == 'l' || p.peek() == 'L')
+ p.advance();
+ else if ((p.peek() == 'd' || p.peek() == 'D')
+ && (p.peek(1) == 'f' || p.peek(1) == 'F' || p.peek(1) == 'd' || p.peek(1) == 'D' || p.peek(1) == 'l' || p.peek(1) == 'L'))
+ p.advance(2);
+ }
+ if (identifier_char(p.peek()) || p.peek() == '.')
+ return;
+ tokens->push_back({start, p.i, io::Token::Number});
+}
+
void handle_syntax(CParser &p, std::vector *tokens, std::vector *events) {
if (p.peek() == '/' && p.peek(1) == '/') {
p.current().state = CState::CInternalState::INLINE_COMMENT;
@@ -165,82 +356,8 @@ void handle_syntax(CParser &p, std::vector *tokens, std::vectorpush_back({start, p.i, io::Token::Number});
+ if (('0' <= p.peek() && p.peek() <= '9') || p.peek() == '.') {
+ handle_number(p, tokens);
return;
}
p.advance();
diff --git a/src/internal/syntax/ruby/parse.cc b/src/internal/syntax/ruby/parse.cc
index ea7433e..66337af 100644
--- a/src/internal/syntax/ruby/parse.cc
+++ b/src/internal/syntax/ruby/parse.cc
@@ -1000,6 +1000,7 @@ bool handle_syntax(RubyParser &p, std::vector *tokens, std::vectorpush_back({p.i, p.i + j, io::Token::Function});
p.advance(j);
+ return false;
}
uint32_t start = p.i;
if (p.peek(j) == ':') {
diff --git a/src/internal/vase/vase.cc b/src/internal/vase/vase.cc
index 397e764..fd7b59c 100644
--- a/src/internal/vase/vase.cc
+++ b/src/internal/vase/vase.cc
@@ -179,7 +179,10 @@ Shard *insert(AppendStorage *ap, Shard *root, Shard *text, uint64_t line) {
if (!root) {
if (line != 0)
throw ed_error("line out of range");
- Shard::retain(text);
+ if (text)
+ Shard::retain(text);
+ else
+ text = newline(ap);
return text;
}
if (line > root->lines + 1)