Compare commits
2
Commits
46bdb8cd0f
...
a276bf60da
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a276bf60da
|
||
|
|
3bfebe30ce
|
@@ -5,10 +5,11 @@
|
|||||||
|
|
||||||
namespace bed::internal::io {
|
namespace bed::internal::io {
|
||||||
struct Token {
|
struct Token {
|
||||||
uint32_t start;
|
uint64_t start;
|
||||||
uint32_t end;
|
uint64_t end;
|
||||||
enum Kind : uint8_t {
|
enum Kind : uint8_t {
|
||||||
TempCurrent,
|
TempCurrent,
|
||||||
|
BufferName,
|
||||||
AddressSeperator,
|
AddressSeperator,
|
||||||
Address,
|
Address,
|
||||||
Offset,
|
Offset,
|
||||||
@@ -23,7 +24,6 @@ struct Token {
|
|||||||
Shell,
|
Shell,
|
||||||
Ruby,
|
Ruby,
|
||||||
File,
|
File,
|
||||||
Regex,
|
|
||||||
Replacement,
|
Replacement,
|
||||||
Suffix,
|
Suffix,
|
||||||
Color1,
|
Color1,
|
||||||
|
|||||||
@@ -85,12 +85,12 @@ struct Parser {
|
|||||||
std::string_view cmd;
|
std::string_view cmd;
|
||||||
uint16_t i;
|
uint16_t i;
|
||||||
Command *command;
|
Command *command;
|
||||||
std::vector<ui::Token> *tokens;
|
std::vector<io::Token> *tokens;
|
||||||
CompletionContext *completion;
|
CompletionContext *completion;
|
||||||
|
|
||||||
explicit Parser(
|
explicit Parser(
|
||||||
std::string_view cmd, BEd &bed, Command *command,
|
std::string_view cmd, BEd &bed, Command *command,
|
||||||
std::vector<ui::Token> *tokens, CompletionContext *completion
|
std::vector<io::Token> *tokens, CompletionContext *completion
|
||||||
);
|
);
|
||||||
|
|
||||||
char peek(uint16_t = 0); // == \0 if at eof.
|
char peek(uint16_t = 0); // == \0 if at eof.
|
||||||
@@ -107,7 +107,7 @@ struct Parser {
|
|||||||
void operation();
|
void operation();
|
||||||
|
|
||||||
void parse();
|
void parse();
|
||||||
|
static std::vector<io::Token> get_highlight(std::string_view cmd, BEd &bed);
|
||||||
static Command get_command(std::string_view, BEd &);
|
static Command get_command(std::string_view, BEd &);
|
||||||
static std::vector<AddressPromise> get_addresses(std::string_view cmd, BEd &bed);
|
static std::vector<AddressPromise> get_addresses(std::string_view cmd, BEd &bed);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,31 +4,6 @@
|
|||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
|
|
||||||
namespace bed::internal::ui {
|
namespace bed::internal::ui {
|
||||||
struct Token {
|
|
||||||
enum struct Type : uint8_t {
|
|
||||||
TempCurrent, // @
|
|
||||||
AddressSeperator, // ; ,
|
|
||||||
Address, // . $ % [ ] ^ ~
|
|
||||||
Offset, // +N -N + -
|
|
||||||
AddressRegex, // /re/ ?re?
|
|
||||||
AddressSymbol, // >s> <s< <s>
|
|
||||||
Number, // 10
|
|
||||||
Mark, // 'm
|
|
||||||
RubyFunction, // (func:arg)
|
|
||||||
RubyArg,
|
|
||||||
Function,
|
|
||||||
Any,
|
|
||||||
Shell,
|
|
||||||
Ruby,
|
|
||||||
File,
|
|
||||||
Regex,
|
|
||||||
Replacement,
|
|
||||||
Suffix
|
|
||||||
} type;
|
|
||||||
uint16_t start;
|
|
||||||
uint16_t end;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CommandIO {
|
struct CommandIO {
|
||||||
std::string cmd;
|
std::string cmd;
|
||||||
uint16_t cursor;
|
uint16_t cursor;
|
||||||
|
|||||||
@@ -29,8 +29,6 @@ uint64_t ShardBuffer::find_prev(std::string_view pattern, uint64_t start) {
|
|||||||
uint64_t ShardBuffer::next_closing(uint64_t start) {
|
uint64_t ShardBuffer::next_closing(uint64_t start) {
|
||||||
if (parse.lang) {
|
if (parse.lang) {
|
||||||
uint64_t closing = syntax::next_closing(parse, start - 1);
|
uint64_t closing = syntax::next_closing(parse, start - 1);
|
||||||
if (closing == UINT64_MAX)
|
|
||||||
return lines();
|
|
||||||
return closing + 1;
|
return closing + 1;
|
||||||
} else {
|
} else {
|
||||||
start += 10;
|
start += 10;
|
||||||
|
|||||||
@@ -118,6 +118,39 @@ void Function::register_extented(BEd &ctx) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
ctx.functions.insert(
|
||||||
|
"b",
|
||||||
|
Function{
|
||||||
|
.address_kind = Function::AddressKind::None,
|
||||||
|
.argument_kind = Function::ArgumentKind::None,
|
||||||
|
.input_mode = Function::InputMode::None,
|
||||||
|
.desc = "List active buffers",
|
||||||
|
.default_address = "",
|
||||||
|
.accept_zero = false,
|
||||||
|
.pre_text_mode = nullptr,
|
||||||
|
.handle = [](
|
||||||
|
BEd &ctx,
|
||||||
|
const buffer::Address &addr_,
|
||||||
|
vase::Shard *,
|
||||||
|
const Argument &,
|
||||||
|
std::vector<buffer::Line> *
|
||||||
|
) {
|
||||||
|
auto ¤t = std::get<std::string>(addr_);
|
||||||
|
bool current_real = false;
|
||||||
|
for (auto &[name, _] : ctx.buffers) {
|
||||||
|
if (current == name) {
|
||||||
|
ctx.io.write("* ");
|
||||||
|
current_real = true;
|
||||||
|
} else {
|
||||||
|
ctx.io.write(" ");
|
||||||
|
}
|
||||||
|
ctx.io.write_line(name);
|
||||||
|
}
|
||||||
|
if (!current_real)
|
||||||
|
ctx.io.write_line("* " + current);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
ctx.functions.insert(
|
ctx.functions.insert(
|
||||||
"#",
|
"#",
|
||||||
Function{
|
Function{
|
||||||
@@ -137,6 +170,27 @@ void Function::register_extented(BEd &ctx) {
|
|||||||
) {},
|
) {},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
ctx.functions.insert(
|
||||||
|
"`",
|
||||||
|
Function{
|
||||||
|
.address_kind = Function::AddressKind::None,
|
||||||
|
.argument_kind = Function::ArgumentKind::Ruby,
|
||||||
|
.input_mode = Function::InputMode::None,
|
||||||
|
.desc = "Execute some ruby code",
|
||||||
|
.default_address = "",
|
||||||
|
.accept_zero = false,
|
||||||
|
.pre_text_mode = nullptr,
|
||||||
|
.handle = [](
|
||||||
|
BEd &,
|
||||||
|
const buffer::Address &,
|
||||||
|
vase::Shard *,
|
||||||
|
const Argument &,
|
||||||
|
std::vector<buffer::Line> *
|
||||||
|
) {
|
||||||
|
// TODO: connect up to mruby.
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
ctx.functions.insert(
|
ctx.functions.insert(
|
||||||
"echo",
|
"echo",
|
||||||
Function{
|
Function{
|
||||||
|
|||||||
@@ -745,10 +745,19 @@ void Function::register_posix(BEd &ctx) {
|
|||||||
std::vector<buffer::Line> *
|
std::vector<buffer::Line> *
|
||||||
) {
|
) {
|
||||||
auto &addr = std::get<buffer::Range>(addr_);
|
auto &addr = std::get<buffer::Range>(addr_);
|
||||||
if (addr.start == addr.end)
|
ctx.io.apply(io::Token::BufferName);
|
||||||
ctx.io.write_line(std::format(":{}:{}", addr.buffername, addr.start));
|
ctx.io.write(":" + addr.buffername + ":");
|
||||||
else
|
ctx.io.apply(io::Token::Number);
|
||||||
ctx.io.write_line(std::format(":{}:{},{}", addr.buffername, addr.start, addr.end));
|
if (addr.start == addr.end) {
|
||||||
|
ctx.io.write_line(std::format(" {}", addr.start));
|
||||||
|
} else {
|
||||||
|
ctx.io.write(std::format(" {}", addr.start));
|
||||||
|
ctx.io.apply(io::Token::AddressSeperator);
|
||||||
|
ctx.io.write(",");
|
||||||
|
ctx.io.apply(io::Token::Number);
|
||||||
|
ctx.io.write_line(std::format("{}", addr.end));
|
||||||
|
}
|
||||||
|
ctx.io.reset();
|
||||||
ctx.prev().buffername = addr.buffername;
|
ctx.prev().buffername = addr.buffername;
|
||||||
ctx.prev().start = addr.start;
|
ctx.prev().start = addr.start;
|
||||||
ctx.prev().end = addr.end;
|
ctx.prev().end = addr.end;
|
||||||
|
|||||||
@@ -6,34 +6,74 @@ void Parser::locator(AddressPromise &addr) {
|
|||||||
addr.base = AddressPromise::None{};
|
addr.base = AddressPromise::None{};
|
||||||
switch (peek()) {
|
switch (peek()) {
|
||||||
case '.':
|
case '.':
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = i,
|
||||||
|
.end = i + (uint64_t)1,
|
||||||
|
.type = io::Token::AddressSymbol}
|
||||||
|
);
|
||||||
advance();
|
advance();
|
||||||
addr.base = AddressPromise::Current{};
|
addr.base = AddressPromise::Current{};
|
||||||
break;
|
break;
|
||||||
case '$':
|
case '$':
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = i,
|
||||||
|
.end = i + (uint64_t)1,
|
||||||
|
.type = io::Token::AddressSymbol}
|
||||||
|
);
|
||||||
advance();
|
advance();
|
||||||
addr.base = AddressPromise::Last{};
|
addr.base = AddressPromise::Last{};
|
||||||
break;
|
break;
|
||||||
case '%':
|
case '%':
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = i,
|
||||||
|
.end = i + (uint64_t)1,
|
||||||
|
.type = io::Token::AddressSymbol}
|
||||||
|
);
|
||||||
advance();
|
advance();
|
||||||
addr.base = AddressPromise::LastRange{};
|
addr.base = AddressPromise::LastRange{};
|
||||||
break;
|
break;
|
||||||
case '[':
|
case '[':
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = i,
|
||||||
|
.end = i + (uint64_t)1,
|
||||||
|
.type = io::Token::AddressSymbol}
|
||||||
|
);
|
||||||
advance();
|
advance();
|
||||||
addr.base = AddressPromise::Block{Direction::Backward};
|
addr.base = AddressPromise::Block{Direction::Backward};
|
||||||
break;
|
break;
|
||||||
case ']':
|
case ']':
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = i,
|
||||||
|
.end = i + (uint64_t)1,
|
||||||
|
.type = io::Token::AddressSymbol}
|
||||||
|
);
|
||||||
advance();
|
advance();
|
||||||
addr.base = AddressPromise::Block{Direction::Forward};
|
addr.base = AddressPromise::Block{Direction::Forward};
|
||||||
break;
|
break;
|
||||||
case '^':
|
case '^':
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = i,
|
||||||
|
.end = i + (uint64_t)1,
|
||||||
|
.type = io::Token::AddressSymbol}
|
||||||
|
);
|
||||||
advance();
|
advance();
|
||||||
addr.base = AddressPromise::Diagnostic{Direction::Backward};
|
addr.base = AddressPromise::Diagnostic{Direction::Backward};
|
||||||
break;
|
break;
|
||||||
case '~':
|
case '~':
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = i,
|
||||||
|
.end = i + (uint64_t)1,
|
||||||
|
.type = io::Token::AddressSymbol}
|
||||||
|
);
|
||||||
advance();
|
advance();
|
||||||
addr.base = AddressPromise::Diagnostic{Direction::Forward};
|
addr.base = AddressPromise::Diagnostic{Direction::Forward};
|
||||||
break;
|
break;
|
||||||
case '\'':
|
case '\'':
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = i,
|
||||||
|
.end = i + (uint64_t)2,
|
||||||
|
.type = io::Token::Mark}
|
||||||
|
);
|
||||||
advance();
|
advance();
|
||||||
if (('a' <= peek() && peek() <= 'z')
|
if (('a' <= peek() && peek() <= 'z')
|
||||||
|| ('A' <= peek() && peek() <= 'Z'))
|
|| ('A' <= peek() && peek() <= 'Z'))
|
||||||
@@ -43,6 +83,11 @@ void Parser::locator(AddressPromise &addr) {
|
|||||||
advance();
|
advance();
|
||||||
break;
|
break;
|
||||||
case '{': {
|
case '{': {
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = i,
|
||||||
|
.end = i + (uint64_t)1,
|
||||||
|
.type = io::Token::AddressSymbol}
|
||||||
|
);
|
||||||
advance();
|
advance();
|
||||||
uint16_t j = 0;
|
uint16_t j = 0;
|
||||||
std::string func;
|
std::string func;
|
||||||
@@ -64,8 +109,24 @@ void Parser::locator(AddressPromise &addr) {
|
|||||||
arg = peek_str(j);
|
arg = peek_str(j);
|
||||||
else
|
else
|
||||||
func = peek_str(j);
|
func = peek_str(j);
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = i,
|
||||||
|
.end = i + (uint64_t)func.size(),
|
||||||
|
.type = io::Token::RubyFunction}
|
||||||
|
);
|
||||||
|
if (arg.size())
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = i + (uint64_t)func.size() + 1,
|
||||||
|
.end = i + (uint64_t)func.size() + 1 + (uint64_t)arg.size(),
|
||||||
|
.type = io::Token::RubyFunction}
|
||||||
|
);
|
||||||
addr.base = AddressPromise::Scripted{std::move(func), std::move(arg)};
|
addr.base = AddressPromise::Scripted{std::move(func), std::move(arg)};
|
||||||
advance(j + 1);
|
advance(j + 1);
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = i,
|
||||||
|
.end = i - (uint64_t)1,
|
||||||
|
.type = io::Token::AddressSymbol}
|
||||||
|
);
|
||||||
} break;
|
} break;
|
||||||
case '/': {
|
case '/': {
|
||||||
advance();
|
advance();
|
||||||
@@ -87,9 +148,19 @@ void Parser::locator(AddressPromise &addr) {
|
|||||||
Direction::Forward,
|
Direction::Forward,
|
||||||
std::string(peek_str(j))
|
std::string(peek_str(j))
|
||||||
);
|
);
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = (uint64_t)i - 1,
|
||||||
|
.end = (uint64_t)i + j + 1,
|
||||||
|
.type = io::Token::Regexp}
|
||||||
|
);
|
||||||
advance(j + 1);
|
advance(j + 1);
|
||||||
} break;
|
} break;
|
||||||
case '?': {
|
case '?': {
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = i,
|
||||||
|
.end = i + (uint64_t)1,
|
||||||
|
.type = io::Token::AddressSymbol}
|
||||||
|
);
|
||||||
advance();
|
advance();
|
||||||
uint16_t j = 0;
|
uint16_t j = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
@@ -109,6 +180,11 @@ void Parser::locator(AddressPromise &addr) {
|
|||||||
Direction::Backward,
|
Direction::Backward,
|
||||||
std::string(peek_str(j))
|
std::string(peek_str(j))
|
||||||
);
|
);
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = (uint64_t)i - 1,
|
||||||
|
.end = (uint64_t)i + j + 1,
|
||||||
|
.type = io::Token::Regexp}
|
||||||
|
);
|
||||||
advance(j + 1);
|
advance(j + 1);
|
||||||
} break;
|
} break;
|
||||||
case '<': {
|
case '<': {
|
||||||
@@ -132,6 +208,11 @@ void Parser::locator(AddressPromise &addr) {
|
|||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = (uint64_t)i - 1,
|
||||||
|
.end = (uint64_t)i + j + 1,
|
||||||
|
.type = io::Token::AddressSymbol}
|
||||||
|
);
|
||||||
advance(j + 1);
|
advance(j + 1);
|
||||||
} break;
|
} break;
|
||||||
case '>': {
|
case '>': {
|
||||||
@@ -149,9 +230,19 @@ void Parser::locator(AddressPromise &addr) {
|
|||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = (uint64_t)i - 1,
|
||||||
|
.end = (uint64_t)i + j + 1,
|
||||||
|
.type = io::Token::AddressSymbol}
|
||||||
|
);
|
||||||
advance(j + 1);
|
advance(j + 1);
|
||||||
} break;
|
} break;
|
||||||
case '+': {
|
case '+': {
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = i,
|
||||||
|
.end = i + (uint64_t)1,
|
||||||
|
.type = io::Token::AddressSymbol}
|
||||||
|
);
|
||||||
advance();
|
advance();
|
||||||
addr.base = AddressPromise::Current{};
|
addr.base = AddressPromise::Current{};
|
||||||
uint16_t j = 0;
|
uint16_t j = 0;
|
||||||
@@ -162,10 +253,20 @@ void Parser::locator(AddressPromise &addr) {
|
|||||||
}
|
}
|
||||||
if (j == 0)
|
if (j == 0)
|
||||||
num = 1;
|
num = 1;
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = (uint64_t)i,
|
||||||
|
.end = (uint64_t)i + j,
|
||||||
|
.type = io::Token::Number}
|
||||||
|
);
|
||||||
advance(j);
|
advance(j);
|
||||||
addr.offset += num;
|
addr.offset += num;
|
||||||
} break;
|
} break;
|
||||||
case '-': {
|
case '-': {
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = i,
|
||||||
|
.end = i + (uint64_t)1,
|
||||||
|
.type = io::Token::AddressSymbol}
|
||||||
|
);
|
||||||
advance();
|
advance();
|
||||||
addr.base = AddressPromise::Current{};
|
addr.base = AddressPromise::Current{};
|
||||||
uint16_t j = 0;
|
uint16_t j = 0;
|
||||||
@@ -176,17 +277,28 @@ void Parser::locator(AddressPromise &addr) {
|
|||||||
}
|
}
|
||||||
if (j == 0)
|
if (j == 0)
|
||||||
num = 1;
|
num = 1;
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = (uint64_t)i,
|
||||||
|
.end = (uint64_t)i + j,
|
||||||
|
.type = io::Token::Number}
|
||||||
|
);
|
||||||
advance(j);
|
advance(j);
|
||||||
addr.offset -= num;
|
addr.offset -= num;
|
||||||
} break;
|
} break;
|
||||||
default:
|
default:
|
||||||
if ('0' <= peek() && peek() <= '9') {
|
if ('0' <= peek() && peek() <= '9') {
|
||||||
|
uint16_t start = i;
|
||||||
uint64_t num = 0;
|
uint64_t num = 0;
|
||||||
while ('0' <= peek() && peek() <= '9') {
|
while ('0' <= peek() && peek() <= '9') {
|
||||||
num = num * 10 + (peek() - '0');
|
num = num * 10 + (peek() - '0');
|
||||||
advance();
|
advance();
|
||||||
}
|
}
|
||||||
addr.base = AddressPromise::Number{num};
|
addr.base = AddressPromise::Number{num};
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = (uint64_t)start,
|
||||||
|
.end = (uint64_t)i,
|
||||||
|
.type = io::Token::Number}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,14 +308,25 @@ int64_t Parser::offset() {
|
|||||||
while (peek() == '+' || peek() == '-'
|
while (peek() == '+' || peek() == '-'
|
||||||
|| ('0' <= peek() && peek() <= '9')) {
|
|| ('0' <= peek() && peek() <= '9')) {
|
||||||
bool positive = peek() != '-';
|
bool positive = peek() != '-';
|
||||||
if (peek() == '+' || peek() == '-')
|
if (peek() == '+' || peek() == '-') {
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = i,
|
||||||
|
.end = i + (uint64_t)1,
|
||||||
|
.type = io::Token::AddressSymbol}
|
||||||
|
);
|
||||||
advance();
|
advance();
|
||||||
|
}
|
||||||
uint16_t j = 0;
|
uint16_t j = 0;
|
||||||
int64_t num = 0;
|
int64_t num = 0;
|
||||||
while ('0' <= peek(j) && peek(j) <= '9')
|
while ('0' <= peek(j) && peek(j) <= '9')
|
||||||
num = num * 10 + (peek(j++) - '0');
|
num = num * 10 + (peek(j++) - '0');
|
||||||
if (j == 0)
|
if (j == 0)
|
||||||
num = 1;
|
num = 1;
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = (uint64_t)i,
|
||||||
|
.end = (uint64_t)i + j,
|
||||||
|
.type = io::Token::Number}
|
||||||
|
);
|
||||||
advance(j);
|
advance(j);
|
||||||
offset += positive ? num : -num;
|
offset += positive ? num : -num;
|
||||||
skip_ws();
|
skip_ws();
|
||||||
@@ -214,6 +337,7 @@ int64_t Parser::offset() {
|
|||||||
|
|
||||||
void Parser::address(AddressPromise &addr) {
|
void Parser::address(AddressPromise &addr) {
|
||||||
if (peek() == ':') {
|
if (peek() == ':') {
|
||||||
|
uint16_t start = i;
|
||||||
advance();
|
advance();
|
||||||
uint16_t j = 0;
|
uint16_t j = 0;
|
||||||
while (peek(j) != ':' && peek(j) != '\0')
|
while (peek(j) != ':' && peek(j) != '\0')
|
||||||
@@ -222,6 +346,11 @@ void Parser::address(AddressPromise &addr) {
|
|||||||
advance(j);
|
advance(j);
|
||||||
if (peek() == ':')
|
if (peek() == ':')
|
||||||
advance();
|
advance();
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = start,
|
||||||
|
.end = i,
|
||||||
|
.type = io::Token::BufferName}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
skip_ws();
|
skip_ws();
|
||||||
if (peek() == '\0')
|
if (peek() == '\0')
|
||||||
@@ -238,6 +367,11 @@ void Parser::addresses(std::vector<AddressPromise> &addresses) {
|
|||||||
address(*addr);
|
address(*addr);
|
||||||
while (peek() == ',' || peek() == ';') {
|
while (peek() == ',' || peek() == ';') {
|
||||||
addr->jumping = peek() == ';';
|
addr->jumping = peek() == ';';
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = i,
|
||||||
|
.end = i + (uint64_t)1,
|
||||||
|
.type = io::Token::AddressSeperator}
|
||||||
|
);
|
||||||
advance();
|
advance();
|
||||||
skip_ws();
|
skip_ws();
|
||||||
addresses.push_back({});
|
addresses.push_back({});
|
||||||
|
|||||||
@@ -11,6 +11,11 @@ void Parser::operation() {
|
|||||||
if (len == 0)
|
if (len == 0)
|
||||||
throw ed_error("Function not found.");
|
throw ed_error("Function not found.");
|
||||||
functions::Function *function = bed.functions.get_ptr(peek_str(len));
|
functions::Function *function = bed.functions.get_ptr(peek_str(len));
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = i,
|
||||||
|
.end = i + len,
|
||||||
|
.type = io::Token::Function}
|
||||||
|
);
|
||||||
advance(len);
|
advance(len);
|
||||||
command->function = function;
|
command->function = function;
|
||||||
char suffix = '\0';
|
char suffix = '\0';
|
||||||
@@ -27,10 +32,20 @@ void Parser::operation() {
|
|||||||
command->argument = peek();
|
command->argument = peek();
|
||||||
else
|
else
|
||||||
throw ed_error("Valid mark needed.");
|
throw ed_error("Valid mark needed.");
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = i,
|
||||||
|
.end = i + (uint64_t)1,
|
||||||
|
.type = io::Token::Mark}
|
||||||
|
);
|
||||||
advance();
|
advance();
|
||||||
break;
|
break;
|
||||||
case functions::Function::ArgumentKind::Any:
|
case functions::Function::ArgumentKind::Any:
|
||||||
command->argument = std::string(peek_str());
|
command->argument = std::string(peek_str());
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = i,
|
||||||
|
.end = i + peek_str().size(),
|
||||||
|
.type = io::Token::Any}
|
||||||
|
);
|
||||||
advance(peek_str().size());
|
advance(peek_str().size());
|
||||||
break;
|
break;
|
||||||
case functions::Function::ArgumentKind::Global: {
|
case functions::Function::ArgumentKind::Global: {
|
||||||
@@ -108,8 +123,18 @@ void Parser::operation() {
|
|||||||
skip_ws();
|
skip_ws();
|
||||||
switch (peek()) {
|
switch (peek()) {
|
||||||
case '!':
|
case '!':
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = i,
|
||||||
|
.end = (uint64_t)i + 1,
|
||||||
|
.type = io::Token::Error}
|
||||||
|
);
|
||||||
advance();
|
advance();
|
||||||
command->argument = functions::Function::ShellArg(std::string(peek_str()));
|
command->argument = functions::Function::ShellArg(std::string(peek_str()));
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = i,
|
||||||
|
.end = i + peek_str().size(),
|
||||||
|
.type = io::Token::Shell}
|
||||||
|
);
|
||||||
advance(peek_str().size());
|
advance(peek_str().size());
|
||||||
break;
|
break;
|
||||||
case '\0':
|
case '\0':
|
||||||
@@ -117,6 +142,11 @@ void Parser::operation() {
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
command->argument = std::filesystem::path(peek_str());
|
command->argument = std::filesystem::path(peek_str());
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = i,
|
||||||
|
.end = i + peek_str().size(),
|
||||||
|
.type = io::Token::File}
|
||||||
|
);
|
||||||
advance(peek_str().size());
|
advance(peek_str().size());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -133,6 +163,7 @@ void Parser::operation() {
|
|||||||
char delim = peek();
|
char delim = peek();
|
||||||
if (delim == '\0')
|
if (delim == '\0')
|
||||||
throw ed_error("regex expected");
|
throw ed_error("regex expected");
|
||||||
|
uint16_t start = i;
|
||||||
advance();
|
advance();
|
||||||
uint16_t j = 0;
|
uint16_t j = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
@@ -172,8 +203,18 @@ void Parser::operation() {
|
|||||||
advance(j);
|
advance(j);
|
||||||
options = "p";
|
options = "p";
|
||||||
}
|
}
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = start,
|
||||||
|
.end = i,
|
||||||
|
.type = io::Token::Regexp}
|
||||||
|
);
|
||||||
if (peek() != '\0') {
|
if (peek() != '\0') {
|
||||||
options = std::string(peek_str());
|
options = std::string(peek_str());
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = i,
|
||||||
|
.end = i + peek_str().size(),
|
||||||
|
.type = io::Token::Suffix}
|
||||||
|
);
|
||||||
advance(peek_str().size());
|
advance(peek_str().size());
|
||||||
}
|
}
|
||||||
std::erase_if(options, [&](char c) {
|
std::erase_if(options, [&](char c) {
|
||||||
@@ -185,17 +226,38 @@ void Parser::operation() {
|
|||||||
});
|
});
|
||||||
command->argument = functions::Function::RegexArg(expression, replacement, options);
|
command->argument = functions::Function::RegexArg(expression, replacement, options);
|
||||||
} break;
|
} break;
|
||||||
case functions::Function::ArgumentKind::Ruby:
|
case functions::Function::ArgumentKind::Ruby: {
|
||||||
command->argument = functions::Function::RubyArg(std::string(peek_str()));
|
command->argument = functions::Function::RubyArg(std::string(peek_str()));
|
||||||
|
auto *ruby_parser = bed.languages["ruby"];
|
||||||
|
void *state = ruby_parser->none_state();
|
||||||
|
std::vector<syntax::ParseEvent> events;
|
||||||
|
std::vector<io::Token> tokens_;
|
||||||
|
ruby_parser->parse(&state, peek_str(), false, &tokens_, &events);
|
||||||
|
for (auto &token : tokens_) {
|
||||||
|
token.start += i;
|
||||||
|
token.end += i;
|
||||||
|
tokens->push_back(token);
|
||||||
|
}
|
||||||
|
ruby_parser->destroy(state);
|
||||||
advance(peek_str().size());
|
advance(peek_str().size());
|
||||||
break;
|
} break;
|
||||||
case functions::Function::ArgumentKind::Shell:
|
case functions::Function::ArgumentKind::Shell:
|
||||||
command->argument = functions::Function::ShellArg(std::string(peek_str()));
|
command->argument = functions::Function::ShellArg(std::string(peek_str()));
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = i,
|
||||||
|
.end = i + peek_str().size(),
|
||||||
|
.type = io::Token::Shell}
|
||||||
|
);
|
||||||
advance(peek_str().size());
|
advance(peek_str().size());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!suffix) {
|
if (!suffix) {
|
||||||
suffix = peek();
|
suffix = peek();
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = i,
|
||||||
|
.end = i + (uint64_t)1,
|
||||||
|
.type = io::Token::Suffix}
|
||||||
|
);
|
||||||
advance();
|
advance();
|
||||||
}
|
}
|
||||||
if (suffix) {
|
if (suffix) {
|
||||||
|
|||||||
@@ -22,6 +22,11 @@ void Parser::skip_ws() {
|
|||||||
void Parser::parse() {
|
void Parser::parse() {
|
||||||
skip_ws();
|
skip_ws();
|
||||||
if (peek() == '@') {
|
if (peek() == '@') {
|
||||||
|
tokens->push_back(
|
||||||
|
{.start = 0,
|
||||||
|
.end = 1,
|
||||||
|
.type = io::Token::TempCurrent}
|
||||||
|
);
|
||||||
advance();
|
advance();
|
||||||
command->temp_address = true;
|
command->temp_address = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -37,14 +42,26 @@ void Parser::parse() {
|
|||||||
|
|
||||||
Parser::Parser(
|
Parser::Parser(
|
||||||
std::string_view cmd, BEd &bed, Command *command,
|
std::string_view cmd, BEd &bed, Command *command,
|
||||||
std::vector<ui::Token> *tokens, CompletionContext *completion
|
std::vector<io::Token> *tokens, CompletionContext *completion
|
||||||
) : bed(bed), cmd(cmd), command(command), tokens(tokens), completion(completion) {
|
) : bed(bed), cmd(cmd), command(command), tokens(tokens), completion(completion) {
|
||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<io::Token> Parser::get_highlight(std::string_view cmd, BEd &bed) {
|
||||||
|
Command c;
|
||||||
|
std::vector<io::Token> tokens;
|
||||||
|
CompletionContext completion;
|
||||||
|
try {
|
||||||
|
Parser p(cmd, bed, &c, &tokens, &completion);
|
||||||
|
p.parse();
|
||||||
|
} catch (const ed_error &e) {
|
||||||
|
}
|
||||||
|
return tokens;
|
||||||
|
}
|
||||||
|
|
||||||
Command Parser::get_command(std::string_view cmd, BEd &bed) {
|
Command Parser::get_command(std::string_view cmd, BEd &bed) {
|
||||||
Command c;
|
Command c;
|
||||||
std::vector<ui::Token> tokens;
|
std::vector<io::Token> tokens;
|
||||||
CompletionContext completion;
|
CompletionContext completion;
|
||||||
Parser p(cmd, bed, &c, &tokens, &completion);
|
Parser p(cmd, bed, &c, &tokens, &completion);
|
||||||
p.parse();
|
p.parse();
|
||||||
@@ -53,7 +70,7 @@ Command Parser::get_command(std::string_view cmd, BEd &bed) {
|
|||||||
|
|
||||||
std::vector<AddressPromise> Parser::get_addresses(std::string_view cmd, BEd &bed) {
|
std::vector<AddressPromise> Parser::get_addresses(std::string_view cmd, BEd &bed) {
|
||||||
std::vector<AddressPromise> result;
|
std::vector<AddressPromise> result;
|
||||||
std::vector<ui::Token> tokens;
|
std::vector<io::Token> tokens;
|
||||||
CompletionContext completion;
|
CompletionContext completion;
|
||||||
Parser p(cmd, bed, nullptr, &tokens, &completion);
|
Parser p(cmd, bed, nullptr, &tokens, &completion);
|
||||||
p.addresses(result);
|
p.addresses(result);
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ uint64_t next_closing(const ParserSnapshot &snap, uint64_t line) {
|
|||||||
c.next();
|
c.next();
|
||||||
first_leaf = false;
|
first_leaf = false;
|
||||||
}
|
}
|
||||||
return (snap.root->lines() - line > 10 ? line + 10 : snap.root->lines());
|
return (snap.root->lines() - line > 10 ? line + 10 : snap.root->lines() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t prev_opening(const ParserSnapshot &snap, uint64_t line) {
|
uint64_t prev_opening(const ParserSnapshot &snap, uint64_t line) {
|
||||||
|
|||||||
@@ -15,28 +15,109 @@ io::Highlight Theme::get(const io::Token::Kind &token) const {
|
|||||||
|
|
||||||
Theme Theme::default_theme() {
|
Theme Theme::default_theme() {
|
||||||
Theme theme;
|
Theme theme;
|
||||||
theme.hl[io::Token::Color1] = {
|
|
||||||
|
theme.hl[io::Token::TempCurrent] = {
|
||||||
|
.fg = 0x7AA2F7,
|
||||||
|
.bg = 0x000000,
|
||||||
|
.flags = io::Highlight::None,
|
||||||
|
};
|
||||||
|
theme.hl[io::Token::BufferName] = {
|
||||||
|
.fg = 0xBB9AF7,
|
||||||
|
.bg = 0x000000,
|
||||||
|
.flags = io::Highlight::None,
|
||||||
|
};
|
||||||
|
theme.hl[io::Token::AddressSeperator] = {
|
||||||
|
.fg = 0xA9B1D6,
|
||||||
|
.bg = 0x000000,
|
||||||
|
.flags = io::Highlight::None,
|
||||||
|
};
|
||||||
|
theme.hl[io::Token::Address] = {
|
||||||
|
.fg = 0xE0AF68,
|
||||||
|
.bg = 0x000000,
|
||||||
|
.flags = io::Highlight::None,
|
||||||
|
};
|
||||||
|
theme.hl[io::Token::Offset] = {
|
||||||
|
.fg = 0xFFAF70,
|
||||||
|
.bg = 0x000000,
|
||||||
|
.flags = io::Highlight::None,
|
||||||
|
};
|
||||||
|
theme.hl[io::Token::AddressRegex] = {
|
||||||
|
.fg = 0xD2A6FF,
|
||||||
|
.bg = 0x000000,
|
||||||
|
.flags = io::Highlight::None,
|
||||||
|
};
|
||||||
|
theme.hl[io::Token::AddressSymbol] = {
|
||||||
|
.fg = 0xFF9E64,
|
||||||
|
.bg = 0x000000,
|
||||||
|
.flags = io::Highlight::None,
|
||||||
|
};
|
||||||
|
theme.hl[io::Token::Mark] = {
|
||||||
|
.fg = 0xFF757F,
|
||||||
|
.bg = 0x000000,
|
||||||
|
.flags = io::Highlight::None,
|
||||||
|
};
|
||||||
|
theme.hl[io::Token::RubyFunction] = {
|
||||||
.fg = 0x7DCFFF,
|
.fg = 0x7DCFFF,
|
||||||
.bg = 0x000000,
|
.bg = 0x000000,
|
||||||
.flags = io::Highlight::None,
|
.flags = io::Highlight::None,
|
||||||
};
|
};
|
||||||
|
theme.hl[io::Token::RubyArg] = {
|
||||||
|
.fg = 0xA9B1D6,
|
||||||
|
.bg = 0x000000,
|
||||||
|
.flags = io::Highlight::None,
|
||||||
|
};
|
||||||
|
theme.hl[io::Token::Any] = {
|
||||||
|
.fg = 0x7DCFFF,
|
||||||
|
.bg = 0x000000,
|
||||||
|
.flags = io::Highlight::None,
|
||||||
|
};
|
||||||
|
theme.hl[io::Token::Shell] = {
|
||||||
|
.fg = 0x89DDFF,
|
||||||
|
.bg = 0x000000,
|
||||||
|
.flags = io::Highlight::None,
|
||||||
|
};
|
||||||
|
theme.hl[io::Token::Ruby] = {
|
||||||
|
.fg = 0x95E6CB,
|
||||||
|
.bg = 0x000000,
|
||||||
|
.flags = io::Highlight::None,
|
||||||
|
};
|
||||||
|
theme.hl[io::Token::File] = {
|
||||||
|
.fg = 0xAAD94C,
|
||||||
|
.bg = 0x000000,
|
||||||
|
.flags = io::Highlight::None,
|
||||||
|
};
|
||||||
|
theme.hl[io::Token::Replacement] = {
|
||||||
|
.fg = 0x9ECE6A,
|
||||||
|
.bg = 0x000000,
|
||||||
|
.flags = io::Highlight::None,
|
||||||
|
};
|
||||||
|
theme.hl[io::Token::Suffix] = {
|
||||||
|
.fg = 0xF07178,
|
||||||
|
.bg = 0x000000,
|
||||||
|
.flags = io::Highlight::None,
|
||||||
|
};
|
||||||
|
theme.hl[io::Token::Color1] = {
|
||||||
|
.fg = 0x7AA2F7,
|
||||||
|
.bg = 0x000000,
|
||||||
|
.flags = io::Highlight::None,
|
||||||
|
};
|
||||||
theme.hl[io::Token::Color2] = {
|
theme.hl[io::Token::Color2] = {
|
||||||
.fg = 0xAAD94C,
|
.fg = 0xAAD94C,
|
||||||
.bg = 0x000000,
|
.bg = 0x000000,
|
||||||
.flags = io::Highlight::None,
|
.flags = io::Highlight::None,
|
||||||
};
|
};
|
||||||
theme.hl[io::Token::Color3] = {
|
theme.hl[io::Token::Color3] = {
|
||||||
.fg = 0xFF8F40,
|
.fg = 0xFF9E64,
|
||||||
.bg = 0x000000,
|
.bg = 0x000000,
|
||||||
.flags = io::Highlight::None,
|
.flags = io::Highlight::None,
|
||||||
};
|
};
|
||||||
theme.hl[io::Token::Color4] = {
|
theme.hl[io::Token::Color4] = {
|
||||||
.fg = 0xD2A6FF,
|
.fg = 0xBB9AF7,
|
||||||
.bg = 0x000000,
|
.bg = 0x000000,
|
||||||
.flags = io::Highlight::None,
|
.flags = io::Highlight::None,
|
||||||
};
|
};
|
||||||
theme.hl[io::Token::Color5] = {
|
theme.hl[io::Token::Color5] = {
|
||||||
.fg = 0xEF5168,
|
.fg = 0xFF757F,
|
||||||
.bg = 0x000000,
|
.bg = 0x000000,
|
||||||
.flags = io::Highlight::None,
|
.flags = io::Highlight::None,
|
||||||
};
|
};
|
||||||
@@ -77,7 +158,7 @@ Theme Theme::default_theme() {
|
|||||||
.flags = io::Highlight::None,
|
.flags = io::Highlight::None,
|
||||||
};
|
};
|
||||||
theme.hl[io::Token::Regexp] = {
|
theme.hl[io::Token::Regexp] = {
|
||||||
.fg = 0xD2A6FF,
|
.fg = 0x7DCFFF,
|
||||||
.bg = 0x000000,
|
.bg = 0x000000,
|
||||||
.flags = io::Highlight::None,
|
.flags = io::Highlight::None,
|
||||||
};
|
};
|
||||||
@@ -187,7 +268,6 @@ Theme Theme::default_theme() {
|
|||||||
Theme Theme::from_name(std::string_view name) {
|
Theme Theme::from_name(std::string_view name) {
|
||||||
if (name == "default")
|
if (name == "default")
|
||||||
return default_theme();
|
return default_theme();
|
||||||
throw std::runtime_error("Unknown theme: " + std::string(name));
|
throw ed_error("Unknown theme: " + std::string(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace bed::internal::theme
|
} // namespace bed::internal::theme
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "internal/ui/command.h"
|
#include "internal/ui/command.h"
|
||||||
#include "bed.h"
|
#include "bed.h"
|
||||||
|
#include "internal/parser/parser.h"
|
||||||
|
|
||||||
namespace bed::internal::ui {
|
namespace bed::internal::ui {
|
||||||
/*template <typename F>
|
/*template <typename F>
|
||||||
@@ -162,7 +163,22 @@ void CommandIO::redraw() {
|
|||||||
bed.io.write("\x1b[2K", 4);
|
bed.io.write("\x1b[2K", 4);
|
||||||
bed.io.move_cursor(start, 1);
|
bed.io.move_cursor(start, 1);
|
||||||
bed.io.write(prompt);
|
bed.io.write(prompt);
|
||||||
bed.io.write(cmd);
|
const auto tokens = parser::Parser::get_highlight(cmd, bed);
|
||||||
|
uint32_t pos = 0;
|
||||||
|
for (const auto &token : tokens) {
|
||||||
|
const uint32_t tstart = token.start;
|
||||||
|
const uint32_t tend = token.end;
|
||||||
|
if (tstart > cmd.size())
|
||||||
|
break;
|
||||||
|
if (pos < tstart)
|
||||||
|
bed.io.write(cmd.data() + pos, tstart - pos);
|
||||||
|
bed.io.apply(token.type);
|
||||||
|
bed.io.write(cmd.data() + tstart, tend - tstart);
|
||||||
|
bed.io.reset();
|
||||||
|
pos = tend;
|
||||||
|
}
|
||||||
|
if (pos < cmd.size())
|
||||||
|
bed.io.write(cmd.data() + pos, cmd.size() - pos);
|
||||||
bed.io.move_cursor(start, prompt.size() + cursor + 1);
|
bed.io.move_cursor(start, prompt.size() + cursor + 1);
|
||||||
}
|
}
|
||||||
} // namespace bed::internal::ui
|
} // namespace bed::internal::ui
|
||||||
|
|||||||
@@ -289,6 +289,8 @@ Shard *Shard::from_command(const char *cmd, bool posix_ending) {
|
|||||||
last = nullptr;
|
last = nullptr;
|
||||||
if (!pieces.empty())
|
if (!pieces.empty())
|
||||||
last = (Petal *)pieces.back();
|
last = (Petal *)pieces.back();
|
||||||
|
else
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (last && ending[0] == '\r')
|
if (last && ending[0] == '\r')
|
||||||
last->length--;
|
last->length--;
|
||||||
|
|||||||
Reference in New Issue
Block a user