Cleanup and minor Fixes

This commit is contained in:
2026-01-28 18:46:44 +00:00
parent cca0177929
commit 6abdefa808
22 changed files with 343 additions and 371 deletions

View File

@@ -5,18 +5,21 @@
#include "utils/utils.h"
Editor *new_editor(const char *filename_arg, Coord position, Coord size,
bool unix_eol) {
uint8_t eol) {
Editor *editor = new Editor();
if (!editor)
return nullptr;
uint32_t len = 0;
std::string filename = path_abs(filename_arg);
char *str = load_file(filename.c_str(), &len);
editor->unix_eol = eol & 1;
char *str = load_file(filename.c_str(), &len, &editor->unix_eol);
if (!str) {
free_editor(editor);
return nullptr;
str = (char *)malloc(1);
*str = '\n';
len = 1;
}
editor->unix_eol = unix_eol;
if ((eol >> 1) & 1)
editor->unix_eol = eol & 1;
editor->filename = filename;
editor->uri = path_to_file_uri(filename);
editor->position = position;

View File

@@ -76,7 +76,7 @@ int main(int argc, char *argv[]) {
ruby_init();
ruby_start((get_exe_dir() + "/../config/main.rb").c_str());
ruby_start();
load_theme();
load_languages_info();
load_custom_highlighters();
@@ -84,10 +84,10 @@ int main(int argc, char *argv[]) {
Coord screen = start_screen();
const char *filename = (argc > 1) ? argv[1] : "";
bool unix_eol = read_line_endings();
uint8_t eol = read_line_endings();
Editor *editor =
new_editor(filename, {0, 0}, {screen.row - 2, screen.col}, unix_eol);
new_editor(filename, {0, 0}, {screen.row - 2, screen.col}, eol);
Bar bar(screen);
auto end = std::chrono::high_resolution_clock::now();

View File

@@ -1,5 +1,3 @@
#include "ruby/internal/gc.h"
#include "ruby/internal/value.h"
#include "scripting/decl.h"
#include "utils/utils.h"
@@ -28,16 +26,55 @@ struct R_Language {
VALUE C_module = Qnil;
std::mutex ruby_mutex;
void ruby_start(const char *main_file) {
namespace fs = std::filesystem;
static void ruby_load(const char *main_file) {
std::lock_guard lock(ruby_mutex);
ruby_init_loadpath();
int state = 0;
rb_load_protect(rb_str_new_cstr(main_file), 0, &state);
if (state) {
rb_errinfo();
VALUE err = rb_errinfo();
rb_set_errinfo(Qnil);
fprintf(stderr, "%d: Failed to load Ruby file\n", state);
return;
fprintf(stderr, "%d: Failed to load Ruby file %s\n", state, main_file);
}
}
static void ruby_eval_string(const char *code) {
int state = 0;
rb_eval_string_protect(code, &state);
if (state) {
VALUE err = rb_errinfo();
rb_set_errinfo(Qnil);
fprintf(stderr, "Ruby eval failed\n");
}
}
void ruby_start() {
fs::path exe_dir = get_exe_dir();
std::vector<fs::path> candidates;
candidates.emplace_back("./crib.rb");
const char *xdg = std::getenv("XDG_CONFIG_HOME");
const char *home = std::getenv("HOME");
if (xdg) {
candidates.emplace_back(fs::path(xdg) / "crib/crib.rb");
candidates.emplace_back(fs::path(xdg) / "crib/main.rb");
candidates.emplace_back(fs::path(xdg) / "crib.rb");
} else if (home) {
fs::path base = fs::path(home) / ".config";
candidates.emplace_back(base / "crib/crib.rb");
candidates.emplace_back(base / "crib/main.rb");
candidates.emplace_back(base / "crib.rb");
}
candidates.emplace_back(exe_dir / "../config/main.rb");
candidates.emplace_back(exe_dir / "../config/crib.rb");
ruby_eval_string(crib_module);
ruby_eval_string(tokens_def);
for (const auto &p : candidates) {
if (fs::exists(p) && fs::is_regular_file(p)) {
ruby_load(p.string().c_str());
break;
}
}
C_module = rb_const_get(rb_cObject, rb_intern("C"));
if (C_module == Qnil)
@@ -102,14 +139,16 @@ bool custom_compare(VALUE match_block, VALUE state1, VALUE state2) {
}
VALUE parse_custom(std::vector<Token> *tokens, VALUE parser_block,
const char *line, uint32_t len, VALUE state) {
const char *line, uint32_t len, VALUE state,
uint32_t c_line) {
std::lock_guard lock(ruby_mutex);
tokens->clear();
if (NIL_P(parser_block))
return {};
VALUE ruby_line = rb_str_new(line, len);
VALUE tokens_and_state_hash =
rb_funcall(parser_block, rb_intern("call"), 2, ruby_line, state);
VALUE line_idx = UINT2NUM(c_line);
VALUE tokens_and_state_hash = rb_funcall(parser_block, rb_intern("call"), 3,
ruby_line, state, line_idx);
VALUE tokens_rb =
rb_hash_aref(tokens_and_state_hash, ID2SYM(rb_intern("tokens")));
for (long i = 0; i < RARRAY_LEN(tokens_rb); ++i) {
@@ -287,12 +326,22 @@ void load_languages_info() {
lsps[lsp.command] = lsp;
}
bool read_line_endings() {
uint8_t read_line_endings() {
std::lock_guard lock(ruby_mutex);
if (C_module == Qnil)
return true;
return 1;
VALUE le = rb_funcall(C_module, rb_intern("line_endings"), 0);
if (SYMBOL_P(le))
return std::string(rb_id2name(SYM2ID(le))) == "unix";
return true;
if (!SYMBOL_P(le))
return 1;
uint8_t flags = 1;
const char *name = rb_id2name(SYM2ID(le));
if (std::strcmp(name, "unix") == 0)
flags = 0b01;
else if (std::strcmp(name, "windows") == 0)
flags = 0b00;
else if (std::strcmp(name, "auto_unix") == 0)
flags = 0b11;
else if (std::strcmp(name, "auto_windows") == 0)
flags = 0b10;
return flags;
}

View File

@@ -1,11 +1,10 @@
#include "syntax/decl.h"
#include "syntax/langs.h"
#include <cstdint>
struct BashFullState {
int brace_level = 0;
enum : uint8_t { NONE, STRING, HEREDOC };
enum : uint8_t { NONE, STRING, HEREDOC, PARAMETER };
uint8_t in_state = BashFullState::NONE;
bool line_cont = false;
@@ -50,7 +49,8 @@ bool bash_state_match(std::shared_ptr<void> state_1,
std::shared_ptr<void> bash_parse(std::vector<Token> *tokens,
std::shared_ptr<void> in_state,
const char *text, uint32_t len) {
const char *text, uint32_t len,
uint32_t line_num) {
static bool keywords_trie_init = false;
if (!keywords_trie_init) {
keywords_trie_init = true;
@@ -64,10 +64,44 @@ std::shared_ptr<void> bash_parse(std::vector<Token> *tokens,
if (len == 0)
return state;
while (i < len) {
if (state->full_state->in_state == BashFullState::PARAMETER) {
uint32_t start = i;
while (i < len) {
if (text[i] == '{') {
i++;
state->full_state->brace_level++;
continue;
}
if (text[i] == '}') {
if (--state->full_state->brace_level == 0 &&
!state->interp_stack.empty()) {
tokens->push_back({i - 1, i, TokenKind::K_INTERPOLATION});
state->full_state = state->interp_stack.top();
state->interp_stack.pop();
i++;
break;
}
}
i++;
}
continue;
}
if (state->full_state->in_state == BashFullState::STRING) {
uint32_t start = i;
while (i < len) {
if (state->full_state->lit.allow_interp && text[i] == '$') {
if (++i < len && text[i] == '{') {
tokens->push_back({start, i - 1, TokenKind::K_STRING});
tokens->push_back({i - 1, i, TokenKind::K_INTERPOLATION});
state->interp_stack.push(state->full_state);
state->full_state = std::make_shared<BashFullState>();
state->full_state->in_state = BashFullState::PARAMETER;
state->full_state->brace_level = 1;
break;
}
}
if (text[i] == state->full_state->lit.delim[0]) {
i++;
tokens->push_back({start, i, TokenKind::K_STRING});
state->full_state->in_state = BashFullState::NONE;
break;
@@ -79,7 +113,7 @@ std::shared_ptr<void> bash_parse(std::vector<Token> *tokens,
continue;
}
if (text[i] == '#') {
if (i == 0 && len > 4 && text[i + 1] == '!') {
if (line_num == 0 && i == 0 && len > 4 && text[i + 1] == '!') {
tokens->push_back({0, len, TokenKind::K_SHEBANG});
return state;
}
@@ -91,6 +125,12 @@ std::shared_ptr<void> bash_parse(std::vector<Token> *tokens,
state->full_state->lit.allow_interp = false;
tokens->push_back({i, ++i, TokenKind::K_STRING});
continue;
} else if (text[i] == '"') {
state->full_state->in_state = BashFullState::STRING;
state->full_state->lit.delim = "\"";
state->full_state->lit.allow_interp = true;
tokens->push_back({i, ++i, TokenKind::K_STRING});
continue;
}
i++;
}

View File

@@ -64,6 +64,10 @@ void Parser::work() {
dirty_lines.push(c_line);
continue;
}
if (scroll_max > 50 && c_line < scroll_max - 50) {
dirty_lines.push(c_line);
continue;
}
uint32_t line_count = line_tree.count();
lock_data.lock();
std::shared_ptr<void> prev_state =
@@ -118,13 +122,14 @@ void Parser::work() {
std::static_pointer_cast<CustomState>(prev_state);
state = state_ptr->state;
}
VALUE out_state =
parse_custom(&line_data->tokens, parser_block, text, r_len, state);
VALUE out_state = parse_custom(&line_data->tokens, parser_block, text,
r_len, state, c_line);
std::shared_ptr<CustomState> out_state_ptr =
std::make_shared<CustomState>(out_state);
new_state = out_state_ptr;
} else {
new_state = parse_func(&line_data->tokens, prev_state, text, r_len);
new_state =
parse_func(&line_data->tokens, prev_state, text, r_len, c_line);
}
line_data->in_state = prev_state;
line_data->out_state = new_state;
@@ -134,7 +139,8 @@ void Parser::work() {
}
prev_state = new_state;
c_line++;
if (c_line < line_count && c_line > scroll_max + 50) {
if (c_line < line_count && c_line > scroll_max + 50 && scroll_max < 50 &&
c_line < scroll_max + 50) {
lock_data.unlock();
if (lock.owns_lock())
lock.unlock();

View File

@@ -288,7 +288,8 @@ bool ruby_state_match(std::shared_ptr<void> state_1,
std::shared_ptr<void> ruby_parse(std::vector<Token> *tokens,
std::shared_ptr<void> in_state,
const char *text, uint32_t len) {
const char *text, uint32_t len,
uint32_t line_num) {
static bool keywords_trie_init = false;
static Trie<void> base_keywords_trie;
static Trie<void> expecting_keywords_trie;
@@ -703,7 +704,7 @@ std::shared_ptr<void> ruby_parse(std::vector<Token> *tokens,
i++;
continue;
} else if (text[i] == '#') {
if (i == 0 && len > 4 && text[i + 1] == '!') {
if (line_num == 0 && i == 0 && len > 4 && text[i + 1] == '!') {
state->full_state->expecting_expr = false;
tokens->push_back({0, len, TokenKind::K_SHEBANG});
return state;

View File

@@ -44,7 +44,7 @@ std::string get_exe_dir() {
return path.substr(0, path.find_last_of('/'));
}
char *load_file(const char *path, uint32_t *out_len) {
char *load_file(const char *path, uint32_t *out_len, bool *out_eol) {
std::ifstream file(path, std::ios::binary | std::ios::ate);
if (!file.is_open())
return nullptr;
@@ -64,18 +64,28 @@ char *load_file(const char *path, uint32_t *out_len) {
if (!buf)
return nullptr;
file.read(buf, data_len);
if (memchr(buf, '\r', data_len) == nullptr) {
bool has_cr = memchr(buf, '\r', data_len) != nullptr;
bool has_lf = memchr(buf, '\n', data_len) != nullptr;
if (!has_cr && !has_lf) {
uint32_t write = data_len;
if (write == 0 || buf[write - 1] != '\n')
buf[write++] = '\n';
*out_len = write;
return buf;
}
if (!has_cr) {
*out_eol = true;
uint32_t write = data_len;
if (buf[write - 1] != '\n')
buf[write++] = '\n';
*out_len = write;
return buf;
}
*out_eol = false;
uint32_t write = 0;
for (uint32_t i = 0; i < data_len; ++i)
if (buf[i] != '\r')
buf[write++] = buf[i];
if (write == 0 || buf[write - 1] != '\n')
if (buf[write - 1] != '\n')
buf[write++] = '\n';
*out_len = write;
return buf;