Add command syntax highlighting.

This commit is contained in:
2026-09-03 16:46:13 +01:00
parent 3bfebe30ce
commit a276bf60da
12 changed files with 304 additions and 84 deletions
+2 -3
View File
@@ -5,8 +5,8 @@
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, BufferName,
@@ -24,7 +24,6 @@ struct Token {
Shell, Shell,
Ruby, Ruby,
File, File,
Regex,
Replacement, Replacement,
Suffix, Suffix,
Color1, Color1,
+3 -3
View File
@@ -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);
}; };
-25
View File
@@ -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;
-2
View File
@@ -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;
+21
View File
@@ -170,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{
+135 -1
View File
@@ -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({});
+64 -2
View File
@@ -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) {
+20 -3
View File
@@ -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);
+1 -1
View File
@@ -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) {
+39 -43
View File
@@ -15,53 +15,54 @@ 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::TempCurrent] = { theme.hl[io::Token::TempCurrent] = {
.fg = 0x7DCFFF, .fg = 0x7AA2F7,
.bg = 0x000000, .bg = 0x000000,
.flags = io::Highlight::None, .flags = io::Highlight::None,
}; };
theme.hl[io::Token::BufferName] = { theme.hl[io::Token::BufferName] = {
.fg = 0xAAD94C, .fg = 0xBB9AF7,
.bg = 0x000000, .bg = 0x000000,
.flags = io::Highlight::None, .flags = io::Highlight::None,
}; };
theme.hl[io::Token::AddressSeperator] = { theme.hl[io::Token::AddressSeperator] = {
.fg = 0xFF8F40, .fg = 0xA9B1D6,
.bg = 0x000000, .bg = 0x000000,
.flags = io::Highlight::None, .flags = io::Highlight::None,
}; };
theme.hl[io::Token::Address] = { theme.hl[io::Token::Address] = {
.fg = 0xD2A6FF, .fg = 0xE0AF68,
.bg = 0x000000, .bg = 0x000000,
.flags = io::Highlight::None, .flags = io::Highlight::None,
}; };
theme.hl[io::Token::Offset] = { theme.hl[io::Token::Offset] = {
.fg = 0xEF5168, .fg = 0xFFAF70,
.bg = 0x000000, .bg = 0x000000,
.flags = io::Highlight::None, .flags = io::Highlight::None,
}; };
theme.hl[io::Token::AddressRegex] = { theme.hl[io::Token::AddressRegex] = {
.fg = 0x7DCFFF,
.bg = 0x000000,
.flags = io::Highlight::None,
};
theme.hl[io::Token::AddressSymbol] = {
.fg = 0xAAD94C,
.bg = 0x000000,
.flags = io::Highlight::None,
};
theme.hl[io::Token::Mark] = {
.fg = 0xFF8F40,
.bg = 0x000000,
.flags = io::Highlight::None,
};
theme.hl[io::Token::RubyFunction] = {
.fg = 0xD2A6FF, .fg = 0xD2A6FF,
.bg = 0x000000, .bg = 0x000000,
.flags = io::Highlight::None, .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,
.bg = 0x000000,
.flags = io::Highlight::None,
};
theme.hl[io::Token::RubyArg] = { theme.hl[io::Token::RubyArg] = {
.fg = 0xEF5168, .fg = 0xA9B1D6,
.bg = 0x000000, .bg = 0x000000,
.flags = io::Highlight::None, .flags = io::Highlight::None,
}; };
@@ -71,37 +72,32 @@ Theme Theme::default_theme() {
.flags = io::Highlight::None, .flags = io::Highlight::None,
}; };
theme.hl[io::Token::Shell] = { theme.hl[io::Token::Shell] = {
.fg = 0xAAD94C, .fg = 0x89DDFF,
.bg = 0x000000, .bg = 0x000000,
.flags = io::Highlight::None, .flags = io::Highlight::None,
}; };
theme.hl[io::Token::Ruby] = { theme.hl[io::Token::Ruby] = {
.fg = 0xFF8F40, .fg = 0x95E6CB,
.bg = 0x000000, .bg = 0x000000,
.flags = io::Highlight::None, .flags = io::Highlight::None,
}; };
theme.hl[io::Token::File] = { theme.hl[io::Token::File] = {
.fg = 0xD2A6FF,
.bg = 0x000000,
.flags = io::Highlight::None,
};
theme.hl[io::Token::Regex] = {
.fg = 0xEF5168,
.bg = 0x000000,
.flags = io::Highlight::None,
};
theme.hl[io::Token::Replacement] = {
.fg = 0x7DCFFF,
.bg = 0x000000,
.flags = io::Highlight::None,
};
theme.hl[io::Token::Suffix] = {
.fg = 0xAAD94C, .fg = 0xAAD94C,
.bg = 0x000000, .bg = 0x000000,
.flags = io::Highlight::None, .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] = { theme.hl[io::Token::Color1] = {
.fg = 0x7DCFFF, .fg = 0x7AA2F7,
.bg = 0x000000, .bg = 0x000000,
.flags = io::Highlight::None, .flags = io::Highlight::None,
}; };
@@ -111,17 +107,17 @@ Theme Theme::default_theme() {
.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,
}; };
@@ -162,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,
}; };
+17 -1
View File
@@ -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
+2
View File
@@ -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--;