Compare commits
2
Commits
9680a18e05
...
bea8ff18c0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bea8ff18c0
|
||
|
|
2a903f761a
|
@@ -31,5 +31,6 @@ struct BEd {
|
||||
~BEd();
|
||||
void handle(std::string_view cmd, bool eof);
|
||||
void run();
|
||||
void suffix_handle(char s);
|
||||
};
|
||||
} // namespace bed
|
||||
|
||||
@@ -41,17 +41,11 @@ struct Address {
|
||||
char m;
|
||||
};
|
||||
|
||||
struct RegexLine { // /re/ or ?re?
|
||||
struct Regex { // /re/ or ?re?
|
||||
internal::Direction dir;
|
||||
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.)
|
||||
uint16_t n;
|
||||
};
|
||||
@@ -91,7 +85,6 @@ struct Address {
|
||||
Last,
|
||||
Number,
|
||||
Mark,
|
||||
RegexLine,
|
||||
Regex,
|
||||
Diagnostic,
|
||||
DiagnosticNext,
|
||||
|
||||
@@ -34,6 +34,7 @@ struct Buffer {
|
||||
void remove(uint64_t start_line, uint64_t end_line);
|
||||
void append(std::string text, uint64_t 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);
|
||||
};
|
||||
} // namespace bed::internal::buffer
|
||||
|
||||
@@ -3,5 +3,55 @@
|
||||
#include "pch.h"
|
||||
|
||||
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
|
||||
|
||||
@@ -69,17 +69,8 @@ struct Token {
|
||||
};
|
||||
|
||||
struct ParseEvent {
|
||||
std::string_view name;
|
||||
enum T : uint8_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) {}
|
||||
uint8_t closing;
|
||||
ParseEvent(uint8_t t) : closing(t) {}
|
||||
};
|
||||
|
||||
struct Language {
|
||||
@@ -90,16 +81,6 @@ struct Language {
|
||||
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 {
|
||||
static constexpr uint64_t BRANCH_BIT = 1ull << 63;
|
||||
static constexpr uint64_t LINES_MASK = ~BRANCH_BIT;
|
||||
|
||||
@@ -5,15 +5,6 @@
|
||||
#include "tries.h"
|
||||
|
||||
namespace bed::internal::syntax::ruby {
|
||||
enum struct ScopeTypes : uint8_t {
|
||||
None,
|
||||
Comment,
|
||||
Method,
|
||||
Class,
|
||||
Module,
|
||||
Block
|
||||
};
|
||||
|
||||
struct alignas(2) RubyState {
|
||||
struct RubyInternalState {
|
||||
uint16_t brace_level;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "buffer/append.h"
|
||||
#include "buffer/original.h"
|
||||
#include "constants.h"
|
||||
#include "definitions.h"
|
||||
#include "iterators/line.h"
|
||||
#include "pch.h"
|
||||
#include "shard.h"
|
||||
@@ -92,6 +93,9 @@ struct Vase {
|
||||
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 redo();
|
||||
void snapshot();
|
||||
|
||||
@@ -94,4 +94,9 @@ void BEd::handle(std::string_view cmd_, bool eof) {
|
||||
suffix->handle(*this);
|
||||
return;
|
||||
}
|
||||
|
||||
void BEd::suffix_handle(char s) {
|
||||
if (suffixes[s - 'a'].has_value())
|
||||
suffixes[s - 'a'].value().handle(*this);
|
||||
}
|
||||
} // namespace bed
|
||||
|
||||
@@ -29,11 +29,12 @@ Address::Address(std::string &cmd, uint64_t &i) {
|
||||
break;
|
||||
case '\'': {
|
||||
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++;
|
||||
else
|
||||
throw address_error("Invalid mark.");
|
||||
base = Mark(cmd[i]);
|
||||
base = Mark(cmd[i - 1]);
|
||||
} break;
|
||||
case '/': {
|
||||
i++;
|
||||
@@ -54,7 +55,9 @@ Address::Address(std::string &cmd, uint64_t &i) {
|
||||
else
|
||||
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;
|
||||
case '?': {
|
||||
i++;
|
||||
@@ -75,7 +78,9 @@ Address::Address(std::string &cmd, uint64_t &i) {
|
||||
else
|
||||
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;
|
||||
case '+': {
|
||||
base = Current();
|
||||
|
||||
@@ -17,24 +17,45 @@ uint64_t Address::resolve(BEd &ctx) {
|
||||
line = ctx.active->vase.lines();
|
||||
} else if constexpr (std::is_same_v<T, Number>) {
|
||||
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>) {
|
||||
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 (ctx.active->parser) {
|
||||
if (ctx.active->line == 0)
|
||||
ctx.active->line = 1;
|
||||
line = ctx.active->parser->next_closing(ctx.active->line - 1) + 1;
|
||||
uint64_t closing = ctx.active->parser->next_closing(current_line - 1);
|
||||
if (closing == UINT64_MAX)
|
||||
line = ctx.active->vase.lines();
|
||||
else
|
||||
line = closing + 1;
|
||||
} else {
|
||||
line = current_line + 10;
|
||||
if (line > ctx.active->vase.lines())
|
||||
line = ctx.active->vase.lines();
|
||||
} else {
|
||||
line = ctx.active->line + 10;
|
||||
}
|
||||
} else {
|
||||
if (ctx.active->parser) {
|
||||
if (ctx.active->line == 0)
|
||||
ctx.active->line = 1;
|
||||
line = ctx.active->parser->prev_opening(ctx.active->line - 1) + 1;
|
||||
line = ctx.active->parser->prev_opening(current_line - 1) + 1;
|
||||
} else {
|
||||
line = ctx.active->line - 10;
|
||||
if (current_line > 10)
|
||||
line = current_line - 10;
|
||||
else
|
||||
line = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -64,8 +64,6 @@ void Buffer::jump(uint64_t n_line) {
|
||||
if (n_line > vase.lines())
|
||||
throw ed_error("Line number too high.");
|
||||
line = n_line;
|
||||
prev_range.start = line;
|
||||
prev_range.end = 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;
|
||||
vase.insert(&p, text);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -89,6 +90,9 @@ void Buffer::remove(uint64_t start_line, uint64_t end_line) {
|
||||
vase.erase({{start_line - 1, 0}, {end_line, 0}});
|
||||
prev_range.start = 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;
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
prev_range.start = 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;
|
||||
}
|
||||
|
||||
@@ -132,6 +139,8 @@ inline void reset(std::ostream &out) {
|
||||
}
|
||||
|
||||
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) {
|
||||
std::optional<syntax::Parser::Iterator> it_o = parser->get_hl(vase, start_line - 1);
|
||||
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)
|
||||
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.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) {
|
||||
|
||||
@@ -9,6 +9,15 @@ void Suffix::register_suffixes(BEd &ctx) {
|
||||
.handle = [](BEd &ctx) {
|
||||
auto line = ctx.active->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(
|
||||
"q",
|
||||
Command{
|
||||
@@ -92,27 +121,67 @@ void Command::register_posix(BEd &ctx) {
|
||||
.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())
|
||||
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);
|
||||
else if (addresses.size() == 1)
|
||||
ctx.active->print(ctx, addresses[0], addresses[0]);
|
||||
else
|
||||
ctx.active->print(ctx, addresses[0], addresses[1]);
|
||||
ctx.active->jump(end_line);
|
||||
}
|
||||
}
|
||||
);
|
||||
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(
|
||||
"=",
|
||||
Command{
|
||||
.address_mode = Command::AddressMode::Single,
|
||||
.address_mode = Command::AddressMode::Range,
|
||||
.suffix = Command::SuffixKind::Suffix,
|
||||
.desc = "Print line number",
|
||||
.accept_zero = false,
|
||||
.desc = "Print line number(s)",
|
||||
.accept_zero = true,
|
||||
.handle = [](BEd &ctx, std::span<const uint64_t> addresses, std::string_view) {
|
||||
if (!addresses.size())
|
||||
std::cout << ctx.active->vase.lines() << std::endl;
|
||||
else
|
||||
else if (addresses.size() == 1)
|
||||
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]);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -243,15 +243,12 @@ void Parser::modify(vase::Vase &vase, uint64_t target, uint64_t count) {
|
||||
events.clear();
|
||||
lang.parse(&state, it.line, at == 0, &tokens, &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) {
|
||||
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->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++;
|
||||
}
|
||||
|
||||
@@ -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") {
|
||||
p.current().state = RubyState::RubyInternalState::COMMENT;
|
||||
p.current().flags &= ~RubyState::RubyInternalState::EXPECTING_EXPRESSION;
|
||||
events->push_back(ParseEvent::Opening);
|
||||
events->push_back(false);
|
||||
tokens->push_back({0, p.len(), Token::Comment});
|
||||
return true;
|
||||
}
|
||||
@@ -266,7 +266,7 @@ bool handle_syntax(RubyParser &p, std::vector<Token> *tokens, std::vector<ParseE
|
||||
case RubyState::RubyInternalState::CLASS_NAME: {
|
||||
if (p.peek() == '<' && p.peek(1) == '<') {
|
||||
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 |= RubyState::RubyInternalState::EXPECTING_EXPRESSION;
|
||||
return false;
|
||||
@@ -285,7 +285,7 @@ bool handle_syntax(RubyParser &p, std::vector<Token> *tokens, std::vector<ParseE
|
||||
return false;
|
||||
}
|
||||
}
|
||||
events->push_back(ParseEvent::Opening);
|
||||
events->push_back(false);
|
||||
p.current().flags = (p.current().flags & ~RubyState::RubyInternalState::NAME_MASK);
|
||||
return false;
|
||||
}
|
||||
@@ -311,7 +311,7 @@ bool handle_syntax(RubyParser &p, std::vector<Token> *tokens, std::vector<ParseE
|
||||
return false;
|
||||
}
|
||||
}
|
||||
events->push_back(ParseEvent::Opening);
|
||||
events->push_back(false);
|
||||
p.current().flags = (p.current().flags & ~RubyState::RubyInternalState::NAME_MASK);
|
||||
return false;
|
||||
}
|
||||
@@ -330,7 +330,7 @@ bool handle_syntax(RubyParser &p, std::vector<Token> *tokens, std::vector<ParseE
|
||||
return false;
|
||||
}
|
||||
}
|
||||
events->push_back(ParseEvent::Opening);
|
||||
events->push_back(false);
|
||||
p.current().flags = (p.current().flags & ~RubyState::RubyInternalState::NAME_MASK);
|
||||
return false;
|
||||
}
|
||||
@@ -899,21 +899,21 @@ bool handle_syntax(RubyParser &p, std::vector<Token> *tokens, std::vector<ParseE
|
||||
p.advance(j);
|
||||
return false;
|
||||
} 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;
|
||||
tokens->push_back({p.i, p.i + j, Token::Keyword});
|
||||
p.advance(j);
|
||||
return false;
|
||||
} else if (j == tries.conditional_keywords_trie.longest_match(p.peek_str(j))) {
|
||||
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;
|
||||
tokens->push_back({p.i, p.i + j, Token::Keyword});
|
||||
p.advance(j);
|
||||
return false;
|
||||
} else if (j == tries.end_keywords_trie.longest_match(p.peek_str(j))) {
|
||||
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});
|
||||
p.advance(j);
|
||||
return false;
|
||||
@@ -950,7 +950,7 @@ bool handle_syntax(RubyParser &p, std::vector<Token> *tokens, std::vector<ParseE
|
||||
return false;
|
||||
}
|
||||
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});
|
||||
p.advance(3);
|
||||
return false;
|
||||
@@ -980,17 +980,18 @@ bool handle_syntax(RubyParser &p, std::vector<Token> *tokens, std::vector<ParseE
|
||||
return false;
|
||||
}
|
||||
uint32_t start = p.i;
|
||||
if (p.peek(j) == ':') {
|
||||
p.advance(j);
|
||||
if (p.peek() == ':') {
|
||||
p.advance();
|
||||
tokens->push_back({start, p.i, Token::Label});
|
||||
return false;
|
||||
} else if (p.peek(-1) == '!' || p.peek(-1) == '?') {
|
||||
p.advance();
|
||||
} else if (p.peek(j - 1) == '!' || p.peek(j - 1) == '?') {
|
||||
p.advance(j);
|
||||
tokens->push_back({start, p.i, Token::Function});
|
||||
return false;
|
||||
} else {
|
||||
uint32_t j = 0;
|
||||
p.advance(j);
|
||||
j = 0;
|
||||
if (p.peek(j) == '(' || p.peek(j) == '{') {
|
||||
tokens->push_back({start, p.i, Token::Function});
|
||||
return false;
|
||||
@@ -1066,7 +1067,7 @@ void ruby_parse(
|
||||
tokens->push_back({p.i, p.len(), Token::Comment});
|
||||
if (p.i == 0 && p.peek_str(4) == "=end") {
|
||||
p.current().state = RubyState::RubyInternalState::NONE;
|
||||
events->push_back(ParseEvent::Closing);
|
||||
events->push_back(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -156,4 +156,122 @@ std::vector<Range> Vase::regex_search(
|
||||
result.push_back({point_of(match.start), point_of(match.end)});
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user