Compare commits

...
2 Commits
Author SHA1 Message Date
syedm bea8ff18c0 Add marks and regex addressing systems
- Hook up parser to buffer edits.
- Other minor fixes.
2026-08-22 15:01:48 +01:00
syedm 2a903f761a Minor fixes in address resolving. 2026-08-21 21:57:43 +01:00
15 changed files with 373 additions and 83 deletions
+1
View File
@@ -31,5 +31,6 @@ struct BEd {
~BEd(); ~BEd();
void handle(std::string_view cmd, bool eof); void handle(std::string_view cmd, bool eof);
void run(); void run();
void suffix_handle(char s);
}; };
} // namespace bed } // namespace bed
+1 -8
View File
@@ -41,17 +41,11 @@ struct Address {
char m; char m;
}; };
struct RegexLine { // /re/ or ?re? struct Regex { // /re/ or ?re?
internal::Direction dir; internal::Direction dir;
std::string re; std::string re;
}; };
// BEd Extended types of addressing.
struct Regex { // &/re/ or &?re?
internal::Direction dir; // returns next/previous line containing the regex
std::string re; // (not only if it matches full line)
};
struct Diagnostic { // #n# for diagnostic number n. (From lsp.) struct Diagnostic { // #n# for diagnostic number n. (From lsp.)
uint16_t n; uint16_t n;
}; };
@@ -91,7 +85,6 @@ struct Address {
Last, Last,
Number, Number,
Mark, Mark,
RegexLine,
Regex, Regex,
Diagnostic, Diagnostic,
DiagnosticNext, DiagnosticNext,
+1
View File
@@ -34,6 +34,7 @@ struct Buffer {
void remove(uint64_t start_line, uint64_t end_line); void remove(uint64_t start_line, uint64_t end_line);
void append(std::string text, uint64_t line); void append(std::string text, uint64_t line);
void print(BEd &ctx, uint64_t start_line, uint64_t end_line); void print(BEd &ctx, uint64_t start_line, uint64_t end_line);
void number_print(BEd &ctx, uint64_t start_line, uint64_t end_line);
std::string list_string(std::string_view s); std::string list_string(std::string_view s);
}; };
} // namespace bed::internal::buffer } // namespace bed::internal::buffer
+51 -1
View File
@@ -3,5 +3,55 @@
#include "pch.h" #include "pch.h"
namespace bed::internal::marks { namespace bed::internal::marks {
struct MarksEngine {}; struct MarksEngine {
uint64_t marks[1 << UINT8_WIDTH]{UINT64_MAX};
MarksEngine() {
for (auto &m : marks)
m = UINT64_MAX;
}
uint64_t get(uint8_t m) {
return marks[m];
}
void set(uint8_t m, uint64_t line) {
marks[m] = line;
}
void insert(uint64_t start, uint64_t count) {
for (uint16_t i = 0; i <= UINT8_MAX; ++i) {
if (marks[i] == UINT64_MAX)
continue;
if (marks[i] >= start)
marks[i] += count;
}
}
void erase(uint64_t start, uint64_t count) {
for (uint16_t i = 0; i <= UINT8_MAX; ++i) {
if (marks[i] == UINT64_MAX)
continue;
if (marks[i] >= start) {
if (marks[i] < start + count)
marks[i] = UINT64_MAX;
else
marks[i] -= count;
}
}
}
void collapse(uint64_t start, uint64_t count) {
for (uint16_t i = 0; i <= UINT8_MAX; ++i) {
if (marks[i] == UINT64_MAX)
continue;
if (marks[i] >= start) {
if (marks[i] < start + count)
marks[i] = start;
else
marks[i] -= count;
}
}
}
};
} // namespace bed::internal::marks } // namespace bed::internal::marks
+2 -21
View File
@@ -69,17 +69,8 @@ struct Token {
}; };
struct ParseEvent { struct ParseEvent {
std::string_view name; uint8_t closing;
enum T : uint8_t { ParseEvent(uint8_t t) : closing(t) {}
Opening,
Closing,
SymbolDef,
Symbol
} ev_type;
uint8_t type; // type.
ParseEvent(T t) : ev_type(t) {}
ParseEvent(T e_t, std::string_view s, uint8_t type) : name(s), ev_type(e_t), type(type) {}
}; };
struct Language { struct Language {
@@ -90,16 +81,6 @@ struct Language {
std::function<void(void *)> destroy; std::function<void(void *)> destroy;
}; };
struct Symbol {
uint32_t definition;
uint16_t reference_count;
uint8_t type;
uint8_t len;
// first chars of count len, padded to 4 bytes.
// then a set of references. 32bit
// references later as modifying at end is faster than shifting the name.
};
struct ParseState { struct ParseState {
static constexpr uint64_t BRANCH_BIT = 1ull << 63; static constexpr uint64_t BRANCH_BIT = 1ull << 63;
static constexpr uint64_t LINES_MASK = ~BRANCH_BIT; static constexpr uint64_t LINES_MASK = ~BRANCH_BIT;
-9
View File
@@ -5,15 +5,6 @@
#include "tries.h" #include "tries.h"
namespace bed::internal::syntax::ruby { namespace bed::internal::syntax::ruby {
enum struct ScopeTypes : uint8_t {
None,
Comment,
Method,
Class,
Module,
Block
};
struct alignas(2) RubyState { struct alignas(2) RubyState {
struct RubyInternalState { struct RubyInternalState {
uint16_t brace_level; uint16_t brace_level;
+4
View File
@@ -3,6 +3,7 @@
#include "buffer/append.h" #include "buffer/append.h"
#include "buffer/original.h" #include "buffer/original.h"
#include "constants.h" #include "constants.h"
#include "definitions.h"
#include "iterators/line.h" #include "iterators/line.h"
#include "pch.h" #include "pch.h"
#include "shard.h" #include "shard.h"
@@ -92,6 +93,9 @@ struct Vase {
std::string_view pattern, Range range, std::string_view options std::string_view pattern, Range range, std::string_view options
); );
uint64_t find_next(std::string_view pattern, uint64_t start);
uint64_t find_prev(std::string_view pattern, uint64_t start);
bool undo(); bool undo();
bool redo(); bool redo();
void snapshot(); void snapshot();
+5
View File
@@ -94,4 +94,9 @@ void BEd::handle(std::string_view cmd_, bool eof) {
suffix->handle(*this); suffix->handle(*this);
return; return;
} }
void BEd::suffix_handle(char s) {
if (suffixes[s - 'a'].has_value())
suffixes[s - 'a'].value().handle(*this);
}
} // namespace bed } // namespace bed
+9 -4
View File
@@ -29,11 +29,12 @@ Address::Address(std::string &cmd, uint64_t &i) {
break; break;
case '\'': { case '\'': {
i++; i++;
if (i < cmd.size() && 'a' <= cmd[i] && cmd[i] <= 'z') if (i < cmd.size()
&& (('a' <= cmd[i] && cmd[i] <= 'z') || ('A' <= cmd[i] && cmd[i] <= 'Z')))
i++; i++;
else else
throw address_error("Invalid mark."); throw address_error("Invalid mark.");
base = Mark(cmd[i]); base = Mark(cmd[i - 1]);
} break; } break;
case '/': { case '/': {
i++; i++;
@@ -54,7 +55,9 @@ Address::Address(std::string &cmd, uint64_t &i) {
else else
i++; i++;
} }
base = RegexLine(Direction::Forward, cmd.substr(start, i - start)); base = Regex(Direction::Forward, cmd.substr(start, i - start));
if (i < cmd.size())
i++;
} break; } break;
case '?': { case '?': {
i++; i++;
@@ -75,7 +78,9 @@ Address::Address(std::string &cmd, uint64_t &i) {
else else
i++; i++;
} }
base = RegexLine(Direction::Backward, cmd.substr(start, i - start)); base = Regex(Direction::Backward, cmd.substr(start, i - start));
if (i < cmd.size())
i++;
} break; } break;
case '+': { case '+': {
base = Current(); base = Current();
+30 -9
View File
@@ -17,24 +17,45 @@ uint64_t Address::resolve(BEd &ctx) {
line = ctx.active->vase.lines(); line = ctx.active->vase.lines();
} else if constexpr (std::is_same_v<T, Number>) { } else if constexpr (std::is_same_v<T, Number>) {
line = addr.i; line = addr.i;
} else if constexpr (std::is_same_v<T, Mark>) {
line = ctx.active->marks.get(addr.m);
if (line == UINT64_MAX)
throw address_error("Mark not set.");
} else if constexpr (std::is_same_v<T, Regex>) {
std::string_view re = addr.re;
if (re.size() == 0)
re = ctx.last_regex;
if (re.size() == 0)
throw address_error("No regex given.");
if (addr.dir == Direction::Forward)
line = ctx.active->vase.find_next(re, ctx.active->line - 1) + 1;
else
line = ctx.active->vase.find_prev(re, ctx.active->line - 1) + 1;
ctx.last_regex = re;
} else if constexpr (std::is_same_v<T, Block>) { } else if constexpr (std::is_same_v<T, Block>) {
uint64_t current_line = ctx.active->line;
if (ctx.active->vase.lines() > 0 && current_line == 0)
current_line = 1;
if (addr.dir == Direction::Forward) { if (addr.dir == Direction::Forward) {
if (ctx.active->parser) { if (ctx.active->parser) {
if (ctx.active->line == 0) uint64_t closing = ctx.active->parser->next_closing(current_line - 1);
ctx.active->line = 1; if (closing == UINT64_MAX)
line = ctx.active->parser->next_closing(ctx.active->line - 1) + 1; line = ctx.active->vase.lines();
else
line = closing + 1;
} else {
line = current_line + 10;
if (line > ctx.active->vase.lines()) if (line > ctx.active->vase.lines())
line = ctx.active->vase.lines(); line = ctx.active->vase.lines();
} else {
line = ctx.active->line + 10;
} }
} else { } else {
if (ctx.active->parser) { if (ctx.active->parser) {
if (ctx.active->line == 0) line = ctx.active->parser->prev_opening(current_line - 1) + 1;
ctx.active->line = 1;
line = ctx.active->parser->prev_opening(ctx.active->line - 1) + 1;
} else { } else {
line = ctx.active->line - 10; if (current_line > 10)
line = current_line - 10;
else
line = 0;
} }
} }
} else { } else {
+55 -2
View File
@@ -64,8 +64,6 @@ void Buffer::jump(uint64_t n_line) {
if (n_line > vase.lines()) if (n_line > vase.lines())
throw ed_error("Line number too high."); throw ed_error("Line number too high.");
line = n_line; line = n_line;
prev_range.start = line;
prev_range.end = line;
} }
void Buffer::append(std::string text, uint64_t line) { void Buffer::append(std::string text, uint64_t line) {
@@ -82,6 +80,9 @@ void Buffer::append(std::string text, uint64_t line) {
prev_range.start = p.row + 1; prev_range.start = p.row + 1;
vase.insert(&p, text); vase.insert(&p, text);
prev_range.end = p.row + 1; prev_range.end = p.row + 1;
marks.insert(prev_range.start, prev_range.end);
if (parser)
parser->insert(vase, prev_range.start, prev_range.end);
modified = true; modified = true;
} }
@@ -89,6 +90,9 @@ void Buffer::remove(uint64_t start_line, uint64_t end_line) {
vase.erase({{start_line - 1, 0}, {end_line, 0}}); vase.erase({{start_line - 1, 0}, {end_line, 0}});
prev_range.start = start_line; prev_range.start = start_line;
prev_range.end = start_line; prev_range.end = start_line;
marks.erase(start_line, end_line - start_line + 1);
if (parser)
parser->erase(vase, start_line, end_line - start_line + 1);
modified = true; modified = true;
} }
@@ -96,6 +100,9 @@ void Buffer::join(uint64_t start_line, uint64_t end_line) {
vase.regex_search_replace(R"(\n)", {{start_line - 1, 0}, {end_line, 0}}, "", "g"); vase.regex_search_replace(R"(\n)", {{start_line - 1, 0}, {end_line, 0}}, "", "g");
prev_range.start = start_line; prev_range.start = start_line;
prev_range.end = start_line; prev_range.end = start_line;
marks.collapse(start_line, end_line - start_line);
if (parser)
parser->erase(vase, start_line, end_line - start_line);
modified = true; modified = true;
} }
@@ -132,6 +139,8 @@ inline void reset(std::ostream &out) {
} }
void Buffer::print(BEd &ctx, uint64_t start_line, uint64_t end_line) { void Buffer::print(BEd &ctx, uint64_t start_line, uint64_t end_line) {
prev_range.start = start_line;
prev_range.end = end_line;
if (parser) { if (parser) {
std::optional<syntax::Parser::Iterator> it_o = parser->get_hl(vase, start_line - 1); std::optional<syntax::Parser::Iterator> it_o = parser->get_hl(vase, start_line - 1);
auto &it = *it_o; auto &it = *it_o;
@@ -169,8 +178,52 @@ void Buffer::print(BEd &ctx, uint64_t start_line, uint64_t end_line) {
while (it.next() && start_line++ <= end_line) while (it.next() && start_line++ <= end_line)
std::cout << it.line << std::endl; std::cout << it.line << std::endl;
} }
}
void Buffer::number_print(BEd &ctx, uint64_t start_line, uint64_t end_line) {
prev_range.start = start_line; prev_range.start = start_line;
prev_range.end = end_line; prev_range.end = end_line;
uint8_t width = 1;
for (uint64_t n = end_line; n >= 10; n /= 10)
++width;
if (parser) {
std::optional<syntax::Parser::Iterator> it_o = parser->get_hl(vase, start_line - 1);
auto &it = *it_o;
while (start_line <= end_line) {
it.next();
std::cout << std::setw(width) << it.at << "\t";
const std::string &line = it.it->line;
const auto &tokens = it.tokens;
uint32_t cursor = 0;
for (const auto &token : tokens) {
const uint32_t start = token.start;
const uint32_t end = token.end;
if (start > line.size())
break;
if (end > line.size())
break;
if (cursor < start) {
std::cout.write(
line.data() + cursor,
start - cursor
);
}
const auto highlight = ctx.theme.get(token);
apply(std::cout, highlight);
std::cout.write(line.data() + start, end - start);
reset(std::cout);
cursor = end;
}
if (cursor < line.size())
std::cout.write(line.data() + cursor, line.size() - cursor);
std::cout << std::endl;
++start_line;
}
} else {
vase::Iterator it = vase.iterate(start_line - 1, Direction::Forward);
while (it.next() && start_line <= end_line)
std::cout << std::setw(width) << start_line++ << "\t" << it.line << std::endl;
}
} }
std::string Buffer::list_string(std::string_view s) { std::string Buffer::list_string(std::string_view s) {
+78 -9
View File
@@ -9,6 +9,15 @@ void Suffix::register_suffixes(BEd &ctx) {
.handle = [](BEd &ctx) { .handle = [](BEd &ctx) {
auto line = ctx.active->line; auto line = ctx.active->line;
ctx.active->print(ctx, line, line); ctx.active->print(ctx, line, line);
ctx.active->jump(line);
}
};
ctx.suffixes['n' - 'a'] = Suffix{
.desc = "Prints current line with line number.",
.handle = [](BEd &ctx) {
auto line = ctx.active->line;
ctx.active->number_print(ctx, line, line);
ctx.active->jump(line);
} }
}; };
} }
@@ -55,6 +64,26 @@ void Command::register_posix(BEd &ctx) {
} }
} }
); );
ctx.commands.insert(
"j",
Command{
.address_mode = Command::AddressMode::Range,
.suffix = Command::SuffixKind::Suffix,
.desc = "Join a set of lines (default: .,.+1)",
.accept_zero = true,
.handle = [](BEd &ctx, std::span<const uint64_t> addresses, std::string_view) {
std::cout << addresses.size() << "\n";
uint64_t start_line = ctx.active->line;
uint64_t end_line = ctx.active->line + 1;
if (addresses.size() == 1)
return;
else if (addresses.size() == 2)
start_line = addresses[0], end_line = addresses[1];
ctx.active->join(start_line, end_line);
ctx.active->jump(start_line);
}
}
);
ctx.commands.insert( ctx.commands.insert(
"q", "q",
Command{ Command{
@@ -92,27 +121,67 @@ void Command::register_posix(BEd &ctx) {
.handle = [](BEd &ctx, std::span<const uint64_t> addresses, std::string_view) { .handle = [](BEd &ctx, std::span<const uint64_t> addresses, std::string_view) {
uint64_t start_line = ctx.active->line; uint64_t start_line = ctx.active->line;
uint64_t end_line = ctx.active->line; uint64_t end_line = ctx.active->line;
if (!addresses.size()) if (addresses.size() == 1)
start_line = addresses[0], end_line = addresses[0];
else if (addresses.size() == 2)
start_line = addresses[0], end_line = addresses[1];
ctx.active->print(ctx, start_line, end_line); ctx.active->print(ctx, start_line, end_line);
else if (addresses.size() == 1) ctx.active->jump(end_line);
ctx.active->print(ctx, addresses[0], addresses[0]); }
else }
ctx.active->print(ctx, addresses[0], addresses[1]); );
ctx.commands.insert(
"n",
Command{
.address_mode = Command::AddressMode::Range,
.suffix = Command::SuffixKind::Suffix,
.desc = "Print range with line numbers (default .,.)",
.accept_zero = false,
.handle = [](BEd &ctx, std::span<const uint64_t> addresses, std::string_view) {
uint64_t start_line = ctx.active->line;
uint64_t end_line = ctx.active->line;
if (addresses.size() == 1)
start_line = addresses[0], end_line = addresses[0];
else if (addresses.size() == 2)
start_line = addresses[0], end_line = addresses[1];
ctx.active->number_print(ctx, start_line, end_line);
ctx.active->jump(end_line);
} }
} }
); );
ctx.commands.insert( ctx.commands.insert(
"=", "=",
Command{ Command{
.address_mode = Command::AddressMode::Single, .address_mode = Command::AddressMode::Range,
.suffix = Command::SuffixKind::Suffix, .suffix = Command::SuffixKind::Suffix,
.desc = "Print line number", .desc = "Print line number(s)",
.accept_zero = false, .accept_zero = true,
.handle = [](BEd &ctx, std::span<const uint64_t> addresses, std::string_view) { .handle = [](BEd &ctx, std::span<const uint64_t> addresses, std::string_view) {
if (!addresses.size()) if (!addresses.size())
std::cout << ctx.active->vase.lines() << std::endl; std::cout << ctx.active->vase.lines() << std::endl;
else else if (addresses.size() == 1)
std::cout << addresses[0] << std::endl; std::cout << addresses[0] << std::endl;
else
std::cout << addresses[0] << "," << addresses[1] << std::endl;
}
}
);
ctx.commands.insert(
"k",
Command{
.address_mode = Command::AddressMode::Single,
.suffix = Command::SuffixKind::Continuation,
.desc = "Mark a line.",
.accept_zero = true,
.handle = [](BEd &ctx, std::span<const uint64_t> addresses, std::string_view args) {
if (args.size() < 1 || args.size() > 2)
throw ed_error("Malformed mark command");
if (addresses.size())
ctx.active->marks.set(args[0], addresses[0]);
else
ctx.active->marks.set(args[0], ctx.active->line);
if (args.size() > 1)
ctx.suffix_handle(args[1]);
} }
} }
); );
+1 -4
View File
@@ -243,15 +243,12 @@ void Parser::modify(vase::Vase &vase, uint64_t target, uint64_t count) {
events.clear(); events.clear();
lang.parse(&state, it.line, at == 0, &tokens, &events); lang.parse(&state, it.line, at == 0, &tokens, &events);
for (const auto &ev : events) { for (const auto &ev : events) {
const auto t = uint8_t(ev.ev_type);
if (t > ParseEvent::Closing)
continue;
if (c.leaf->n == c.leaf->cap) { if (c.leaf->n == c.leaf->cap) {
uint32_t cap = c.leaf->cap ? c.leaf->cap * 2 : 8; uint32_t cap = c.leaf->cap ? c.leaf->cap * 2 : 8;
c.leaf->blocks = (uint16_t *)realloc(c.leaf->blocks, cap * sizeof(uint16_t)); c.leaf->blocks = (uint16_t *)realloc(c.leaf->blocks, cap * sizeof(uint16_t));
c.leaf->cap = cap; c.leaf->cap = cap;
} }
c.leaf->blocks[c.leaf->n++] = t << 15 | (at - chunk_start); c.leaf->blocks[c.leaf->n++] = ev.closing << 15 | (at - chunk_start);
} }
at++; at++;
} }
+15 -14
View File
@@ -225,7 +225,7 @@ bool handle_line_markers(RubyParser &p, std::vector<Token> *tokens, std::vector<
if (p.len() == 6 && p.peek_str(6) == "=begin") { if (p.len() == 6 && p.peek_str(6) == "=begin") {
p.current().state = RubyState::RubyInternalState::COMMENT; p.current().state = RubyState::RubyInternalState::COMMENT;
p.current().flags &= ~RubyState::RubyInternalState::EXPECTING_EXPRESSION; p.current().flags &= ~RubyState::RubyInternalState::EXPECTING_EXPRESSION;
events->push_back(ParseEvent::Opening); events->push_back(false);
tokens->push_back({0, p.len(), Token::Comment}); tokens->push_back({0, p.len(), Token::Comment});
return true; return true;
} }
@@ -266,7 +266,7 @@ bool handle_syntax(RubyParser &p, std::vector<Token> *tokens, std::vector<ParseE
case RubyState::RubyInternalState::CLASS_NAME: { case RubyState::RubyInternalState::CLASS_NAME: {
if (p.peek() == '<' && p.peek(1) == '<') { if (p.peek() == '<' && p.peek(1) == '<') {
p.advance(2); p.advance(2);
events->push_back(ParseEvent::Opening); events->push_back(false);
p.current().flags = (p.current().flags & ~RubyState::RubyInternalState::NAME_MASK); p.current().flags = (p.current().flags & ~RubyState::RubyInternalState::NAME_MASK);
p.current().flags |= RubyState::RubyInternalState::EXPECTING_EXPRESSION; p.current().flags |= RubyState::RubyInternalState::EXPECTING_EXPRESSION;
return false; return false;
@@ -285,7 +285,7 @@ bool handle_syntax(RubyParser &p, std::vector<Token> *tokens, std::vector<ParseE
return false; return false;
} }
} }
events->push_back(ParseEvent::Opening); events->push_back(false);
p.current().flags = (p.current().flags & ~RubyState::RubyInternalState::NAME_MASK); p.current().flags = (p.current().flags & ~RubyState::RubyInternalState::NAME_MASK);
return false; return false;
} }
@@ -311,7 +311,7 @@ bool handle_syntax(RubyParser &p, std::vector<Token> *tokens, std::vector<ParseE
return false; return false;
} }
} }
events->push_back(ParseEvent::Opening); events->push_back(false);
p.current().flags = (p.current().flags & ~RubyState::RubyInternalState::NAME_MASK); p.current().flags = (p.current().flags & ~RubyState::RubyInternalState::NAME_MASK);
return false; return false;
} }
@@ -330,7 +330,7 @@ bool handle_syntax(RubyParser &p, std::vector<Token> *tokens, std::vector<ParseE
return false; return false;
} }
} }
events->push_back(ParseEvent::Opening); events->push_back(false);
p.current().flags = (p.current().flags & ~RubyState::RubyInternalState::NAME_MASK); p.current().flags = (p.current().flags & ~RubyState::RubyInternalState::NAME_MASK);
return false; return false;
} }
@@ -899,21 +899,21 @@ bool handle_syntax(RubyParser &p, std::vector<Token> *tokens, std::vector<ParseE
p.advance(j); p.advance(j);
return false; return false;
} else if (j == tries.expecting_end_keywords_trie.longest_match(p.peek_str(j))) { } else if (j == tries.expecting_end_keywords_trie.longest_match(p.peek_str(j))) {
events->push_back(ParseEvent::Opening); events->push_back(false);
p.current().flags |= RubyState::RubyInternalState::EXPECTING_EXPRESSION; p.current().flags |= RubyState::RubyInternalState::EXPECTING_EXPRESSION;
tokens->push_back({p.i, p.i + j, Token::Keyword}); tokens->push_back({p.i, p.i + j, Token::Keyword});
p.advance(j); p.advance(j);
return false; return false;
} else if (j == tries.conditional_keywords_trie.longest_match(p.peek_str(j))) { } else if (j == tries.conditional_keywords_trie.longest_match(p.peek_str(j))) {
if (p.current().flags & RubyState::RubyInternalState::NEWLINE || p.op_last) if (p.current().flags & RubyState::RubyInternalState::NEWLINE || p.op_last)
events->push_back(ParseEvent::Opening); events->push_back(false);
p.current().flags |= RubyState::RubyInternalState::EXPECTING_EXPRESSION; p.current().flags |= RubyState::RubyInternalState::EXPECTING_EXPRESSION;
tokens->push_back({p.i, p.i + j, Token::Keyword}); tokens->push_back({p.i, p.i + j, Token::Keyword});
p.advance(j); p.advance(j);
return false; return false;
} else if (j == tries.end_keywords_trie.longest_match(p.peek_str(j))) { } else if (j == tries.end_keywords_trie.longest_match(p.peek_str(j))) {
p.current().flags |= RubyState::RubyInternalState::EXPECTING_EXPRESSION; p.current().flags |= RubyState::RubyInternalState::EXPECTING_EXPRESSION;
events->push_back(ParseEvent::Opening); events->push_back(false);
tokens->push_back({p.i, p.i + j, Token::Keyword}); tokens->push_back({p.i, p.i + j, Token::Keyword});
p.advance(j); p.advance(j);
return false; return false;
@@ -950,7 +950,7 @@ bool handle_syntax(RubyParser &p, std::vector<Token> *tokens, std::vector<ParseE
return false; return false;
} }
if (j == 3 && p.peek_str(3) == "end") { if (j == 3 && p.peek_str(3) == "end") {
events->push_back(ParseEvent::Closing); events->push_back(true);
tokens->push_back({p.i, p.i + j, Token::Keyword}); tokens->push_back({p.i, p.i + j, Token::Keyword});
p.advance(3); p.advance(3);
return false; return false;
@@ -980,17 +980,18 @@ bool handle_syntax(RubyParser &p, std::vector<Token> *tokens, std::vector<ParseE
return false; return false;
} }
uint32_t start = p.i; uint32_t start = p.i;
if (p.peek(j) == ':') {
p.advance(j); p.advance(j);
if (p.peek() == ':') {
p.advance(); p.advance();
tokens->push_back({start, p.i, Token::Label}); tokens->push_back({start, p.i, Token::Label});
return false; return false;
} else if (p.peek(-1) == '!' || p.peek(-1) == '?') { } else if (p.peek(j - 1) == '!' || p.peek(j - 1) == '?') {
p.advance(); p.advance(j);
tokens->push_back({start, p.i, Token::Function}); tokens->push_back({start, p.i, Token::Function});
return false; return false;
} else { } else {
uint32_t j = 0; p.advance(j);
j = 0;
if (p.peek(j) == '(' || p.peek(j) == '{') { if (p.peek(j) == '(' || p.peek(j) == '{') {
tokens->push_back({start, p.i, Token::Function}); tokens->push_back({start, p.i, Token::Function});
return false; return false;
@@ -1066,7 +1067,7 @@ void ruby_parse(
tokens->push_back({p.i, p.len(), Token::Comment}); tokens->push_back({p.i, p.len(), Token::Comment});
if (p.i == 0 && p.peek_str(4) == "=end") { if (p.i == 0 && p.peek_str(4) == "=end") {
p.current().state = RubyState::RubyInternalState::NONE; p.current().state = RubyState::RubyInternalState::NONE;
events->push_back(ParseEvent::Closing); events->push_back(true);
} }
return; return;
} }
+118
View File
@@ -156,4 +156,122 @@ std::vector<Range> Vase::regex_search(
result.push_back({point_of(match.start), point_of(match.end)}); result.push_back({point_of(match.start), point_of(match.end)});
return result; return result;
} }
uint64_t Vase::find_next(std::string_view pattern, uint64_t start) {
std::vector<RegexMatch> results;
int errornumber;
PCRE2_SIZE erroroffset;
pcre2_code *re = pcre2_compile(
(PCRE2_SPTR)pattern.data(),
pattern.size(),
PCRE2_UTF | PCRE2_EXTENDED,
&errornumber,
&erroroffset,
NULL
);
if (re == NULL)
throw ed_error("Can't compile regex.");
pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(re, nullptr);
if (!match_data) {
pcre2_code_free(re);
throw ed_error("Can't create regex match data.");
}
uint64_t at = (start + 1) % lines();
LineIterator it(root, at, Direction::Forward);
std::string line;
while (it.next(&line)) {
int rc = pcre2_match(re, (PCRE2_SPTR)line.data(), line.size(), 0, 0, match_data, nullptr);
if (rc >= 0) {
pcre2_match_data_free(match_data);
pcre2_code_free(re);
return at;
}
if (rc != PCRE2_ERROR_NOMATCH) {
pcre2_match_data_free(match_data);
pcre2_code_free(re);
throw ed_error("Regex matching failed.");
}
at++;
}
at = 0;
LineIterator it2(root, at, Direction::Forward);
while (it2.next(&line)) {
if (at >= start)
break;
int rc = pcre2_match(re, (PCRE2_SPTR)line.data(), line.size(), 0, 0, match_data, nullptr);
if (rc >= 0) {
pcre2_match_data_free(match_data);
pcre2_code_free(re);
return at;
}
if (rc != PCRE2_ERROR_NOMATCH) {
pcre2_match_data_free(match_data);
pcre2_code_free(re);
throw ed_error("Regex matching failed.");
}
at++;
}
pcre2_match_data_free(match_data);
pcre2_code_free(re);
throw ed_error("No line matched.");
}
uint64_t Vase::find_prev(std::string_view pattern, uint64_t start) {
std::vector<RegexMatch> results;
int errornumber;
PCRE2_SIZE erroroffset;
pcre2_code *re = pcre2_compile(
(PCRE2_SPTR)pattern.data(),
pattern.size(),
PCRE2_UTF | PCRE2_EXTENDED,
&errornumber,
&erroroffset,
NULL
);
if (re == NULL)
throw ed_error("Can't compile regex.");
pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(re, nullptr);
if (!match_data) {
pcre2_code_free(re);
throw ed_error("Can't create regex match data.");
}
uint64_t at = (start == 0 ? lines() : start) - 1;
LineIterator it(root, at, Direction::Backward);
std::string line;
while (it.next(&line)) {
int rc = pcre2_match(re, (PCRE2_SPTR)line.data(), line.size(), 0, 0, match_data, nullptr);
if (rc >= 0) {
pcre2_match_data_free(match_data);
pcre2_code_free(re);
return at;
}
if (rc != PCRE2_ERROR_NOMATCH) {
pcre2_match_data_free(match_data);
pcre2_code_free(re);
throw ed_error("Regex matching failed.");
}
at--;
}
at = lines();
LineIterator it2(root, at, Direction::Backward);
while (it2.next(&line)) {
if (at <= start)
break;
int rc = pcre2_match(re, (PCRE2_SPTR)line.data(), line.size(), 0, 0, match_data, nullptr);
if (rc >= 0) {
pcre2_match_data_free(match_data);
pcre2_code_free(re);
return at;
}
if (rc != PCRE2_ERROR_NOMATCH) {
pcre2_match_data_free(match_data);
pcre2_code_free(re);
throw ed_error("Regex matching failed.");
}
at--;
}
pcre2_match_data_free(match_data);
pcre2_code_free(re);
throw ed_error("No line matched.");
}
} // namespace bed::internal::vase } // namespace bed::internal::vase