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)