From 9900b83871abe1f80d79d05123f8874d594b84f9 Mon Sep 17 00:00:00 2001 From: Syed Daanish Date: Tue, 9 Dec 2025 23:18:06 +0000 Subject: [PATCH] Minor fixes --- Makefile | 3 --- README.md | 5 ++++ grammar/ruby.scm | 6 ++--- include/editor.h | 26 +------------------ src/editor.cc | 66 +++++++++++++++++++++++++++++++++++++++++++----- src/main.cc | 19 ++++++++------ src/ts.cc | 8 +++--- 7 files changed, 84 insertions(+), 49 deletions(-) diff --git a/Makefile b/Makefile index 9cf085a..a644e4d 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,6 @@ LIBS := \ libs/tree-sitter-ruby/libtree-sitter-ruby.a \ -lpcre2-8 - SRC := $(wildcard $(SRC_DIR)/*.cc) OBJ_DEBUG := $(patsubst $(SRC_DIR)/%.cc,$(OBJ_DIR)/debug/%.o,$(SRC)) OBJ_RELEASE := $(patsubst $(SRC_DIR)/%.cc,$(OBJ_DIR)/release/%.o,$(SRC)) @@ -53,7 +52,6 @@ $(TARGET_RELEASE): $(OBJ_RELEASE) $(UNICODE_OBJ_RELEASE) mkdir -p $(BIN_DIR) $(CXX_RELEASE) $(CFLAGS_RELEASE) -o $@ $^ $(LIBS) -# Pattern rules for object files + dependency generation $(OBJ_DIR)/debug/%.o: $(SRC_DIR)/%.cc mkdir -p $(dir $@) $(CXX_DEBUG) $(CFLAGS_DEBUG) -MMD -MP -c $< -o $@ @@ -70,7 +68,6 @@ $(OBJ_DIR)/release/unicode_width/%.o: libs/unicode_width/%.c mkdir -p $(dir $@) $(CXX_RELEASE) $(CFLAGS_RELEASE) -MMD -MP -c $< -o $@ -# Include deps if they exist DEP_DEBUG += $(UNICODE_OBJ_DEBUG:.o=.d) DEP_RELEASE += $(UNICODE_OBJ_RELEASE:.o=.d) diff --git a/README.md b/README.md index 16419ac..3a64fcd 100644 --- a/README.md +++ b/README.md @@ -3,3 +3,8 @@ Copyright 2025 Syed Daanish # Crib A TUI IDE. + +# TODO + +- [ ] VERY HIGH PRIORITY: fix bug when moving upwards into wrapped line (cuses random line amongst the wrapped lines to be visually focused while in reality the top is selected), has be somewhere in `ensure_scroll` function. +- [ ] Add support for wide characters with wrapping. diff --git a/grammar/ruby.scm b/grammar/ruby.scm index 63cd5e8..a2e78a1 100644 --- a/grammar/ruby.scm +++ b/grammar/ruby.scm @@ -142,17 +142,17 @@ ((identifier) @keyword.modifier (#match? @keyword.modifier "^(private|protected|public)$" )) -;; #fbb152 #000000 0 0 0 1 +;; #fbb152 #000000 0 0 0 3 (program (call (identifier) @keyword.import) (#match? @keyword.import "^(require|require_relative|load)$")) -;; #fbb152 #000000 0 0 0 2 +;; #fbb152 #000000 0 0 0 4 ((identifier) @constant.builtin (#match? @constant.builtin "^(__callee__|__dir__|__id__|__method__|__send__|__ENCODING__|__FILE__|__LINE__)$" )) -;; #aad84c #000000 0 0 0 1 +;; #aad84c #000000 0 0 0 3 ((identifier) @function.builtin (#match? @function.builtin "^(attr_reader|attr_writer|attr_accessor|module_function)$" )) diff --git a/include/editor.h b/include/editor.h index 6d42d3e..3283aef 100644 --- a/include/editor.h +++ b/include/editor.h @@ -31,31 +31,6 @@ struct Spans { Queue> edits; bool mid_parse = false; std::shared_mutex mtx; - - void apply(uint32_t x, int64_t y) { - std::unique_lock lock(mtx); - auto it = std::lower_bound( - spans.begin(), spans.end(), Span{.start = x, .end = 0, .hl = nullptr}, - [](auto &a, auto &b) { return a.start < b.start; }); - while (it != spans.begin()) { - auto prev = std::prev(it); - if (prev->end <= x) - break; - it = prev; - } - while (it != spans.end()) { - if (it->start < x && it->end > x) { - it->end += y; - } else if (it->start > x) { - it->start += y; - it->end += y; - } - if (it->end <= it->start) - it = spans.erase(it); - else - ++it; - } - } }; struct SpanCursor { @@ -145,5 +120,6 @@ void cursor_down(Editor *editor, uint32_t number); void cursor_left(Editor *editor, uint32_t number); void cursor_right(Editor *editor, uint32_t number); void ensure_scroll(Editor *editor); +void apply_edit(std::vector &spans, uint32_t x, int64_t y); #endif diff --git a/src/editor.cc b/src/editor.cc index 5071bbd..de59966 100644 --- a/src/editor.cc +++ b/src/editor.cc @@ -40,19 +40,20 @@ Editor *new_editor(const char *filename, Coord position, Coord size) { editor->size = size; editor->tree = nullptr; editor->cursor = {0, 0}; + editor->cursor_preffered = UINT32_MAX; editor->selection_active = false; editor->selection = {0, 0}; editor->scroll = {0, 0}; editor->root = load(str, len, optimal_chunk_size(len)); + free(str); editor->folded.resize(editor->root->line_count + 2); std::string query = get_exe_dir() + "/../grammar/ruby.scm"; - if (!(len > (1024 * 1024))) { + if (len < (1024 * 64)) { editor->parser = ts_parser_new(); editor->language = tree_sitter_ruby(); ts_parser_set_language(editor->parser, editor->language); editor->query = load_query(query.c_str(), editor); } - free(str); return editor; } @@ -183,8 +184,10 @@ void cursor_down(Editor *editor, uint32_t number) { char *line_content = next_line(it); if (line_content == nullptr) return; - uint32_t visual_col = - get_visual_col_from_bytes(line_content, editor->cursor.col); + if (editor->cursor_preffered == UINT32_MAX) + editor->cursor_preffered = + get_visual_col_from_bytes(line_content, editor->cursor.col); + uint32_t visual_col = editor->cursor_preffered; do { free(line_content); line_content = next_line(it); @@ -212,8 +215,10 @@ void cursor_up(Editor *editor, uint32_t number) { free(it); return; } - uint32_t visual_col = - get_visual_col_from_bytes(line_content, editor->cursor.col); + if (editor->cursor_preffered == UINT32_MAX) + editor->cursor_preffered = + get_visual_col_from_bytes(line_content, editor->cursor.col); + uint32_t visual_col = editor->cursor_preffered; free(line_content); while (number > 0 && editor->cursor.row > 0) { editor->cursor.row--; @@ -275,6 +280,19 @@ void cursor_right(Editor *editor, uint32_t number) { } number--; } + LineIterator *it2 = begin_l_iter(editor->root, editor->cursor.row); + char *cur_line = next_line(it2); + free(it2); + if (cur_line) { + uint32_t len2 = strlen(cur_line); + if (len2 > 0 && cur_line[len2 - 1] == '\n') + cur_line[--len2] = '\0'; + editor->cursor_preffered = + get_visual_col_from_bytes(cur_line, editor->cursor.col); + free(cur_line); + } else { + editor->cursor_preffered = UINT32_MAX; + } if (line) free(line); } @@ -328,6 +346,19 @@ void cursor_left(Editor *editor, uint32_t number) { } number--; } + LineIterator *it2 = begin_l_iter(editor->root, editor->cursor.row); + char *cur_line = next_line(it2); + free(it2); + if (cur_line) { + uint32_t len2 = strlen(cur_line); + if (len2 > 0 && cur_line[len2 - 1] == '\n') + cur_line[--len2] = '\0'; + editor->cursor_preffered = + get_visual_col_from_bytes(cur_line, editor->cursor.col); + free(cur_line); + } else { + editor->cursor_preffered = UINT32_MAX; + } if (line) free(line); } @@ -376,6 +407,29 @@ void update_render_fold_marker(uint32_t row, uint32_t cols) { update(row, i, " ", 0xc6c6c6, 0, 0); } +void apply_edit(std::vector &spans, uint32_t x, int64_t y) { + Span key{.start = x, .end = 0, .hl = nullptr}; + auto it = std::lower_bound( + spans.begin(), spans.end(), key, + [](const Span &a, const Span &b) { return a.start < b.start; }); + size_t idx = std::distance(spans.begin(), it); + while (idx > 0 && spans.at(idx - 1).end > x) + --idx; + for (size_t i = idx; i < spans.size();) { + Span &s = spans.at(i); + if (s.start < x && s.end > x) { + s.end += y; + } else if (s.start > x) { + s.start += y; + s.end += y; + } + if (s.end <= s.start) + spans.erase(spans.begin() + i); + else + ++i; + } +} + void render_editor(Editor *editor) { uint32_t screen_rows = editor->size.row; uint32_t screen_cols = editor->size.col; diff --git a/src/main.cc b/src/main.cc index f600911..ad9dc2c 100644 --- a/src/main.cc +++ b/src/main.cc @@ -75,10 +75,10 @@ void handle_editor_event(Editor *editor, KeyEvent event) { }; editor->edit_queue.push(edit); } - editor->spans.apply(pos, 1); + cursor_right(editor, 1); + apply_edit(editor->spans.spans, pos, 1); if (editor->spans.mid_parse) editor->spans.edits.push({pos, 1}); - cursor_right(editor, 1); } if (event.key_type == KEY_CHAR && event.c == '\t') { std::shared_lock lock_1(editor->knot_mtx); @@ -99,10 +99,11 @@ void handle_editor_event(Editor *editor, KeyEvent event) { }; editor->edit_queue.push(edit); } - editor->spans.apply(pos, 2); + cursor_right(editor, 2); + std::unique_lock lock_3(editor->spans.mtx); + apply_edit(editor->spans.spans, pos, 2); if (editor->spans.mid_parse) editor->spans.edits.push({pos, 2}); - cursor_right(editor, 2); } if (event.key_type == KEY_CHAR && (event.c == '\n' || event.c == '\r')) { std::shared_lock lock_1(editor->knot_mtx); @@ -120,14 +121,15 @@ void handle_editor_event(Editor *editor, KeyEvent event) { .new_end_byte = pos + 1, .start_point = {editor->cursor.row, editor->cursor.col}, .old_end_point = {editor->cursor.row, editor->cursor.col}, - .new_end_point = {editor->cursor.row, editor->cursor.col + 1}, + .new_end_point = {editor->cursor.row + 1, 0}, }; editor->edit_queue.push(edit); } - editor->spans.apply(pos + 1, 1); + cursor_right(editor, 1); + std::unique_lock lock_3(editor->spans.mtx); + apply_edit(editor->spans.spans, pos + 1, 1); if (editor->spans.mid_parse) editor->spans.edits.push({pos + 1, 1}); - cursor_right(editor, 1); } if (event.key_type == KEY_CHAR && event.c == 0x7F) { std::shared_lock lock_1(editor->knot_mtx); @@ -152,7 +154,8 @@ void handle_editor_event(Editor *editor, KeyEvent event) { }; editor->edit_queue.push(edit); } - editor->spans.apply(start, start - pos); + std::unique_lock lock_3(editor->spans.mtx); + apply_edit(editor->spans.spans, start, start - pos); if (editor->spans.mid_parse) editor->spans.edits.push({start, start - pos}); } diff --git a/src/ts.cc b/src/ts.cc index 94753b2..4a3910a 100644 --- a/src/ts.cc +++ b/src/ts.cc @@ -94,7 +94,7 @@ static inline bool ts_predicate(TSQuery *query, const TSQueryMatch &match, ts_query_predicates_for_pattern(query, match.pattern_index, &step_count); if (!steps || step_count != 4) return true; - if (source->char_count >= (64 * 1024)) + if (source->char_count >= (16 * 1024)) return false; std::string command; std::string regex_txt; @@ -233,11 +233,11 @@ void ts_collect_spans(Editor *editor) { if (!running) return; std::sort(new_spans.begin(), new_spans.end()); + std::pair span_edit; + while (editor->spans.edits.pop(span_edit)) + apply_edit(new_spans, span_edit.first, span_edit.second); std::unique_lock span_mtx(editor->spans.mtx); editor->spans.mid_parse = false; editor->spans.spans.swap(new_spans); span_mtx.unlock(); - std::pair span_edit; - while (editor->spans.edits.pop(span_edit)) - editor->spans.apply(span_edit.first, span_edit.second); }