Compare commits
3 Commits
876639363f
...
9900b83871
| Author | SHA1 | Date | |
|---|---|---|---|
|
9900b83871
|
|||
|
cacda354c2
|
|||
|
6598bb941b
|
52
.gitmodules
vendored
52
.gitmodules
vendored
@@ -1,16 +1,56 @@
|
||||
[submodule "libs/libgrapheme"]
|
||||
path = libs/libgrapheme
|
||||
url = https://git.suckless.org/libgrapheme.git
|
||||
ignore = dirty
|
||||
|
||||
; tree-sitter
|
||||
[submodule "libs/tree-sitter"]
|
||||
path = libs/tree-sitter
|
||||
url = https://github.com/tree-sitter/tree-sitter.git
|
||||
ignore = dirty
|
||||
|
||||
; Tree-sitter languages
|
||||
[submodule "libs/tree-sitter-ruby"]
|
||||
path = libs/tree-sitter-ruby
|
||||
url = https://github.com/tree-sitter/tree-sitter-ruby.git
|
||||
ignore = dirty
|
||||
[submodule "libs/tree-sitter-c"]
|
||||
path = libs/tree-sitter-c
|
||||
url = https://github.com/tree-sitter/tree-sitter-c.git
|
||||
ignore = dirty
|
||||
[submodule "libs/tree-sitter-ruby"]
|
||||
path = libs/tree-sitter-ruby
|
||||
url = https://github.com/tree-sitter/tree-sitter-ruby.git
|
||||
[submodule "libs/tree-sitter-cpp"]
|
||||
path = libs/tree-sitter-cpp
|
||||
url = https://github.com/tree-sitter/tree-sitter-cpp.git
|
||||
ignore = dirty
|
||||
[submodule "libs/libgrapheme"]
|
||||
path = libs/libgrapheme
|
||||
url = https://git.suckless.org/libgrapheme.git
|
||||
[submodule "libs/tree-sitter-css"]
|
||||
path = libs/tree-sitter-css
|
||||
url = https://github.com/tree-sitter/tree-sitter-css.git
|
||||
ignore = dirty
|
||||
[submodule "libs/tree-sitter-html"]
|
||||
path = libs/tree-sitter-html
|
||||
url = https://github.com/tree-sitter/tree-sitter-html.git
|
||||
ignore = dirty
|
||||
[submodule "libs/tree-sitter-javascript"]
|
||||
path = libs/tree-sitter-javascript
|
||||
url = https://github.com/tree-sitter/tree-sitter-javascript.git
|
||||
ignore = dirty
|
||||
[submodule "libs/tree-sitter-json"]
|
||||
path = libs/tree-sitter-json
|
||||
url = https://github.com/tree-sitter/tree-sitter-json.git
|
||||
ignore = dirty
|
||||
[submodule "libs/tree-sitter-python"]
|
||||
path = libs/tree-sitter-python
|
||||
url = https://github.com/tree-sitter/tree-sitter-python.git
|
||||
ignore = dirty
|
||||
[submodule "libs/tree-sitter-haskell"]
|
||||
path = libs/tree-sitter-haskell
|
||||
url = https://github.com/tree-sitter/tree-sitter-haskell.git
|
||||
ignore = dirty
|
||||
[submodule "libs/tree-sitter-go"]
|
||||
path = libs/tree-sitter-go
|
||||
url = https://github.com/tree-sitter/tree-sitter-go.git
|
||||
ignore = dirty
|
||||
[submodule "libs/tree-sitter-bash"]
|
||||
path = libs/tree-sitter-bash
|
||||
url = https://github.com/tree-sitter/tree-sitter-bash.git
|
||||
ignore = dirty
|
||||
|
||||
3
Makefile
3
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)
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)$" ))
|
||||
|
||||
|
||||
@@ -31,31 +31,6 @@ struct Spans {
|
||||
Queue<std::pair<uint32_t, int64_t>> 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<Span> &spans, uint32_t x, int64_t y);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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 =
|
||||
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 =
|
||||
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<Span> &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;
|
||||
|
||||
19
src/main.cc
19
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});
|
||||
}
|
||||
|
||||
@@ -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<uint32_t, int64_t> 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<uint32_t, int64_t> span_edit;
|
||||
while (editor->spans.edits.pop(span_edit))
|
||||
editor->spans.apply(span_edit.first, span_edit.second);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user