Switch to OOP style code

This commit is contained in:
2026-02-04 00:38:11 +00:00
parent e3fc5323df
commit a62d4a18a8
50 changed files with 3011 additions and 3078 deletions

View File

@@ -1,25 +1,24 @@
#include "editor/editor.h"
void ensure_cursor(Editor *editor) {
std::shared_lock knot_lock(editor->knot_mtx);
if (editor->cursor < editor->scroll) {
editor->cursor.row = editor->scroll.row;
editor->cursor.col = editor->scroll.col;
editor->cursor_preffered = UINT32_MAX;
void Editor::ensure_cursor() {
if (this->cursor < this->scroll) {
this->cursor.row = this->scroll.row;
this->cursor.col = this->scroll.col;
this->cursor_preffered = UINT32_MAX;
return;
}
uint32_t numlen =
EXTRA_META + static_cast<int>(std::log10(editor->root->line_count + 1));
uint32_t render_width = editor->size.col - numlen;
EXTRA_META + static_cast<int>(std::log10(this->root->line_count + 1));
uint32_t render_width = this->size.col - numlen;
uint32_t visual_rows = 0;
uint32_t line_index = editor->scroll.row;
uint32_t line_index = this->scroll.row;
bool first_visual_line = true;
LineIterator *it = begin_l_iter(editor->root, line_index);
LineIterator *it = begin_l_iter(this->root, line_index);
if (!it)
return;
Coord last_visible = editor->scroll;
Coord last_visible = this->scroll;
while (true) {
if (visual_rows >= editor->size.row)
if (visual_rows >= this->size.row)
break;
uint32_t line_len;
char *line = next_line(it, &line_len);
@@ -27,13 +26,13 @@ void ensure_cursor(Editor *editor) {
break;
if (line_len > 0 && line[line_len - 1] == '\n')
line_len--;
uint32_t offset = first_visual_line ? editor->scroll.col : 0;
uint32_t offset = first_visual_line ? this->scroll.col : 0;
first_visual_line = false;
while (offset < line_len || (line_len == 0 && offset == 0)) {
Coord current = {line_index, offset};
last_visible = current;
visual_rows++;
if (visual_rows >= editor->size.row)
if (visual_rows >= this->size.row)
break;
uint32_t col = 0;
uint32_t advance = 0;
@@ -48,9 +47,9 @@ void ensure_cursor(Editor *editor) {
left -= g;
col += w;
}
if (line_index == editor->cursor.row) {
if (editor->cursor.col >= offset &&
editor->cursor.col <= offset + advance) {
if (line_index == this->cursor.row) {
if (this->cursor.col >= offset &&
this->cursor.col <= offset + advance) {
free(it->buffer);
free(it);
return;
@@ -64,20 +63,19 @@ void ensure_cursor(Editor *editor) {
}
line_index++;
}
editor->cursor.row = last_visible.row;
editor->cursor.col = last_visible.col;
editor->cursor_preffered = UINT32_MAX;
this->cursor.row = last_visible.row;
this->cursor.col = last_visible.col;
this->cursor_preffered = UINT32_MAX;
free(it->buffer);
free(it);
}
void ensure_scroll(Editor *editor) {
std::shared_lock knot_lock(editor->knot_mtx);
void Editor::ensure_scroll() {
uint32_t numlen =
EXTRA_META + static_cast<int>(std::log10(editor->root->line_count + 1));
uint32_t render_width = editor->size.col - numlen;
if (editor->cursor < editor->scroll) {
LineIterator *it = begin_l_iter(editor->root, editor->cursor.row);
EXTRA_META + static_cast<int>(std::log10(this->root->line_count + 1));
uint32_t render_width = this->size.col - numlen;
if (this->cursor < this->scroll) {
LineIterator *it = begin_l_iter(this->root, this->cursor.row);
if (!it)
return;
uint32_t len;
@@ -98,9 +96,9 @@ void ensure_scroll(Editor *editor) {
int width = display_width(line + offset, inc);
if (cols + width > render_width) {
cols = 0;
if (editor->cursor.col > old_offset && editor->cursor.col <= offset) {
editor->scroll.row = editor->cursor.row;
editor->scroll.col = old_offset;
if (this->cursor.col > old_offset && this->cursor.col <= offset) {
this->scroll.row = this->cursor.row;
this->scroll.col = old_offset;
free(it->buffer);
free(it);
return;
@@ -112,14 +110,14 @@ void ensure_scroll(Editor *editor) {
}
free(it->buffer);
free(it);
editor->scroll.row = editor->cursor.row;
editor->scroll.col = (editor->cursor.col == 0) ? 0 : old_offset;
} else if (editor->cursor.row - editor->scroll.row < editor->size.row * 2) {
uint32_t line_index = editor->scroll.row;
LineIterator *it = begin_l_iter(editor->root, line_index);
this->scroll.row = this->cursor.row;
this->scroll.col = (this->cursor.col == 0) ? 0 : old_offset;
} else if (this->cursor.row - this->scroll.row < this->size.row * 2) {
uint32_t line_index = this->scroll.row;
LineIterator *it = begin_l_iter(this->root, line_index);
if (!it)
return;
uint32_t max_visual_lines = editor->size.row;
uint32_t max_visual_lines = this->size.row;
Coord *scroll_queue = (Coord *)malloc(sizeof(Coord) * max_visual_lines);
uint32_t q_head = 0;
uint32_t q_size = 0;
@@ -133,7 +131,7 @@ void ensure_scroll(Editor *editor) {
line_len--;
uint32_t current_byte_offset = 0;
if (first_visual_line) {
current_byte_offset += editor->scroll.col;
current_byte_offset += this->scroll.col;
first_visual_line = false;
}
while (current_byte_offset < line_len ||
@@ -160,16 +158,16 @@ void ensure_scroll(Editor *editor) {
line_left -= cluster_len;
col += width;
}
if (line_index == editor->cursor.row) {
if (line_index == this->cursor.row) {
bool cursor_found = false;
if (editor->cursor.col >= current_byte_offset &&
editor->cursor.col < current_byte_offset + local_render_offset)
if (this->cursor.col >= current_byte_offset &&
this->cursor.col < current_byte_offset + local_render_offset)
cursor_found = true;
else if (editor->cursor.col == line_len &&
else if (this->cursor.col == line_len &&
current_byte_offset + local_render_offset == line_len)
cursor_found = true;
if (cursor_found) {
editor->scroll = scroll_queue[q_head];
this->scroll = scroll_queue[q_head];
free(scroll_queue);
free(it->buffer);
free(it);
@@ -186,10 +184,10 @@ void ensure_scroll(Editor *editor) {
free(it->buffer);
free(it);
} else {
editor->scroll.row = (editor->cursor.row > editor->size.row * 1.5)
? editor->cursor.row - editor->size.row * 1.5
: 0;
editor->scroll.col = 0;
ensure_scroll(editor);
this->scroll.row = (this->cursor.row > this->size.row * 1.5)
? this->cursor.row - this->size.row * 1.5
: 0;
this->scroll.col = 0;
this->ensure_scroll();
}
}

View File

@@ -32,12 +32,9 @@ uint32_t scan_right(const char *line, uint32_t len, uint32_t off) {
return i;
}
void word_boundaries_exclusive(Editor *editor, Coord coord, uint32_t *prev_col,
uint32_t *next_col) {
if (!editor)
return;
std::shared_lock lock(editor->knot_mtx);
LineIterator *it = begin_l_iter(editor->root, coord.row);
void Editor::word_boundaries_exclusive(Coord coord, uint32_t *prev_col,
uint32_t *next_col) {
LineIterator *it = begin_l_iter(this->root, coord.row);
if (!it)
return;
uint32_t line_len;
@@ -85,13 +82,10 @@ uint32_t word_jump_left(const char *line, size_t len, uint32_t col) {
return static_cast<uint32_t>(last);
}
void word_boundaries(Editor *editor, Coord coord, uint32_t *prev_col,
uint32_t *next_col, uint32_t *prev_clusters,
uint32_t *next_clusters) {
if (!editor)
return;
std::shared_lock lock(editor->knot_mtx);
LineIterator *it = begin_l_iter(editor->root, coord.row);
void Editor::word_boundaries(Coord coord, uint32_t *prev_col,
uint32_t *next_col, uint32_t *prev_clusters,
uint32_t *next_clusters) {
LineIterator *it = begin_l_iter(this->root, coord.row);
if (!it)
return;
uint32_t line_len;

View File

@@ -1,23 +1,22 @@
#include "editor/editor.h"
#include "main.h"
Coord editor_hit_test(Editor *editor, uint32_t x, uint32_t y) {
Coord Editor::click_coord(uint32_t x, uint32_t y) {
if (mode == INSERT)
x++;
uint32_t numlen =
EXTRA_META + static_cast<int>(std::log10(editor->root->line_count + 1));
uint32_t render_width = editor->size.col - numlen;
EXTRA_META + static_cast<int>(std::log10(this->root->line_count + 1));
uint32_t render_width = this->size.col - numlen;
x = MAX(x, numlen) - numlen + 1;
uint32_t target_visual_row = y;
uint32_t visual_row = 0;
uint32_t line_index = editor->scroll.row;
uint32_t last_line_index = editor->scroll.row;
uint32_t last_col = editor->scroll.col;
uint32_t line_index = this->scroll.row;
uint32_t last_line_index = this->scroll.row;
uint32_t last_col = this->scroll.col;
bool first_visual_line = true;
std::shared_lock knot_lock(editor->knot_mtx);
LineIterator *it = begin_l_iter(editor->root, line_index);
LineIterator *it = begin_l_iter(this->root, line_index);
if (!it)
return editor->scroll;
return this->scroll;
while (visual_row <= target_visual_row) {
uint32_t line_len;
char *line = next_line(it, &line_len);
@@ -27,7 +26,7 @@ Coord editor_hit_test(Editor *editor, uint32_t x, uint32_t y) {
line_len--;
last_line_index = line_index;
last_col = line_len;
uint32_t offset = first_visual_line ? editor->scroll.col : 0;
uint32_t offset = first_visual_line ? this->scroll.col : 0;
first_visual_line = false;
while (offset < line_len || (line_len == 0 && offset == 0)) {
uint32_t col = 0;

13
src/editor/commands.cc Normal file
View File

@@ -0,0 +1,13 @@
#include "editor/editor.h"
#include "main.h"
void Editor::handle_command(std::string &command) {
if (command == "w") {
this->save();
}
if (command == "wq") {
this->save();
command = "q";
ui::bar.handle_command(command);
}
}

View File

@@ -1,459 +1,458 @@
#include "editor/decl.h"
#include "editor/editor.h"
#include "io/knot.h"
#include "io/sysio.h"
#include "lsp/lsp.h"
#include "main.h"
#include "utils/utils.h"
inline static std::string completion_prefix(Editor *editor) {
Coord hook = editor->completion.hook;
Coord cur = editor->cursor;
if (hook.row != cur.row || cur.col < hook.col)
return "";
LineIterator *it = begin_l_iter(editor->root, hook.row);
uint32_t line_len;
char *line = next_line(it, &line_len);
if (!line) {
free(it->buffer);
free(it);
return "";
}
std::string prefix(line + hook.col, cur.col - hook.col);
free(it->buffer);
free(it);
return prefix;
}
inline static void completion_adjust_scroll(CompletionSession &s) {
if (s.visible.empty())
return;
int vi = -1;
for (size_t i = 0; i < s.visible.size(); i++)
if (s.visible[i] == s.select) {
vi = (int)i;
break;
}
if (vi < 0)
return;
if ((uint32_t)vi < s.scroll)
s.scroll = vi;
else if ((uint32_t)vi >= s.scroll + 8)
s.scroll = vi - 7;
}
void completion_filter(Editor *editor) {
auto &session = editor->completion;
std::string prefix = completion_prefix(editor);
session.visible.clear();
for (size_t i = 0; i < session.items.size(); ++i) {
const auto &item = session.items[i];
const std::string &key = item.filter;
if (key.size() >= prefix.size() &&
key.compare(0, prefix.size(), prefix) == 0)
session.visible.push_back(i);
}
if (session.visible.empty()) {
session.box.hidden = true;
return;
}
if (std::find(session.visible.begin(), session.visible.end(),
session.select) == session.visible.end())
session.select = session.visible[0];
session.box.hidden = false;
session.scroll = 0;
completion_adjust_scroll(session);
session.box.render_update();
}
void completion_request(Editor *editor) {
Coord hook = editor->cursor;
word_boundaries(editor, editor->cursor, &hook.col, nullptr, nullptr, nullptr);
editor->completion.hook = hook;
editor->completion.complete = false;
editor->completion.active = false;
editor->completion.items.clear();
editor->completion.visible.clear();
editor->completion.select = 0;
editor->completion.version = editor->lsp_version;
LSPPending *pending = new LSPPending();
pending->editor = editor;
pending->callback = [](Editor *editor, const json &message) {
auto &session = editor->completion;
std::unique_lock lock(session.mtx);
std::vector<json> items_json;
std::vector<char> end_chars_def;
int insert_text_format = 1;
int insert_text_mode = 1;
if (message.contains("result")) {
auto &result = message["result"];
if (result.is_array()) {
items_json = result.get<std::vector<json>>();
session.complete = true;
if (items_json.empty())
return;
editor->completion.active = true;
} else if (result.is_object() && result.contains("items")) {
auto &list = result;
items_json = list["items"].get<std::vector<json>>();
if (items_json.empty())
return;
editor->completion.active = true;
session.complete = !list.value("isIncomplete", false);
if (list.contains("itemDefaults") && list["itemDefaults"].is_object()) {
auto &defs = list["itemDefaults"];
if (defs.contains("insertTextFormat") &&
defs["insertTextFormat"].is_number())
insert_text_format = defs["insertTextFormat"].get<int>();
if (defs.contains("insertTextMode") &&
defs["insertTextMode"].is_number())
insert_text_mode = defs["insertTextMode"].get<int>();
if (defs.contains("textEdit"))
if (defs["textEdit"].is_array())
for (auto &c : defs["textEdit"]) {
if (!c.is_string())
continue;
std::string str = c.get<std::string>();
if (str.size() != 1)
continue;
end_chars_def.push_back(str[0]);
}
}
}
}
session.items.reserve(items_json.size() + 1);
session.visible.reserve(items_json.size() + 1);
for (auto &item_json : items_json) {
CompletionItem item;
item.original = item_json;
item.label = item_json.value("label", "");
item.kind = item_json.value("kind", 0);
if (item_json.contains("detail") && item_json["detail"].is_string())
item.detail = item_json["detail"].get<std::string>();
if (item_json.contains("documentation")) {
if (item_json["documentation"].is_string()) {
item.documentation = item_json["documentation"].get<std::string>();
} else if (item_json["documentation"].contains("value") &&
item_json["documentation"]["value"].is_string()) {
item.is_markup =
item_json["documentation"]["kind"].get<std::string>() ==
"markdown";
std::string documentation =
item_json["documentation"]["value"].get<std::string>();
if (documentation.size() > 1024)
item.is_markup = false;
if (item.is_markup) {
item.documentation =
substitute_fence(documentation, editor->lang.name);
} else {
item.documentation = documentation;
}
}
}
if (item_json.contains("deprecated") &&
item_json["deprecated"].is_boolean())
item.deprecated = item_json["deprecated"].get<bool>();
auto tags = item_json.value("tags", std::vector<int>());
for (auto tag : tags)
if (tag == 1)
item.deprecated = true;
item.sort = item_json.value("sortText", item.label);
item.filter = item_json.value("filterText", item.label);
if (item_json.contains("preselect") &&
item_json["preselect"].is_boolean() &&
item_json["preselect"].get<bool>())
session.select = session.items.size() - 1;
TextEdit edit;
if (item_json.contains("textEdit")) {
auto &te = item_json["textEdit"];
if (te.contains("newText")) {
edit.text = te.value("newText", "");
if (te.contains("replace")) {
edit.start.row = te["replace"]["start"]["line"];
edit.start.col = te["replace"]["start"]["character"];
edit.end.row = te["replace"]["end"]["line"];
edit.end.col = te["replace"]["end"]["character"];
} else if (te.contains("insert")) {
edit.start.row = te["insert"]["start"]["line"];
edit.start.col = te["insert"]["start"]["character"];
edit.end.row = te["insert"]["end"]["line"];
edit.end.col = te["insert"]["end"]["character"];
} else if (te.contains("range")) {
edit.start.row = te["range"]["start"]["line"];
edit.start.col = te["range"]["start"]["character"];
edit.end.row = te["range"]["end"]["line"];
edit.end.col = te["range"]["end"]["character"];
} else {
edit.start = session.hook;
edit.end = editor->cursor;
}
}
} else if (item_json.contains("insertText") &&
item_json["insertText"].is_string()) {
edit.text = item_json["insertText"].get<std::string>();
edit.start = session.hook;
edit.end = editor->cursor;
} else {
edit.text = item.label;
edit.start = session.hook;
edit.end = editor->cursor;
}
utf8_normalize_edit(editor, &edit);
item.edits.push_back(edit);
if (item_json.contains("additionalTextEdits")) {
for (auto &te : item_json["additionalTextEdits"]) {
TextEdit edit;
edit.text = te.value("newText", "");
edit.start.row = te["range"]["start"]["line"];
edit.start.col = te["range"]["start"]["character"];
edit.end.row = te["range"]["end"]["line"];
edit.end.col = te["range"]["end"]["character"];
utf8_normalize_edit(editor, &edit);
item.edits.push_back(edit);
}
}
item.snippet = insert_text_format == 2;
if (item_json.contains("insertTextFormat"))
item.snippet = item_json["insertTextFormat"].get<int>() == 2;
if (item_json.contains("insertTextMode"))
item.asis = item_json["insertTextMode"].get<int>() == 1;
if (item_json.contains("commitCharacters"))
for (auto &c : item_json["commitCharacters"])
if (c.is_string() && c.get<std::string>().size() == 1)
item.end_chars.push_back(c.get<std::string>()[0]);
session.items.push_back(std::move(item));
session.visible.push_back(session.items.size() - 1);
}
session.box.hidden = false;
session.box.render_update();
};
std::shared_lock lock(editor->knot_mtx);
LineIterator *it = begin_l_iter(editor->root, hook.row);
uint32_t length;
char *line = next_line(it, &length);
if (!line) {
free(it->buffer);
free(it);
return;
}
uint32_t col = utf8_offset_to_utf16(line, length, editor->cursor.col);
free(it->buffer);
free(it);
lock.unlock();
json message = {
{"jsonrpc", "2.0"},
{"method", "textDocument/completion"},
{"params",
{{"textDocument", {{"uri", editor->uri}}},
{"position", {{"line", editor->cursor.row}, {"character", col}}}}}};
if (editor->completion.trigger > 0) {
json context = {{"triggerKind", editor->completion.trigger}};
if (editor->completion.trigger == 2 && editor->completion.trigger_char)
context["triggerCharacter"] =
std::string(1, *editor->completion.trigger_char);
message["params"]["context"] = context;
}
lsp_send(editor->lsp, message, pending);
}
void handle_completion(Editor *editor, KeyEvent event) {
if (!editor->lsp || !editor->lsp->allow_completion)
return;
if (mode != INSERT) {
editor->completion.active = false;
return;
}
std::unique_lock lock(editor->completion.mtx);
if (event.key_type == KEY_PASTE) {
editor->completion.active = false;
return;
} else if (event.key_type == KEY_CHAR) {
char ch = *event.c;
if (!editor->completion.active) {
for (char c : editor->lsp->trigger_chars)
if (c == ch) {
editor->completion.trigger = 2;
editor->completion.trigger_char = c;
completion_request(editor);
return;
}
} else {
if (!editor->completion.items.empty()) {
const auto &item = editor->completion.items[editor->completion.select];
const std::vector<char> &end_chars =
item.end_chars.empty() ? editor->lsp->end_chars : item.end_chars;
for (char c : end_chars)
if (c == ch) {
complete_accept(editor);
return;
}
}
}
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
(ch >= '0' && ch <= '9') || ch == '_') {
if (editor->completion.active) {
if (editor->completion.complete)
completion_filter(editor);
else
completion_request(editor);
} else {
editor->completion.trigger = 3;
completion_request(editor);
}
} else if (ch == CTRL('\\')) {
if (editor->completion.active && !editor->completion.visible.empty()) {
complete_accept(editor);
} else {
editor->completion.trigger = 1;
completion_request(editor);
}
} else if (ch == CTRL('p')) {
if (editor->completion.active)
complete_next(editor);
} else if (ch == CTRL('o')) {
if (editor->completion.active)
complete_prev(editor);
} else if (ch == 0x7F || ch == 0x08 || ch == CTRL('W')) {
if (editor->completion.active) {
if (editor->completion.complete) {
if (editor->cursor <= editor->completion.hook)
editor->completion.active = false;
else
completion_filter(editor);
} else {
if (editor->cursor <= editor->completion.hook)
editor->completion.active = false;
else
completion_request(editor);
}
}
} else {
editor->completion.active = false;
}
} else if (event.key_type == KEY_MOUSE && event.mouse_modifier == 0) {
// Prolly remove mouse support here
// auto &box = editor->completion.box;
// if (event.mouse_y >= box.position.row &&
// event.mouse_x >= box.position.col) {
// uint32_t row = event.mouse_y - box.position.row;
// uint32_t col = event.mouse_x - box.position.col;
// if (row < box.size.row && col < box.size.col) {
// uint8_t idx = 0;
// /* TODO: fix index relative to scroll */
// complete_select(editor, idx);
// }
// }
// if it is being implemented then stop main event handler from processing
// when click inside the box
editor->completion.active = false;
} else {
editor->completion.active = false;
}
}
void completion_resolve_doc(Editor *editor) {
auto &item = editor->completion.items[editor->completion.select];
if (item.documentation)
return;
item.documentation = "";
LSPPending *pending = new LSPPending();
pending->editor = editor;
pending->callback = [](Editor *editor, const json &message) {
std::unique_lock lock(editor->completion.mtx);
auto &item = editor->completion.items[editor->completion.select];
if (message["result"].contains("documentation")) {
if (message["result"]["documentation"].is_string()) {
item.documentation =
message["result"]["documentation"].get<std::string>();
} else if (message["result"]["documentation"].contains("value") &&
message["result"]["documentation"]["value"].is_string()) {
item.is_markup =
message["result"]["documentation"]["kind"].get<std::string>() ==
"markdown";
std::string documentation =
message["result"]["documentation"]["value"].get<std::string>();
if (documentation.size() > 1024)
item.is_markup = false;
if (item.is_markup) {
item.documentation =
substitute_fence(documentation, editor->lang.name);
} else {
item.documentation = documentation;
}
}
}
editor->completion.box.render_update();
};
json message = {{"jsonrpc", "2.0"},
{"method", "completionItem/resolve"},
{"params", item.original}};
lsp_send(editor->lsp, message, pending);
}
void complete_accept(Editor *editor) {
if (!editor->completion.active || editor->completion.box.hidden)
return;
auto &item = editor->completion.items[editor->completion.select];
// TODO: support snippets and asis here
// once indentation engine is implemented
if (editor->completion.version != editor->lsp_version) {
int delta_col = 0;
TextEdit &e = item.edits[0];
if (e.end.row == editor->cursor.row) {
delta_col = editor->cursor.col - e.end.col;
e.end.col = editor->cursor.col;
for (size_t i = 1; i < item.edits.size(); ++i) {
TextEdit &e = item.edits[i];
if (e.start.row == editor->cursor.row) {
e.start.col += delta_col;
if (e.end.row == editor->cursor.row)
e.end.col += delta_col;
}
}
}
}
apply_lsp_edits(editor, item.edits, true);
editor->completion.active = false;
}
inline static int visible_index(const CompletionSession &s) {
for (size_t i = 0; i < s.visible.size(); ++i)
if (s.visible[i] == s.select)
return (int)i;
return -1;
}
void complete_next(Editor *editor) {
auto &s = editor->completion;
if (!s.active || s.box.hidden || s.visible.empty())
return;
int vi = visible_index(s);
if (vi < 0)
vi = 0;
else
vi = (vi + 1) % s.visible.size();
s.select = s.visible[vi];
completion_resolve_doc(editor);
completion_adjust_scroll(editor->completion);
editor->completion.box.render_update();
}
void complete_prev(Editor *editor) {
auto &s = editor->completion;
if (!s.active || s.box.hidden || s.visible.empty())
return;
int vi = visible_index(s);
if (vi < 0)
vi = 0;
else
vi = (vi + s.visible.size() - 1) % s.visible.size();
s.select = s.visible[vi];
completion_resolve_doc(editor);
completion_adjust_scroll(editor->completion);
editor->completion.box.render_update();
}
void complete_select(Editor *editor, uint8_t index) {
editor->completion.select = index;
complete_accept(editor);
}
// #include "editor/decl.h"
// #include "editor/editor.h"
// #include "io/knot.h"
// #include "io/sysio.h"
// #include "lsp/lsp.h"
// #include "main.h"
// #include "ui/completionbox.h"
// #include "utils/utils.h"
//
// inline static std::string completion_prefix(Editor *editor) {
// Coord hook = editor->completion.hook;
// Coord cur = editor->cursor;
// if (hook.row != cur.row || cur.col < hook.col)
// return "";
// LineIterator *it = begin_l_iter(editor->root, hook.row);
// uint32_t line_len;
// char *line = next_line(it, &line_len);
// if (!line) {
// free(it->buffer);
// free(it);
// return "";
// }
// std::string prefix(line + hook.col, cur.col - hook.col);
// free(it->buffer);
// free(it);
// return prefix;
// }
//
// inline static void completion_adjust_scroll(CompletionSession &s) {
// if (s.visible.empty())
// return;
// int vi = -1;
// for (size_t i = 0; i < s.visible.size(); i++)
// if (s.visible[i] == s.select) {
// vi = (int)i;
// break;
// }
// if (vi < 0)
// return;
// if ((uint32_t)vi < s.scroll)
// s.scroll = vi;
// else if ((uint32_t)vi >= s.scroll + 8)
// s.scroll = vi - 7;
// }
//
// void completion_filter(Editor *editor) {
// auto &session = editor->completion;
// std::string prefix = completion_prefix(editor);
// session.visible.clear();
// for (size_t i = 0; i < session.items.size(); ++i) {
// const auto &item = session.items[i];
// const std::string &key = item.filter;
// if (key.size() >= prefix.size() &&
// key.compare(0, prefix.size(), prefix) == 0)
// session.visible.push_back(i);
// }
// if (session.visible.empty()) {
// session.box.hidden = true;
// return;
// }
// if (std::find(session.visible.begin(), session.visible.end(),
// session.select) == session.visible.end())
// session.select = session.visible[0];
// session.box.hidden = false;
// session.scroll = 0;
// completion_adjust_scroll(session);
// session.box.render_update();
// }
//
// void completion_request(Editor *editor) {
// Coord hook = editor->cursor;
// editor->word_boundaries(editor->cursor, &hook.col, nullptr, nullptr,
// nullptr); editor->completion.hook = hook; editor->completion.complete =
// false; editor->completion.active = false; editor->completion.items.clear();
// editor->completion.visible.clear();
// editor->completion.select = 0;
// editor->completion.version = editor->lsp_version;
// LSPPending *pending = new LSPPending();
// pending->editor = editor;
// pending->callback = [](Editor *editor, const json &message) {
// auto &session = editor->completion;
// std::unique_lock lock(session.mtx);
// std::vector<json> items_json;
// std::vector<char> end_chars_def;
// int insert_text_format = 1;
// int insert_text_mode = 1;
// if (message.contains("result")) {
// auto &result = message["result"];
// if (result.is_array()) {
// items_json = result.get<std::vector<json>>();
// session.complete = true;
// if (items_json.empty())
// return;
// editor->completion.active = true;
// } else if (result.is_object() && result.contains("items")) {
// auto &list = result;
// items_json = list["items"].get<std::vector<json>>();
// if (items_json.empty())
// return;
// editor->completion.active = true;
// session.complete = !list.value("isIncomplete", false);
// if (list.contains("itemDefaults") &&
// list["itemDefaults"].is_object()) {
// auto &defs = list["itemDefaults"];
// if (defs.contains("insertTextFormat") &&
// defs["insertTextFormat"].is_number())
// insert_text_format = defs["insertTextFormat"].get<int>();
// if (defs.contains("insertTextMode") &&
// defs["insertTextMode"].is_number())
// insert_text_mode = defs["insertTextMode"].get<int>();
// if (defs.contains("textEdit"))
// if (defs["textEdit"].is_array())
// for (auto &c : defs["textEdit"]) {
// if (!c.is_string())
// continue;
// std::string str = c.get<std::string>();
// if (str.size() != 1)
// continue;
// end_chars_def.push_back(str[0]);
// }
// }
// }
// }
// session.items.reserve(items_json.size() + 1);
// session.visible.reserve(items_json.size() + 1);
// for (auto &item_json : items_json) {
// CompletionItem item;
// item.original = item_json;
// item.label = item_json.value("label", "");
// item.kind = item_json.value("kind", 0);
// if (item_json.contains("detail") && item_json["detail"].is_string())
// item.detail = item_json["detail"].get<std::string>();
// if (item_json.contains("documentation")) {
// if (item_json["documentation"].is_string()) {
// item.documentation = item_json["documentation"].get<std::string>();
// } else if (item_json["documentation"].contains("value") &&
// item_json["documentation"]["value"].is_string()) {
// item.is_markup =
// item_json["documentation"]["kind"].get<std::string>() ==
// "markdown";
// std::string documentation =
// item_json["documentation"]["value"].get<std::string>();
// if (documentation.size() > 1024)
// item.is_markup = false;
// if (item.is_markup) {
// item.documentation =
// substitute_fence(documentation, editor->lang.name);
// } else {
// item.documentation = documentation;
// }
// }
// }
// if (item_json.contains("deprecated") &&
// item_json["deprecated"].is_boolean())
// item.deprecated = item_json["deprecated"].get<bool>();
// auto tags = item_json.value("tags", std::vector<int>());
// for (auto tag : tags)
// if (tag == 1)
// item.deprecated = true;
// item.sort = item_json.value("sortText", item.label);
// item.filter = item_json.value("filterText", item.label);
// if (item_json.contains("preselect") &&
// item_json["preselect"].is_boolean() &&
// item_json["preselect"].get<bool>())
// session.select = session.items.size() - 1;
// TextEdit edit;
// if (item_json.contains("textEdit")) {
// auto &te = item_json["textEdit"];
// if (te.contains("newText")) {
// edit.text = te.value("newText", "");
// if (te.contains("replace")) {
// edit.start.row = te["replace"]["start"]["line"];
// edit.start.col = te["replace"]["start"]["character"];
// edit.end.row = te["replace"]["end"]["line"];
// edit.end.col = te["replace"]["end"]["character"];
// } else if (te.contains("insert")) {
// edit.start.row = te["insert"]["start"]["line"];
// edit.start.col = te["insert"]["start"]["character"];
// edit.end.row = te["insert"]["end"]["line"];
// edit.end.col = te["insert"]["end"]["character"];
// } else if (te.contains("range")) {
// edit.start.row = te["range"]["start"]["line"];
// edit.start.col = te["range"]["start"]["character"];
// edit.end.row = te["range"]["end"]["line"];
// edit.end.col = te["range"]["end"]["character"];
// } else {
// edit.start = session.hook;
// edit.end = editor->cursor;
// }
// }
// } else if (item_json.contains("insertText") &&
// item_json["insertText"].is_string()) {
// edit.text = item_json["insertText"].get<std::string>();
// edit.start = session.hook;
// edit.end = editor->cursor;
// } else {
// edit.text = item.label;
// edit.start = session.hook;
// edit.end = editor->cursor;
// }
// editor->utf8_normalize_edit(&edit);
// item.edits.push_back(edit);
// if (item_json.contains("additionalTextEdits")) {
// for (auto &te : item_json["additionalTextEdits"]) {
// TextEdit edit;
// edit.text = te.value("newText", "");
// edit.start.row = te["range"]["start"]["line"];
// edit.start.col = te["range"]["start"]["character"];
// edit.end.row = te["range"]["end"]["line"];
// edit.end.col = te["range"]["end"]["character"];
// editor->utf8_normalize_edit(&edit);
// item.edits.push_back(edit);
// }
// }
// item.snippet = insert_text_format == 2;
// if (item_json.contains("insertTextFormat"))
// item.snippet = item_json["insertTextFormat"].get<int>() == 2;
// if (item_json.contains("insertTextMode"))
// item.asis = item_json["insertTextMode"].get<int>() == 1;
// if (item_json.contains("commitCharacters"))
// for (auto &c : item_json["commitCharacters"])
// if (c.is_string() && c.get<std::string>().size() == 1)
// item.end_chars.push_back(c.get<std::string>()[0]);
// session.items.push_back(std::move(item));
// session.visible.push_back(session.items.size() - 1);
// }
// session.box.hidden = false;
// session.box.render_update();
// };
// LineIterator *it = begin_l_iter(editor->root, hook.row);
// uint32_t length;
// char *line = next_line(it, &length);
// if (!line) {
// free(it->buffer);
// free(it);
// return;
// }
// uint32_t col = utf8_offset_to_utf16(line, length, editor->cursor.col);
// free(it->buffer);
// free(it);
// json message = {
// {"jsonrpc", "2.0"},
// {"method", "textDocument/completion"},
// {"params",
// {{"textDocument", {{"uri", editor->uri}}},
// {"position", {{"line", editor->cursor.row}, {"character", col}}}}}};
// if (editor->completion.trigger > 0) {
// json context = {{"triggerKind", editor->completion.trigger}};
// if (editor->completion.trigger == 2 && editor->completion.trigger_char)
// context["triggerCharacter"] =
// std::string(1, *editor->completion.trigger_char);
// message["params"]["context"] = context;
// }
// lsp_send(editor->lsp, message, pending);
// }
//
// // Move this into the box and merge the box and this guy
// void CompletionSession::handle(KeyEvent event) {
// if (!editor->lsp || !editor->lsp->allow_completion)
// return;
// if (mode != INSERT) {
// this->active = false;
// return;
// }
// std::unique_lock lock(this->mtx);
// if (event.key_type == KEY_PASTE) {
// this->active = false;
// return;
// } else if (event.key_type == KEY_CHAR) {
// char ch = *event.c;
// if (!this->active) {
// for (char c : editor->lsp->trigger_chars)
// if (c == ch) {
// this->trigger = 2;
// this->trigger_char = c;
// completion_request(editor);
// return;
// }
// } else {
// if (!editor->completion.items.empty()) {
// const auto &item =
// editor->completion.items[editor->completion.select]; const
// std::vector<char> &end_chars =
// item.end_chars.empty() ? editor->lsp->end_chars : item.end_chars;
// for (char c : end_chars)
// if (c == ch) {
// this->accept();
// return;
// }
// }
// }
// if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
// (ch >= '0' && ch <= '9') || ch == '_') {
// if (this->active) {
// if (this->complete)
// completion_filter(editor);
// else
// completion_request(editor);
// } else {
// this->trigger = 3;
// completion_request(editor);
// }
// } else if (ch == CTRL('\\')) {
// if (this->active && !this->visible.empty()) {
// this->accept();
// } else {
// this->trigger = 1;
// completion_request(editor);
// }
// } else if (ch == CTRL('p')) {
// if (this->active)
// this->next();
// } else if (ch == CTRL('o')) {
// if (this->active)
// this->prev();
// } else if (ch == 0x7F || ch == 0x08 || ch == CTRL('W')) {
// if (this->active) {
// if (this->complete) {
// if (editor->cursor <= this->hook)
// this->active = false;
// else
// completion_filter(editor);
// } else {
// if (editor->cursor <= this->hook)
// this->active = false;
// else
// completion_request(editor);
// }
// }
// } else {
// this->active = false;
// }
// } else if (event.key_type == KEY_MOUSE && event.mouse_modifier == 0) {
// // Prolly add mouse support here
// // auto &box = this->box;
// // if (event.mouse_y >= box.position.row &&
// // event.mouse_x >= box.position.col) {
// // uint32_t row = event.mouse_y - box.position.row;
// // uint32_t col = event.mouse_x - box.position.col;
// // if (row < box.size.row && col < box.size.col) {
// // uint8_t idx = 0;
// // /* TODO: fix index relative to scroll */
// // complete_select(editor, idx);
// // }
// // }
// // if it is being implemented then stop main event handler from
// processing
// // when click inside the box
// this->active = false;
// } else {
// this->active = false;
// }
// }
//
// void CompletionSession::resolve_doc() {
// auto &item = this->items[this->select];
// if (item.documentation)
// return;
// item.documentation = "";
// LSPPending *pending = new LSPPending();
// pending->editor = editor;
// pending->callback = [](Editor *editor, const json &message) {
// std::unique_lock lock(editor->completion.mtx);
// auto &item = editor->completion.items[editor->completion.select];
// if (message["result"].contains("documentation")) {
// if (message["result"]["documentation"].is_string()) {
// item.documentation =
// message["result"]["documentation"].get<std::string>();
// } else if (message["result"]["documentation"].contains("value") &&
// message["result"]["documentation"]["value"].is_string()) {
// item.is_markup =
// message["result"]["documentation"]["kind"].get<std::string>() ==
// "markdown";
// std::string documentation =
// message["result"]["documentation"]["value"].get<std::string>();
// if (documentation.size() > 1024)
// item.is_markup = false;
// if (item.is_markup) {
// item.documentation =
// substitute_fence(documentation, editor->lang.name);
// } else {
// item.documentation = documentation;
// }
// }
// }
// editor->completion.box.render_update();
// };
// json message = {{"jsonrpc", "2.0"},
// {"method", "completionItem/resolve"},
// {"params", item.original}};
// lsp_send(editor->lsp, message, pending);
// }
//
// void CompletionSession::accept() {
// if (!this->active || this->box.hidden)
// return;
// auto &item = this->items[this->select];
// // TODO: support snippets and asis here
// // once indentation engine is implemented
// if (this->version != editor->lsp_version) {
// int delta_col = 0;
// TextEdit &e = item.edits[0];
// if (e.end.row == editor->cursor.row) {
// delta_col = editor->cursor.col - e.end.col;
// e.end.col = editor->cursor.col;
// for (size_t i = 1; i < item.edits.size(); ++i) {
// TextEdit &e = item.edits[i];
// if (e.start.row == editor->cursor.row) {
// e.start.col += delta_col;
// if (e.end.row == editor->cursor.row)
// e.end.col += delta_col;
// }
// }
// }
// }
// editor->apply_lsp_edits(item.edits, true);
// this->active = false;
// }
//
// inline static int visible_index(const CompletionSession &s) {
// for (size_t i = 0; i < s.visible.size(); ++i)
// if (s.visible[i] == s.select)
// return (int)i;
// return -1;
// }
//
// void CompletionSession::next() {
// if (!this->active || this->box.hidden || this->visible.empty())
// return;
// int vi = visible_index(*this);
// if (vi < 0)
// vi = 0;
// else
// vi = (vi + 1) % this->visible.size();
// this->select = this->visible[vi];
// this->resolve_doc();
// completion_adjust_scroll(*this);
// this->box.render_update();
// }
//
// void CompletionSession::prev() {
// if (!this->active || this->box.hidden || this->visible.empty())
// return;
// int vi = visible_index(*this);
// if (vi < 0)
// vi = 0;
// else
// vi = (vi + this->visible.size() - 1) % this->visible.size();
// this->select = this->visible[vi];
// this->resolve_doc();
// completion_adjust_scroll(*this);
// this->box.render_update();
// }
//
// void CompletionSession::choose(uint8_t index) {
// this->select = index;
// this->accept();
// }

View File

@@ -1,14 +1,14 @@
#include "editor/editor.h"
#include "utils/utils.h"
Coord move_right(Editor *editor, Coord cursor, uint32_t number) {
Coord Editor::move_right(Coord cursor, uint32_t number) {
Coord result = cursor;
if (!editor || !editor->root || number == 0)
if (!this->root || number == 0)
return result;
uint32_t row = result.row;
uint32_t col = result.col;
uint32_t line_len = 0;
LineIterator *it = begin_l_iter(editor->root, row);
LineIterator *it = begin_l_iter(this->root, row);
if (!it)
return result;
char *line = next_line(it, &line_len);
@@ -22,7 +22,7 @@ Coord move_right(Editor *editor, Coord cursor, uint32_t number) {
while (number > 0) {
if (col >= line_len) {
uint32_t next_row = row + 1;
if (next_row >= editor->root->line_count) {
if (next_row >= this->root->line_count) {
col = line_len;
break;
}
@@ -49,14 +49,16 @@ Coord move_right(Editor *editor, Coord cursor, uint32_t number) {
return result;
}
Coord move_left(Editor *editor, Coord cursor, uint32_t number) {
Coord Editor::move_left(Coord cursor, uint32_t number) {
Coord result = cursor;
if (!editor || !editor->root || number == 0)
if (!this->root || number == 0)
return result;
uint32_t row = result.row;
uint32_t col = result.col;
uint32_t len = 0;
LineIterator *it = begin_l_iter(editor->root, row);
LineIterator *it = begin_l_iter(this->root, row);
if (!it)
return result;
char *line = next_line(it, &len);
if (!line) {
free(it->buffer);
@@ -102,29 +104,28 @@ Coord move_left(Editor *editor, Coord cursor, uint32_t number) {
return result;
}
void cursor_down(Editor *editor, uint32_t number) {
if (!editor || !editor->root || number == 0)
void Editor::cursor_down(uint32_t number) {
if (!this->root || number == 0)
return;
uint32_t visual_col = editor->cursor_preffered;
uint32_t visual_col = this->cursor_preffered;
if (visual_col == UINT32_MAX) {
uint32_t len;
LineIterator *it = begin_l_iter(editor->root, editor->cursor.row);
LineIterator *it = begin_l_iter(this->root, this->cursor.row);
char *line = next_line(it, &len);
if (!line) {
free(it->buffer);
free(it);
return;
}
editor->cursor_preffered =
get_visual_col_from_bytes(line, len, editor->cursor.col);
visual_col = editor->cursor_preffered;
this->cursor_preffered =
get_visual_col_from_bytes(line, len, this->cursor.col);
visual_col = this->cursor_preffered;
free(it->buffer);
free(it);
}
editor->cursor.row =
MIN(editor->cursor.row + number, editor->root->line_count - 1);
this->cursor.row = MIN(this->cursor.row + number, this->root->line_count - 1);
uint32_t len;
LineIterator *it = begin_l_iter(editor->root, editor->cursor.row);
LineIterator *it = begin_l_iter(this->root, this->cursor.row);
char *line = next_line(it, &len);
if (!line) {
free(it->buffer);
@@ -133,26 +134,26 @@ void cursor_down(Editor *editor, uint32_t number) {
}
if (len > 0 && line[len - 1] == '\n')
--len;
editor->cursor.col = get_bytes_from_visual_col(line, len, visual_col);
this->cursor.col = get_bytes_from_visual_col(line, len, visual_col);
free(it->buffer);
free(it);
}
void cursor_up(Editor *editor, uint32_t number) {
if (!editor || !editor->root || number == 0 || editor->cursor.row == 0)
void Editor::cursor_up(uint32_t number) {
if (!this->root || number == 0 || this->cursor.row == 0)
return;
uint32_t len;
LineIterator *it = begin_l_iter(editor->root, editor->cursor.row);
LineIterator *it = begin_l_iter(this->root, this->cursor.row);
char *line_content = next_line(it, &len);
if (!line_content)
return;
if (editor->cursor_preffered == UINT32_MAX)
editor->cursor_preffered =
get_visual_col_from_bytes(line_content, len, editor->cursor.col);
uint32_t visual_col = editor->cursor_preffered;
if (this->cursor_preffered == UINT32_MAX)
this->cursor_preffered =
get_visual_col_from_bytes(line_content, len, this->cursor.col);
uint32_t visual_col = this->cursor_preffered;
free(it->buffer);
free(it);
uint32_t target_row = editor->cursor.row;
uint32_t target_row = this->cursor.row;
while (number > 0 && target_row > 0) {
target_row--;
if (target_row == 0) {
@@ -161,32 +162,31 @@ void cursor_up(Editor *editor, uint32_t number) {
}
number--;
}
it = begin_l_iter(editor->root, target_row);
it = begin_l_iter(this->root, target_row);
line_content = next_line(it, &len);
if (line_content) {
if (len > 0 && line_content[len - 1] == '\n')
--len;
editor->cursor.row = target_row;
editor->cursor.col =
get_bytes_from_visual_col(line_content, len, visual_col);
this->cursor.row = target_row;
this->cursor.col = get_bytes_from_visual_col(line_content, len, visual_col);
} else {
editor->cursor.row = 0;
editor->cursor.col = 0;
this->cursor.row = 0;
this->cursor.col = 0;
}
free(it->buffer);
free(it);
}
void cursor_right(Editor *editor, uint32_t number) {
if (!editor || !editor->root || number == 0)
void Editor::cursor_right(uint32_t number) {
if (!this->root || number == 0)
return;
editor->cursor = move_right(editor, editor->cursor, number);
editor->cursor_preffered = UINT32_MAX;
this->cursor = this->move_right(this->cursor, number);
this->cursor_preffered = UINT32_MAX;
}
void cursor_left(Editor *editor, uint32_t number) {
if (!editor || !editor->root || number == 0)
void Editor::cursor_left(uint32_t number) {
if (!this->root || number == 0)
return;
editor->cursor = move_left(editor, editor->cursor, number);
editor->cursor_preffered = UINT32_MAX;
this->cursor = this->move_left(this->cursor, number);
this->cursor_preffered = UINT32_MAX;
}

View File

@@ -2,20 +2,18 @@
#include "lsp/lsp.h"
#include "utils/utils.h"
void edit_erase(Editor *editor, Coord pos, int64_t len) {
void Editor::edit_erase(Coord pos, int64_t len) {
if (len == 0)
return;
if (len < 0) {
std::shared_lock lock_1(editor->knot_mtx);
uint32_t cursor_original =
line_to_byte(editor->root, editor->cursor.row, nullptr) +
editor->cursor.col;
uint32_t byte_pos = line_to_byte(editor->root, pos.row, nullptr) + pos.col;
Coord point = move_left(editor, pos, -len);
line_to_byte(this->root, this->cursor.row, nullptr) + this->cursor.col;
uint32_t byte_pos = line_to_byte(this->root, pos.row, nullptr) + pos.col;
Coord point = this->move_left(pos, -len);
json lsp_range;
bool do_lsp = (editor->lsp != nullptr);
bool do_lsp = (this->lsp != nullptr);
if (do_lsp) {
LineIterator *it = begin_l_iter(editor->root, point.row);
LineIterator *it = begin_l_iter(this->root, point.row);
uint32_t len;
char *line = next_line(it, &len);
int utf16_start = 0;
@@ -23,7 +21,7 @@ void edit_erase(Editor *editor, Coord pos, int64_t len) {
utf16_start = utf8_offset_to_utf16(line, len, point.col);
free(it->buffer);
free(it);
it = begin_l_iter(editor->root, pos.row);
it = begin_l_iter(this->root, pos.row);
line = next_line(it, &len);
int utf16_end = 0;
if (line)
@@ -33,62 +31,58 @@ void edit_erase(Editor *editor, Coord pos, int64_t len) {
lsp_range = {{"start", {{"line", point.row}, {"character", utf16_start}}},
{"end", {{"line", pos.row}, {"character", utf16_end}}}};
}
uint32_t start = line_to_byte(editor->root, point.row, nullptr) + point.col;
uint32_t start = line_to_byte(this->root, point.row, nullptr) + point.col;
if (cursor_original > start && cursor_original <= byte_pos) {
editor->cursor = point;
editor->cursor_preffered = UINT32_MAX;
this->cursor = point;
this->cursor_preffered = UINT32_MAX;
} else if (cursor_original > byte_pos) {
uint32_t cursor_new = cursor_original - (byte_pos - start);
uint32_t new_col;
uint32_t new_row = byte_to_line(editor->root, cursor_new, &new_col);
editor->cursor = {new_row, new_col};
editor->cursor_preffered = UINT32_MAX;
uint32_t new_row = byte_to_line(this->root, cursor_new, &new_col);
this->cursor = {new_row, new_col};
this->cursor_preffered = UINT32_MAX;
}
lock_1.unlock();
uint32_t start_row = point.row;
uint32_t end_row = pos.row;
apply_hook_deletion(editor, start_row + 1, end_row);
std::unique_lock lock_2(editor->knot_mtx);
editor->root = erase(editor->root, start, byte_pos - start);
lock_2.unlock();
if (editor->parser)
editor->parser->edit(start_row, end_row - start_row, 0);
this->apply_hook_deletion(start_row + 1, end_row);
this->root = erase(this->root, start, byte_pos - start);
if (this->parser)
this->parser->edit(start_row, end_row - start_row, 0);
if (do_lsp) {
if (editor->lsp->incremental_sync) {
json message = {
{"jsonrpc", "2.0"},
auto lsp = this->lsp.load();
if (lsp->incremental_sync) {
auto message = std::make_unique<LSPMessage>();
message->message = {
{"method", "textDocument/didChange"},
{"params",
{{"textDocument",
{{"uri", editor->uri}, {"version", ++editor->lsp_version}}},
{{"uri", this->uri}, {"version", ++this->lsp_version}}},
{"contentChanges",
json::array({{{"range", lsp_range}, {"text", ""}}})}}}};
lsp_send(editor->lsp, message, nullptr);
lsp->send(std::move(message));
} else {
char *buf = read(editor->root, 0, editor->root->char_count);
char *buf = read(this->root, 0, this->root->char_count);
std::string text(buf);
free(buf);
json message = {
{"jsonrpc", "2.0"},
auto message = std::make_unique<LSPMessage>();
message->message = {
{"method", "textDocument/didChange"},
{"params",
{{"textDocument",
{{"uri", editor->uri}, {"version", ++editor->lsp_version}}},
{{"uri", this->uri}, {"version", ++this->lsp_version}}},
{"contentChanges", json::array({{{"text", text}}})}}}};
lsp_send(editor->lsp, message, nullptr);
lsp->send(std::move(message));
}
}
} else {
std::shared_lock lock_1(editor->knot_mtx);
uint32_t cursor_original =
line_to_byte(editor->root, editor->cursor.row, nullptr) +
editor->cursor.col;
uint32_t byte_pos = line_to_byte(editor->root, pos.row, nullptr) + pos.col;
Coord point = move_right(editor, pos, len);
line_to_byte(this->root, this->cursor.row, nullptr) + this->cursor.col;
uint32_t byte_pos = line_to_byte(this->root, pos.row, nullptr) + pos.col;
Coord point = this->move_right(pos, len);
json lsp_range;
bool do_lsp = (editor->lsp != nullptr);
bool do_lsp = (this->lsp != nullptr);
if (do_lsp) {
LineIterator *it = begin_l_iter(editor->root, pos.row);
LineIterator *it = begin_l_iter(this->root, pos.row);
uint32_t line_len;
char *line = next_line(it, &line_len);
int utf16_start = 0;
@@ -96,7 +90,7 @@ void edit_erase(Editor *editor, Coord pos, int64_t len) {
utf16_start = utf8_offset_to_utf16(line, line_len, pos.col);
free(it->buffer);
free(it);
it = begin_l_iter(editor->root, point.row);
it = begin_l_iter(this->root, point.row);
line = next_line(it, &line_len);
int utf16_end = 0;
if (line)
@@ -106,67 +100,63 @@ void edit_erase(Editor *editor, Coord pos, int64_t len) {
lsp_range = {{"start", {{"line", pos.row}, {"character", utf16_start}}},
{"end", {{"line", point.row}, {"character", utf16_end}}}};
}
uint32_t end = line_to_byte(editor->root, point.row, nullptr) + point.col;
uint32_t end = line_to_byte(this->root, point.row, nullptr) + point.col;
if (cursor_original > byte_pos && cursor_original <= end) {
editor->cursor = pos;
editor->cursor_preffered = UINT32_MAX;
this->cursor = pos;
this->cursor_preffered = UINT32_MAX;
} else if (cursor_original > end) {
uint32_t cursor_new = cursor_original - (end - byte_pos);
uint32_t new_col;
uint32_t new_row = byte_to_line(editor->root, cursor_new, &new_col);
editor->cursor = {new_row, new_col};
editor->cursor_preffered = UINT32_MAX;
uint32_t new_row = byte_to_line(this->root, cursor_new, &new_col);
this->cursor = {new_row, new_col};
this->cursor_preffered = UINT32_MAX;
}
lock_1.unlock();
uint32_t start_row = pos.row;
uint32_t end_row = point.row;
apply_hook_deletion(editor, start_row + 1, end_row);
std::unique_lock lock_2(editor->knot_mtx);
editor->root = erase(editor->root, byte_pos, end - byte_pos);
lock_2.unlock();
if (editor->parser)
editor->parser->edit(start_row, end_row - start_row, 0);
this->apply_hook_deletion(start_row + 1, end_row);
this->root = erase(this->root, byte_pos, end - byte_pos);
if (this->parser)
this->parser->edit(start_row, end_row - start_row, 0);
if (do_lsp) {
if (editor->lsp->incremental_sync) {
json message = {
{"jsonrpc", "2.0"},
auto lsp = this->lsp.load();
if (lsp->incremental_sync) {
auto message = std::make_unique<LSPMessage>();
message->message = {
{"method", "textDocument/didChange"},
{"params",
{{"textDocument",
{{"uri", editor->uri}, {"version", ++editor->lsp_version}}},
{{"uri", this->uri}, {"version", ++this->lsp_version}}},
{"contentChanges",
json::array({{{"range", lsp_range}, {"text", ""}}})}}}};
lsp_send(editor->lsp, message, nullptr);
lsp->send(std::move(message));
} else {
char *buf = read(editor->root, 0, editor->root->char_count);
char *buf = read(this->root, 0, this->root->char_count);
std::string text(buf);
free(buf);
json message = {
{"jsonrpc", "2.0"},
auto message = std::make_unique<LSPMessage>();
message->message = {
{"method", "textDocument/didChange"},
{"params",
{{"textDocument",
{{"uri", editor->uri}, {"version", ++editor->lsp_version}}},
{{"uri", this->uri}, {"version", ++this->lsp_version}}},
{"contentChanges", json::array({{{"text", text}}})}}}};
lsp_send(editor->lsp, message, nullptr);
lsp->send(std::move(message));
}
}
}
}
void edit_insert(Editor *editor, Coord pos, char *data, uint32_t len) {
std::shared_lock lock_1(editor->knot_mtx);
void Editor::edit_insert(Coord pos, char *data, uint32_t len) {
uint32_t cursor_original =
line_to_byte(editor->root, editor->cursor.row, nullptr) +
editor->cursor.col;
uint32_t byte_pos = line_to_byte(editor->root, pos.row, nullptr) + pos.col;
line_to_byte(this->root, this->cursor.row, nullptr) + this->cursor.col;
uint32_t byte_pos = line_to_byte(this->root, pos.row, nullptr) + pos.col;
if (cursor_original > byte_pos) {
uint32_t cursor_new = cursor_original + len;
uint32_t new_col;
uint32_t new_row = byte_to_line(editor->root, cursor_new, &new_col);
editor->cursor = {new_row, new_col};
uint32_t new_row = byte_to_line(this->root, cursor_new, &new_col);
this->cursor = {new_row, new_col};
}
LineIterator *it = begin_l_iter(editor->root, pos.row);
LineIterator *it = begin_l_iter(this->root, pos.row);
uint32_t line_len;
char *line = next_line(it, &line_len);
int utf16_col = 0;
@@ -174,55 +164,52 @@ void edit_insert(Editor *editor, Coord pos, char *data, uint32_t len) {
utf16_col = utf8_offset_to_utf16(line, line_len, pos.col);
free(it->buffer);
free(it);
lock_1.unlock();
std::unique_lock lock_2(editor->knot_mtx);
editor->root = insert(editor->root, byte_pos, data, len);
this->root = insert(this->root, byte_pos, data, len);
uint32_t rows = 0;
for (uint32_t i = 0; i < len; i++)
if (data[i] == '\n')
rows++;
apply_hook_insertion(editor, pos.row, rows);
lock_2.unlock();
if (editor->parser)
editor->parser->edit(pos.row, 0, rows);
if (editor->lsp) {
if (editor->lsp->incremental_sync) {
json message = {
{"jsonrpc", "2.0"},
this->apply_hook_insertion(pos.row, rows);
if (this->parser)
this->parser->edit(pos.row, 0, rows);
auto lsp = this->lsp.load();
if (lsp) {
if (lsp->incremental_sync) {
auto message = std::make_unique<LSPMessage>();
message->message = {
{"method", "textDocument/didChange"},
{"params",
{{"textDocument",
{{"uri", editor->uri}, {"version", ++editor->lsp_version}}},
{{"uri", this->uri}, {"version", ++this->lsp_version}}},
{"contentChanges",
json::array(
{{{"range",
{{"start", {{"line", pos.row}, {"character", utf16_col}}},
{"end", {{"line", pos.row}, {"character", utf16_col}}}}},
{"text", std::string(data, len)}}})}}}};
lsp_send(editor->lsp, message, nullptr);
lsp->send(std::move(message));
} else {
char *buf = read(editor->root, 0, editor->root->char_count);
char *buf = read(this->root, 0, this->root->char_count);
std::string text(buf);
free(buf);
json message = {
{"jsonrpc", "2.0"},
auto message = std::make_unique<LSPMessage>();
message->message = {
{"method", "textDocument/didChange"},
{"params",
{{"textDocument",
{{"uri", editor->uri}, {"version", ++editor->lsp_version}}},
{{"uri", this->uri}, {"version", ++this->lsp_version}}},
{"contentChanges", json::array({{{"text", text}}})}}}};
lsp_send(editor->lsp, message, nullptr);
lsp->send(std::move(message));
}
}
}
void edit_replace(Editor *editor, Coord start, Coord end, const char *text,
uint32_t len) {
std::unique_lock lock(editor->knot_mtx);
void Editor::edit_replace(Coord start, Coord end, const char *text,
uint32_t len) {
uint32_t start_byte =
line_to_byte(editor->root, start.row, nullptr) + start.col;
uint32_t end_byte = line_to_byte(editor->root, end.row, nullptr) + end.col;
LineIterator *it = begin_l_iter(editor->root, start.row);
line_to_byte(this->root, start.row, nullptr) + start.col;
uint32_t end_byte = line_to_byte(this->root, end.row, nullptr) + end.col;
LineIterator *it = begin_l_iter(this->root, start.row);
uint32_t line_len;
char *line = next_line(it, &line_len);
int utf16_start = 0;
@@ -230,7 +217,7 @@ void edit_replace(Editor *editor, Coord start, Coord end, const char *text,
utf16_start = utf8_offset_to_utf16(line, line_len, start.col);
free(it->buffer);
free(it);
it = begin_l_iter(editor->root, end.row);
it = begin_l_iter(this->root, end.row);
line = next_line(it, &line_len);
int utf16_end = 0;
if (line)
@@ -238,25 +225,26 @@ void edit_replace(Editor *editor, Coord start, Coord end, const char *text,
free(it->buffer);
free(it);
if (start_byte != end_byte)
editor->root = erase(editor->root, start_byte, end_byte - start_byte);
this->root = erase(this->root, start_byte, end_byte - start_byte);
if (len > 0)
editor->root = insert(editor->root, start_byte, (char *)text, len);
this->root = insert(this->root, start_byte, (char *)text, len);
uint32_t rows = 0;
for (uint32_t i = 0; i < len; i++)
if (text[i] == '\n')
rows++;
if (rows > 0)
rows--;
if (editor->parser)
editor->parser->edit(start.row, end.row - start.row, rows);
if (editor->lsp) {
if (editor->lsp->incremental_sync) {
json message = {
{"jsonrpc", "2.0"},
if (this->parser)
this->parser->edit(start.row, end.row - start.row, rows);
auto lsp = this->lsp.load();
if (lsp) {
if (lsp->incremental_sync) {
auto message = std::make_unique<LSPMessage>();
message->message = {
{"method", "textDocument/didChange"},
{"params",
{{"textDocument",
{{"uri", editor->uri}, {"version", ++editor->lsp_version}}},
{{"uri", this->uri}, {"version", ++this->lsp_version}}},
{"contentChanges",
json::array(
{{{"range",
@@ -264,19 +252,19 @@ void edit_replace(Editor *editor, Coord start, Coord end, const char *text,
{{"line", start.row}, {"character", utf16_start}}},
{"end", {{"line", end.row}, {"character", utf16_end}}}}},
{"text", std::string(text, len)}}})}}}};
lsp_send(editor->lsp, message, nullptr);
lsp->send(std::move(message));
} else {
char *buf = read(editor->root, 0, editor->root->char_count);
char *buf = read(this->root, 0, this->root->char_count);
std::string full_text(buf);
free(buf);
json message = {
{"jsonrpc", "2.0"},
auto message = std::make_unique<LSPMessage>();
message->message = {
{"method", "textDocument/didChange"},
{"params",
{{"textDocument",
{{"uri", editor->uri}, {"version", ++editor->lsp_version}}},
{{"uri", this->uri}, {"version", ++this->lsp_version}}},
{"contentChanges", json::array({{{"text", full_text}}})}}}};
lsp_send(editor->lsp, message, nullptr);
lsp->send(std::move(message));
}
}
}

View File

@@ -5,69 +5,66 @@
#include "syntax/langs.h"
#include "utils/utils.h"
Editor *new_editor(const char *filename_arg, Coord position, Coord size,
uint8_t eol) {
Editor *editor = new Editor();
if (!editor)
return nullptr;
Editor::Editor(const char *filename_arg, uint8_t eol) {
uint32_t len = 0;
std::string filename = path_abs(filename_arg);
editor->unix_eol = eol & 1;
char *str = load_file(filename.c_str(), &len, &editor->unix_eol);
this->unix_eol = eol & 1;
char *str = load_file(filename.c_str(), &len, &this->unix_eol);
if (!str) {
str = (char *)malloc(1);
*str = '\n';
len = 1;
}
if ((eol >> 1) & 1)
editor->unix_eol = eol & 1;
editor->filename = filename;
editor->uri = path_to_file_uri(filename);
editor->position = position;
editor->size = size;
editor->cursor_preffered = UINT32_MAX;
this->unix_eol = eol & 1;
this->filename = filename;
this->uri = path_to_file_uri(filename);
this->cursor_preffered = UINT32_MAX;
if (len == 0) {
free(str);
str = (char *)malloc(1);
*str = '\n';
len = 1;
}
editor->root = load(str, len, optimal_chunk_size(len));
this->scroll = {0, 0};
this->cursor = {0, 0};
this->size = {20, 20};
this->root = load(str, len, optimal_chunk_size(len));
free(str);
editor->lang = language_for_file(filename.c_str());
if (parsers.find(editor->lang.name) != parsers.end())
editor->parser = new Parser(editor, editor->lang.name, size.row + 5);
if (editor->lang.name == "css" || editor->lang.name == "html" ||
editor->lang.name == "javascript" || editor->lang.name == "markdown" ||
editor->lang.name == "typescript")
editor->is_css_color = true;
if (len <= (1024 * 28))
request_add_to_lsp(editor->lang, editor);
editor->indents.compute_indent(editor);
return editor;
this->lang = language_for_file(filename.c_str());
if (parsers.find(this->lang.name) != parsers.end())
this->parser = new Parser(this, this->lang.name, size.row + 5);
if (this->lang.name == "css" || this->lang.name == "html" ||
this->lang.name == "javascript" || this->lang.name == "markdown" ||
this->lang.name == "typescript")
this->is_css_color = true;
if (len <= (1024 * 28)) {
std::lock_guard lock(lsp::lsp_mutex);
lsp::new_editors.push_back(this);
}
this->indents.compute_indent(this);
}
void free_editor(Editor *editor) {
remove_from_lsp(editor);
if (editor->parser)
delete editor->parser;
editor->parser = nullptr;
free_rope(editor->root);
delete editor;
Editor::~Editor() {
auto lsp = this->lsp.load();
if (lsp)
lsp->remove(this);
if (this->parser)
delete this->parser;
this->parser = nullptr;
free_rope(this->root);
}
void save_file(Editor *editor) {
if (!editor || !editor->root)
void Editor::save() {
if (!this->root)
return;
std::shared_lock lock(editor->knot_mtx);
int version = editor->lsp_version;
uint32_t char_count = editor->root->char_count;
char *str = read(editor->root, 0, char_count);
int version = this->lsp_version;
uint32_t char_count = this->root->char_count;
char *str = read(this->root, 0, char_count);
if (!str)
return;
lock.unlock();
std::ofstream out(editor->filename);
if (!editor->unix_eol) {
std::ofstream out(this->filename);
if (!this->unix_eol) {
for (uint32_t i = 0; i < char_count; ++i) {
if (str[i] == '\n')
out.put('\r');
@@ -78,30 +75,33 @@ void save_file(Editor *editor) {
}
out.close();
free(str);
bar.log("Written " + std::to_string(char_count) + " bytes to " +
editor->filename);
if (editor->lsp) {
json save_msg = {{"jsonrpc", "2.0"},
{"method", "textDocument/didSave"},
{"params", {{"textDocument", {{"uri", editor->uri}}}}}};
lsp_send(editor->lsp, save_msg, nullptr);
if (editor->lsp->allow_formatting) {
json msg = {{"jsonrpc", "2.0"},
{"method", "textDocument/formatting"},
{"params",
{{"textDocument", {{"uri", editor->uri}}},
{"options",
{{"tabSize", 2},
{"insertSpaces", true},
{"trimTrailingWhitespace", true},
{"trimFinalNewlines", true}}}}}};
LSPPending *pending = new LSPPending();
pending->editor = editor;
pending->callback = [save_msg, version](Editor *editor,
const json &message) {
if (version != editor->lsp_version)
ui::bar.log("Written " + std::to_string(char_count) + " bytes to " +
this->filename);
auto lsp = this->lsp.load();
if (lsp) {
log("Saving %s", this->filename.c_str());
auto message = std::make_unique<LSPMessage>();
message->message = {{"method", "textDocument/didSave"},
{"params", {{"textDocument", {{"uri", this->uri}}}}}};
lsp->send(std::move(message));
if (lsp->allow_formatting) {
log("Formatting %s", this->filename.c_str());
json s_msg = {{"method", "textDocument/formatting"},
{"params",
{{"textDocument", {{"uri", this->uri}}},
{"options",
{{"tabSize", 2},
{"insertSpaces", true},
{"trimTrailingWhitespace", true},
{"trimFinalNewlines", true}}}}}};
auto save_msg = std::make_unique<LSPMessage>();
save_msg->editor = this;
save_msg->message = s_msg;
save_msg->callback = [s_msg, version](const LSPMessage &msg) {
log("Formattin");
if (version != msg.editor->lsp_version)
return;
auto &edits = message["result"];
auto &edits = msg.message["result"];
if (edits.is_array()) {
std::vector<TextEdit> t_edits;
t_edits.reserve(edits.size());
@@ -112,19 +112,17 @@ void save_file(Editor *editor) {
t_edit.start.col = edit["range"]["start"]["character"];
t_edit.end.row = edit["range"]["end"]["line"];
t_edit.end.col = edit["range"]["end"]["character"];
utf8_normalize_edit(editor, &t_edit);
msg.editor->utf8_normalize_edit(&t_edit);
t_edits.push_back(t_edit);
}
apply_lsp_edits(editor, t_edits, false);
ensure_scroll(editor);
std::shared_lock lock(editor->knot_mtx);
uint32_t char_count = editor->root->char_count;
char *str = read(editor->root, 0, char_count);
msg.editor->apply_lsp_edits(t_edits, false);
msg.editor->ensure_cursor();
uint32_t char_count = msg.editor->root->char_count;
char *str = read(msg.editor->root, 0, char_count);
if (!str)
return;
lock.unlock();
std::ofstream out(editor->filename);
if (!editor->unix_eol) {
std::ofstream out(msg.editor->filename);
if (!msg.editor->unix_eol) {
for (uint32_t i = 0; i < char_count; ++i) {
if (str[i] == '\n')
out.put('\r');
@@ -135,10 +133,14 @@ void save_file(Editor *editor) {
}
out.close();
free(str);
lsp_send(editor->lsp, save_msg, nullptr);
auto save_msg = std::make_unique<LSPMessage>();
save_msg->editor = msg.editor;
save_msg->message = s_msg;
save_msg->callback = [](const LSPMessage &) {};
msg.editor->lsp.load()->send(std::move(save_msg));
}
};
lsp_send(editor->lsp, msg, pending);
lsp->send(std::move(save_msg));
}
}
}

View File

@@ -1,60 +1,59 @@
#include "editor/editor.h"
#include "editor/helpers.h"
#include "extentions/hover.h"
#include "io/sysio.h"
#include "main.h"
#include "utils/utils.h"
void handle_editor_event(Editor *editor, KeyEvent event) {
void Editor::handle_event(KeyEvent event) {
uint8_t old_mode = mode;
if (editor->hover_active)
editor->hover_active = false;
handle_mouse(editor, event);
if (this->hover_active)
this->hover_active = false;
if (event.key_type == KEY_SPECIAL) {
switch (event.special_modifier) {
case 0:
switch (event.special_key) {
case KEY_DOWN:
cursor_down(editor, 1);
this->cursor_down(1);
break;
case KEY_UP:
cursor_up(editor, 1);
this->cursor_up(1);
break;
case KEY_LEFT:
cursor_left(editor, 1);
this->cursor_left(1);
break;
case KEY_RIGHT:
cursor_right(editor, 1);
this->cursor_right(1);
break;
}
break;
case CNTRL:
switch (event.special_key) {
case KEY_DOWN:
cursor_down(editor, 5);
this->cursor_down(5);
break;
case KEY_UP:
cursor_up(editor, 5);
this->cursor_up(5);
break;
case KEY_LEFT:
cursor_prev_word(editor);
this->cursor_prev_word();
case KEY_RIGHT:
cursor_next_word(editor);
this->cursor_next_word();
break;
}
break;
case ALT:
switch (event.special_key) {
case KEY_DOWN:
move_line_down(editor);
this->move_line_down();
break;
case KEY_UP:
move_line_up(editor);
this->move_line_up();
break;
case KEY_LEFT:
cursor_left(editor, 8);
this->cursor_left(8);
break;
case KEY_RIGHT:
cursor_right(editor, 8);
this->cursor_right(8);
break;
}
break;
@@ -65,86 +64,86 @@ void handle_editor_event(Editor *editor, KeyEvent event) {
if (event.key_type == KEY_CHAR && event.len == 1) {
switch (event.c[0]) {
case 'u':
select_all(editor);
this->select_all();
break;
case CTRL('h'):
editor->hover.scroll(-1);
editor->hover_active = true;
static_cast<HoverBox *>(ui::hover_popup->tile.get())->scroll(-1);
this->hover_active = true;
break;
case CTRL('l'):
editor->hover.scroll(1);
editor->hover_active = true;
static_cast<HoverBox *>(ui::hover_popup->tile.get())->scroll(1);
this->hover_active = true;
break;
case 'h':
fetch_lsp_hover(editor);
this->fetch_lsp_hover();
break;
case 'a': {
mode = INSERT;
Coord start = editor->cursor;
cursor_right(editor, 1);
if (start.row != editor->cursor.row)
cursor_left(editor, 1);
Coord start = this->cursor;
this->cursor_right(1);
if (start.row != this->cursor.row)
this->cursor_left(1);
} break;
case 'i':
mode = INSERT;
break;
case 'n':
mode = JUMPER;
editor->jumper_set = true;
this->jumper_set = true;
break;
case 'm':
mode = JUMPER;
editor->jumper_set = false;
this->jumper_set = false;
break;
case 'N':
clear_hooks_at_line(editor, editor->cursor.row);
this->clear_hooks_at_line(this->cursor.row);
break;
case 's':
case 'v':
mode = SELECT;
editor->selection_active = true;
editor->selection = editor->cursor;
editor->selection_type = CHAR;
this->selection_active = true;
this->selection = this->cursor;
this->selection_type = CHAR;
break;
case ';':
case ':':
mode = RUNNER;
break;
case 0x7F:
cursor_left(editor, 1);
this->cursor_left(1);
break;
case ' ':
cursor_right(editor, 1);
this->cursor_right(1);
break;
case '\r':
case '\n':
cursor_down(editor, 1);
this->cursor_down(1);
break;
case '\\':
case '|':
cursor_up(editor, 1);
this->cursor_up(1);
break;
case CTRL('d'):
scroll_down(editor, 1);
ensure_cursor(editor);
this->scroll_down(1);
this->ensure_cursor();
break;
case CTRL('u'):
scroll_up(editor, 1);
ensure_cursor(editor);
this->scroll_up(1);
this->ensure_cursor();
break;
case '>':
case '.':
indent_current_line(editor);
this->indent_current_line();
break;
case '<':
case ',':
dedent_current_line(editor);
this->dedent_current_line();
break;
case CTRL('s'):
save_file(editor);
this->save();
break;
case 'p':
paste(editor);
this->paste();
break;
}
}
@@ -153,34 +152,34 @@ void handle_editor_event(Editor *editor, KeyEvent event) {
if (event.key_type == KEY_CHAR) {
if (event.len == 1) {
if (event.c[0] == '\t') {
editor->indents.insert_tab(editor->cursor);
this->indents.insert_tab(this->cursor);
} else if (event.c[0] == '\n' || event.c[0] == '\r') {
editor->indents.insert_new_line(editor->cursor);
this->indents.insert_new_line(this->cursor);
} else if (event.c[0] == CTRL('W')) {
delete_prev_word(editor);
this->delete_prev_word();
} else if (isprint((unsigned char)(event.c[0]))) {
insert_char(editor, event.c[0]);
this->insert_char(event.c[0]);
} else if (event.c[0] == 0x7F || event.c[0] == 0x08) {
backspace_edit(editor);
this->backspace_edit();
} else if (event.c[0] == 0x1B) {
normal_mode(editor);
this->normal_mode();
}
} else if (event.len > 1) {
edit_insert(editor, editor->cursor, event.c, event.len);
cursor_right(editor, 1);
this->edit_insert(this->cursor, event.c, event.len);
this->cursor_right(1);
}
} else if (event.key_type == KEY_SPECIAL &&
event.special_key == KEY_DELETE) {
switch (event.special_modifier) {
case 0:
edit_erase(editor, editor->cursor, 1);
this->edit_erase(this->cursor, 1);
break;
case CNTRL:
delete_next_word(editor);
this->delete_next_word();
break;
}
} else if (event.key_type == KEY_PASTE) {
insert_str(editor, event.c, event.len);
this->insert_str(event.c, event.len);
}
break;
case SELECT:
@@ -189,28 +188,28 @@ void handle_editor_event(Editor *editor, KeyEvent event) {
case 0x1B:
case 's':
case 'v':
editor->selection_active = false;
this->selection_active = false;
mode = NORMAL;
break;
case 'y':
copy(editor);
this->copy();
mode = NORMAL;
break;
case 'x':
cut(editor);
this->cut();
mode = NORMAL;
break;
case 'p':
paste(editor);
this->paste();
mode = NORMAL;
break;
case '<':
case ',':
dedent_selection(editor);
this->dedent_selection();
break;
case '>':
case '.':
indent_selection(editor);
this->indent_selection();
break;
}
}
@@ -218,25 +217,25 @@ void handle_editor_event(Editor *editor, KeyEvent event) {
case JUMPER:
if (event.key_type == KEY_CHAR && event.len == 1 &&
(event.c[0] >= '!' && event.c[0] <= '~')) {
if (editor->jumper_set) {
if (this->jumper_set) {
for (uint8_t i = 0; i < 94; i++)
if (editor->hooks[i] == editor->cursor.row + 1) {
editor->hooks[i] = 0;
if (this->hooks[i] == this->cursor.row + 1) {
this->hooks[i] = 0;
break;
}
editor->hooks[event.c[0] - '!'] = editor->cursor.row + 1;
this->hooks[event.c[0] - '!'] = this->cursor.row + 1;
} else {
uint32_t line = editor->hooks[event.c[0] - '!'] - 1;
uint32_t line = this->hooks[event.c[0] - '!'] - 1;
if (line > 0) {
editor->cursor = {line, 0};
editor->cursor_preffered = UINT32_MAX;
this->cursor = {line, 0};
this->cursor_preffered = UINT32_MAX;
}
}
}
mode = NORMAL;
break;
}
if (old_mode == mode || mode != INSERT)
handle_completion(editor, event);
ensure_scroll(editor);
// if (old_mode == mode || mode != INSERT)
// this->completion.handle(event);
this->ensure_scroll();
}

View File

@@ -1,86 +1,83 @@
#include "editor/helpers.h"
#include "editor/editor.h"
#include "extentions/hover.h"
#include "io/sysio.h"
#include "lsp/lsp.h"
#include "main.h"
#include "utils/utils.h"
#include <sys/types.h>
void cut(Editor *editor) {
if (ABS((int64_t)editor->cursor.row - (int64_t)editor->selection.row) >
1500) {
bar.log("Selection too large!");
void Editor::cut() {
if (ABS((int64_t)this->cursor.row - (int64_t)this->selection.row) > 1500) {
ui::bar.log("Selection too large!");
return;
}
if (mode != SELECT)
return;
Coord start;
uint32_t len;
char *text = get_selection(editor, &len, &start);
char *text = this->get_selection(&len, &start);
ruby_copy(text, len);
len = count_clusters(text, len, 0, len);
edit_erase(editor, start, len);
this->edit_erase(start, len);
free(text);
editor->selection_active = false;
this->selection_active = false;
}
void copy(Editor *editor) {
if (ABS((int64_t)editor->cursor.row - (int64_t)editor->selection.row) >
1500) {
bar.log("Selection too large!");
void Editor::copy() {
if (ABS((int64_t)this->cursor.row - (int64_t)this->selection.row) > 1500) {
ui::bar.log("Selection too large!");
return;
}
if (mode != SELECT)
return;
uint32_t len;
char *text = get_selection(editor, &len, nullptr);
char *text = this->get_selection(&len, nullptr);
ruby_copy(text, len);
free(text);
editor->selection_active = false;
this->selection_active = false;
}
void paste(Editor *editor) {
void Editor::paste() {
if (mode == NORMAL) {
std::string text = ruby_paste();
if (text.empty())
return;
insert_str(editor, (char *)text.c_str(), text.length());
this->insert_str((char *)text.c_str(), text.length());
} else if (mode == SELECT) {
std::string text = ruby_paste();
if (!text.empty()) {
Coord start, end;
selection_bounds(editor, &start, &end);
this->selection_bounds(&start, &end);
uint32_t start_byte =
line_to_byte(editor->root, start.row, nullptr) + start.col;
uint32_t end_byte =
line_to_byte(editor->root, end.row, nullptr) + end.col;
edit_erase(editor, start, end_byte - start_byte);
edit_insert(editor, editor->cursor, (char *)text.c_str(), text.length());
line_to_byte(this->root, start.row, nullptr) + start.col;
uint32_t end_byte = line_to_byte(this->root, end.row, nullptr) + end.col;
this->edit_erase(start, end_byte - start_byte);
this->edit_insert(this->cursor, (char *)text.c_str(), text.length());
}
editor->selection_active = false;
this->selection_active = false;
}
}
void insert_str(Editor *editor, char *c, uint32_t len) {
void Editor::insert_str(char *c, uint32_t len) {
if (c) {
edit_insert(editor, editor->cursor, c, len);
this->edit_insert(this->cursor, c, len);
uint32_t grapheme_len = count_clusters(c, len, 0, len);
cursor_right(editor, grapheme_len);
this->cursor_right(grapheme_len);
}
}
void indent_current_line(Editor *editor) {
Coord start = editor->cursor;
uint32_t delta = editor->indents.indent_line(editor->cursor.row);
editor->cursor.col = start.col + delta;
editor->cursor.row = start.row;
void Editor::indent_current_line() {
Coord start = this->cursor;
uint32_t delta = this->indents.indent_line(this->cursor.row);
this->cursor.col = start.col + delta;
this->cursor.row = start.row;
}
void dedent_current_line(Editor *editor) {
Coord start = editor->cursor;
uint32_t delta = editor->indents.dedent_line(editor->cursor.row);
editor->cursor.col = MAX((int64_t)start.col - delta, 0);
editor->cursor.row = start.row;
void Editor::dedent_current_line() {
Coord start = this->cursor;
uint32_t delta = this->indents.dedent_line(this->cursor.row);
this->cursor.col = MAX((int64_t)start.col - delta, 0);
this->cursor.row = start.row;
}
static void move_coord_by_delta(Coord &c, uint32_t row, int64_t delta) {
@@ -90,49 +87,49 @@ static void move_coord_by_delta(Coord &c, uint32_t row, int64_t delta) {
}
}
void indent_selection(Editor *editor) {
uint32_t top = MIN(editor->cursor.row, editor->selection.row);
uint32_t bot = MAX(editor->cursor.row, editor->selection.row);
void Editor::indent_selection() {
uint32_t top = MIN(this->cursor.row, this->selection.row);
uint32_t bot = MAX(this->cursor.row, this->selection.row);
if (bot - top > 1500) {
bar.log("Can't indent more than 1500 lines at once!");
ui::bar.log("Can't indent more than 1500 lines at once!");
return;
}
if (bot - top >= 2)
editor->indents.indent_block(top + 1, bot - 1);
uint32_t delta_top = editor->indents.indent_line(top);
this->indents.indent_block(top + 1, bot - 1);
uint32_t delta_top = this->indents.indent_line(top);
uint32_t delta_bot =
(bot == top) ? delta_top : editor->indents.indent_line(bot);
move_coord_by_delta(editor->cursor, top, delta_top);
move_coord_by_delta(editor->selection, top, delta_top);
(bot == top) ? delta_top : this->indents.indent_line(bot);
move_coord_by_delta(this->cursor, top, delta_top);
move_coord_by_delta(this->selection, top, delta_top);
if (bot != top) {
move_coord_by_delta(editor->cursor, bot, delta_bot);
move_coord_by_delta(editor->selection, bot, delta_bot);
move_coord_by_delta(this->cursor, bot, delta_bot);
move_coord_by_delta(this->selection, bot, delta_bot);
}
}
void dedent_selection(Editor *editor) {
uint32_t top = MIN(editor->cursor.row, editor->selection.row);
uint32_t bot = MAX(editor->cursor.row, editor->selection.row);
void Editor::dedent_selection() {
uint32_t top = MIN(this->cursor.row, this->selection.row);
uint32_t bot = MAX(this->cursor.row, this->selection.row);
if (bot - top > 1500) {
bar.log("Can't dedent more than 1500 lines at once!");
ui::bar.log("Can't dedent more than 1500 lines at once!");
return;
}
if (bot - top >= 2)
editor->indents.dedent_block(top + 1, bot - 1);
uint32_t delta_top = editor->indents.dedent_line(top);
this->indents.dedent_block(top + 1, bot - 1);
uint32_t delta_top = this->indents.dedent_line(top);
uint32_t delta_bot =
(bot == top) ? delta_top : editor->indents.dedent_line(bot);
move_coord_by_delta(editor->cursor, top, -(int64_t)delta_top);
move_coord_by_delta(editor->selection, top, -(int64_t)delta_top);
(bot == top) ? delta_top : this->indents.dedent_line(bot);
move_coord_by_delta(this->cursor, top, -(int64_t)delta_top);
move_coord_by_delta(this->selection, top, -(int64_t)delta_top);
if (bot != top) {
move_coord_by_delta(editor->cursor, bot, -(int64_t)delta_bot);
move_coord_by_delta(editor->selection, bot, -(int64_t)delta_bot);
move_coord_by_delta(this->cursor, bot, -(int64_t)delta_bot);
move_coord_by_delta(this->selection, bot, -(int64_t)delta_bot);
}
}
void insert_char(Editor *editor, char c) {
uint32_t col = editor->cursor.col;
LineIterator *it = begin_l_iter(editor->root, editor->cursor.row);
void Editor::insert_char(char c) {
uint32_t col = this->cursor.col;
LineIterator *it = begin_l_iter(this->root, this->cursor.row);
if (!it)
return;
uint32_t len;
@@ -148,7 +145,7 @@ void insert_char(Editor *editor, char c) {
if ((c == '}' && next == '}') || (c == ')' && next == ')') ||
(c == ']' && next == ']') || (c == '"' && next == '"') ||
(c == '\'' && next == '\'')) {
cursor_right(editor, 1);
this->cursor_right(1);
skip_insert = true;
}
}
@@ -175,16 +172,17 @@ void insert_char(Editor *editor, char c) {
}
if (closing) {
char pair[2] = {c, closing};
edit_insert(editor, editor->cursor, pair, 2);
cursor_right(editor, 1);
this->edit_insert(this->cursor, pair, 2);
this->cursor_right(1);
} else {
edit_insert(editor, editor->cursor, &c, 1);
cursor_right(editor, 1);
this->edit_insert(this->cursor, &c, 1);
this->cursor_right(1);
}
if (editor->lsp && editor->lsp->allow_formatting_on_type) {
for (char ch : editor->lsp->format_chars) {
auto lsp = this->lsp.load();
if (lsp && lsp->allow_formatting_on_type) {
for (char ch : lsp->format_chars) {
if (ch == c) {
LineIterator *it = begin_l_iter(editor->root, editor->cursor.row);
LineIterator *it = begin_l_iter(this->root, this->cursor.row);
if (!it)
return;
uint32_t len;
@@ -194,29 +192,27 @@ void insert_char(Editor *editor, char c) {
free(it);
return;
}
uint32_t col = utf8_offset_to_utf16(line, len, editor->cursor.col);
uint32_t col = utf8_offset_to_utf16(line, len, this->cursor.col);
free(it->buffer);
free(it);
int version = editor->lsp_version;
json message = {
{"jsonrpc", "2.0"},
int version = this->lsp_version;
auto message = std::make_unique<LSPMessage>();
message->message = {
{"method", "textDocument/onTypeFormatting"},
{"params",
{{"textDocument", {{"uri", editor->uri}}},
{"position",
{{"line", editor->cursor.row}, {"character", col}}},
{{"textDocument", {{"uri", this->uri}}},
{"position", {{"line", this->cursor.row}, {"character", col}}},
{"ch", std::string(1, c)},
{"options",
{{"tabSize", 2},
{"insertSpaces", true},
{"trimTrailingWhitespace", true},
{"trimFinalNewlines", true}}}}}};
LSPPending *pending = new LSPPending();
pending->editor = editor;
pending->callback = [version](Editor *editor, const json &message) {
if (version != editor->lsp_version)
message->editor = this;
message->callback = [version](const LSPMessage &message) {
if (version != message.editor->lsp_version)
return;
auto &edits = message["result"];
auto &edits = message.message["result"];
if (edits.is_array()) {
std::vector<TextEdit> t_edits;
t_edits.reserve(edits.size());
@@ -227,14 +223,14 @@ void insert_char(Editor *editor, char c) {
t_edit.start.col = edit["range"]["start"]["character"];
t_edit.end.row = edit["range"]["end"]["line"];
t_edit.end.col = edit["range"]["end"]["character"];
utf8_normalize_edit(editor, &t_edit);
message.editor->utf8_normalize_edit(&t_edit);
t_edits.push_back(t_edit);
}
apply_lsp_edits(editor, t_edits, false);
ensure_scroll(editor);
message.editor->apply_lsp_edits(t_edits, false);
message.editor->ensure_scroll();
}
};
lsp_send(editor->lsp, message, pending);
lsp->send(std::move(message));
break;
}
}
@@ -242,19 +238,19 @@ void insert_char(Editor *editor, char c) {
}
}
void normal_mode(Editor *editor) {
Coord prev_pos = editor->cursor;
void Editor::normal_mode() {
Coord prev_pos = this->cursor;
mode = NORMAL;
cursor_left(editor, 1);
if (prev_pos.row != editor->cursor.row)
cursor_right(editor, 1);
this->cursor_left(1);
if (prev_pos.row != this->cursor.row)
this->cursor_right(1);
}
void backspace_edit(Editor *editor) {
Coord prev_pos = editor->cursor;
void Editor::backspace_edit() {
Coord prev_pos = this->cursor;
if (prev_pos.col > 0)
prev_pos.col--;
LineIterator *it = begin_l_iter(editor->root, editor->cursor.row);
LineIterator *it = begin_l_iter(this->root, this->cursor.row);
if (!it)
return;
uint32_t len;
@@ -267,11 +263,11 @@ void backspace_edit(Editor *editor) {
if (len > 0 && line[len - 1] == '\n')
--len;
char prev_char = (prev_pos.col < len) ? line[prev_pos.col] : 0;
char next_char = (editor->cursor.col < len) ? line[editor->cursor.col] : 0;
char next_char = (this->cursor.col < len) ? line[this->cursor.col] : 0;
bool before_content = false;
if (editor->cursor.col > 0) {
if (this->cursor.col > 0) {
before_content = true;
for (uint32_t i = 0; i < editor->cursor.col; i++)
for (uint32_t i = 0; i < this->cursor.col; i++)
if (line[i] != ' ' && line[i] != '\t') {
before_content = false;
break;
@@ -280,7 +276,7 @@ void backspace_edit(Editor *editor) {
free(it->buffer);
free(it);
if (before_content) {
dedent_current_line(editor);
this->dedent_current_line();
return;
}
bool is_pair = (prev_char == '{' && next_char == '}') ||
@@ -289,65 +285,65 @@ void backspace_edit(Editor *editor) {
(prev_char == '"' && next_char == '"') ||
(prev_char == '\'' && next_char == '\'');
if (is_pair) {
edit_erase(editor, editor->cursor, 1);
edit_erase(editor, prev_pos, 1);
this->edit_erase(this->cursor, 1);
this->edit_erase(prev_pos, 1);
} else {
edit_erase(editor, editor->cursor, -1);
this->edit_erase(this->cursor, -1);
}
}
void delete_prev_word(Editor *editor) {
void Editor::delete_prev_word() {
uint32_t prev_col_byte, prev_col_cluster;
word_boundaries(editor, editor->cursor, &prev_col_byte, nullptr,
&prev_col_cluster, nullptr);
if (prev_col_byte == editor->cursor.col)
edit_erase(editor, editor->cursor, -1);
this->word_boundaries(this->cursor, &prev_col_byte, nullptr,
&prev_col_cluster, nullptr);
if (prev_col_byte == this->cursor.col)
this->edit_erase(this->cursor, -1);
else
edit_erase(editor, editor->cursor, -(int64_t)prev_col_cluster);
this->edit_erase(this->cursor, -(int64_t)prev_col_cluster);
}
void delete_next_word(Editor *editor) {
void Editor::delete_next_word() {
uint32_t next_col_byte, next_col_cluster;
word_boundaries(editor, editor->cursor, nullptr, &next_col_byte, nullptr,
&next_col_cluster);
if (next_col_byte == editor->cursor.col)
edit_erase(editor, editor->cursor, 1);
this->word_boundaries(this->cursor, nullptr, &next_col_byte, nullptr,
&next_col_cluster);
if (next_col_byte == this->cursor.col)
this->edit_erase(this->cursor, 1);
else
edit_erase(editor, editor->cursor, next_col_cluster);
this->edit_erase(this->cursor, next_col_cluster);
}
void clear_hooks_at_line(Editor *editor, uint32_t line) {
void Editor::clear_hooks_at_line(uint32_t line) {
for (uint8_t i = 0; i < 94; i++)
if (editor->hooks[i] == line + 1) {
editor->hooks[i] = 0;
if (this->hooks[i] == line + 1) {
this->hooks[i] = 0;
break;
}
}
void cursor_prev_word(Editor *editor) {
void Editor::cursor_prev_word() {
uint32_t prev_col;
word_boundaries(editor, editor->cursor, &prev_col, nullptr, nullptr, nullptr);
editor->cursor_preffered = UINT32_MAX;
if (prev_col == editor->cursor.col)
cursor_left(editor, 1);
word_boundaries(this->cursor, &prev_col, nullptr, nullptr, nullptr);
this->cursor_preffered = UINT32_MAX;
if (prev_col == this->cursor.col)
cursor_left(1);
else
editor->cursor = {editor->cursor.row, prev_col};
this->cursor = {this->cursor.row, prev_col};
}
void cursor_next_word(Editor *editor) {
void Editor::cursor_next_word() {
uint32_t next_col;
word_boundaries(editor, editor->cursor, nullptr, &next_col, nullptr, nullptr);
editor->cursor_preffered = UINT32_MAX;
if (next_col == editor->cursor.col)
cursor_right(editor, 1);
word_boundaries(this->cursor, nullptr, &next_col, nullptr, nullptr);
this->cursor_preffered = UINT32_MAX;
if (next_col == this->cursor.col)
this->cursor_right(1);
else
editor->cursor = {editor->cursor.row, next_col};
this->cursor = {this->cursor.row, next_col};
}
void select_all(Editor *editor) {
if (editor->root->line_count > 0) {
editor->cursor.row = editor->root->line_count - 1;
LineIterator *it = begin_l_iter(editor->root, editor->cursor.row);
void Editor::select_all() {
if (this->root->line_count > 0) {
this->cursor.row = this->root->line_count - 1;
LineIterator *it = begin_l_iter(this->root, this->cursor.row);
if (!it)
return;
uint32_t line_len;
@@ -359,18 +355,19 @@ void select_all(Editor *editor) {
line_len = count_clusters(line, line_len, 0, line_len);
free(it->buffer);
free(it);
editor->cursor.col = line_len;
editor->cursor_preffered = UINT32_MAX;
this->cursor.col = line_len;
this->cursor_preffered = UINT32_MAX;
mode = SELECT;
editor->selection_active = true;
editor->selection = {0, 0};
editor->selection_type = LINE;
this->selection_active = true;
this->selection = {0, 0};
this->selection_type = LINE;
}
}
void fetch_lsp_hover(Editor *editor) {
if (editor->lsp && editor->lsp->allow_hover) {
LineIterator *it = begin_l_iter(editor->root, editor->cursor.row);
void Editor::fetch_lsp_hover() {
auto lsp = this->lsp.load();
if (lsp && lsp->allow_hover) {
LineIterator *it = begin_l_iter(this->root, this->cursor.row);
uint32_t line_len;
char *line = next_line(it, &line_len);
if (!line) {
@@ -378,18 +375,18 @@ void fetch_lsp_hover(Editor *editor) {
free(it);
return;
}
uint32_t col = utf8_offset_to_utf16(line, line_len, editor->cursor.col);
uint32_t col = utf8_offset_to_utf16(line, line_len, this->cursor.col);
free(it->buffer);
free(it);
json hover_request = {
{"jsonrpc", "2.0"},
auto message = std::make_unique<LSPMessage>();
message->message = {
{"method", "textDocument/hover"},
{"params",
{{"textDocument", {{"uri", editor->uri}}},
{"position", {{"line", editor->cursor.row}, {"character", col}}}}}};
LSPPending *pending = new LSPPending();
pending->editor = editor;
pending->callback = [](Editor *editor, const json &hover) {
{{"textDocument", {{"uri", this->uri}}},
{"position", {{"line", this->cursor.row}, {"character", col}}}}}};
message->editor = this;
message->callback = [](const LSPMessage &message) {
auto &hover = message.message;
if (hover.contains("result") && !hover["result"].is_null()) {
auto &contents = hover["result"]["contents"];
std::string hover_text = "";
@@ -413,19 +410,21 @@ void fetch_lsp_hover(Editor *editor) {
hover_text += contents.get<std::string>();
}
if (!hover_text.empty()) {
editor->hover.clear();
editor->hover.text = clean_text(hover_text);
editor->hover.is_markup = is_markup;
editor->hover.render_first();
editor->hover_active = true;
auto hover_box = static_cast<HoverBox *>(ui::hover_popup->tile.get());
hover_box->clear();
hover_box->text = clean_text(hover_text);
hover_box->is_markup = is_markup;
message.editor->hover_active = true;
}
}
};
lsp_send(editor->lsp, hover_request, pending);
lsp->send(std::move(message));
}
}
void handle_mouse(Editor *editor, KeyEvent event) {
void Editor::handle_click(KeyEvent event, Coord size) {
focused_window = this;
this->size = size;
static std::chrono::steady_clock::time_point last_click_time =
std::chrono::steady_clock::now();
static uint32_t click_count = 0;
@@ -439,18 +438,18 @@ void handle_mouse(Editor *editor, KeyEvent event) {
case SCROLL:
switch (event.mouse_direction) {
case SCROLL_UP:
scroll_up(editor, 4);
ensure_cursor(editor);
this->scroll_up(4);
this->ensure_cursor();
break;
case SCROLL_DOWN:
scroll_down(editor, 4);
ensure_cursor(editor);
this->scroll_down(4);
this->ensure_cursor();
break;
case SCROLL_LEFT:
cursor_left(editor, 10);
this->cursor_left(10);
break;
case SCROLL_RIGHT:
cursor_right(editor, 10);
this->cursor_right(10);
break;
}
break;
@@ -463,35 +462,35 @@ void handle_mouse(Editor *editor, KeyEvent event) {
click_count = 1;
last_click_time = now;
last_click_pos = cur_pos;
Coord p = editor_hit_test(editor, event.mouse_x, event.mouse_y);
Coord p = this->click_coord(event.mouse_x, event.mouse_y);
if (p.row == UINT32_MAX && p.col == UINT32_MAX)
return;
editor->cursor_preffered = UINT32_MAX;
this->cursor_preffered = UINT32_MAX;
if (click_count == 1) {
editor->cursor = p;
editor->selection = p;
this->cursor = p;
this->selection = p;
if (mode == SELECT) {
mode = NORMAL;
editor->selection_active = false;
this->selection_active = false;
}
} else if (click_count == 2) {
uint32_t prev_col, next_col;
word_boundaries(editor, editor->cursor, &prev_col, &next_col, nullptr,
nullptr);
if (editor->cursor < editor->selection)
editor->cursor = {editor->cursor.row, prev_col};
this->word_boundaries(this->cursor, &prev_col, &next_col, nullptr,
nullptr);
if (this->cursor < this->selection)
this->cursor = {this->cursor.row, prev_col};
else
editor->cursor = {editor->cursor.row, next_col};
editor->cursor_preffered = UINT32_MAX;
editor->selection_type = WORD;
this->cursor = {this->cursor.row, next_col};
this->cursor_preffered = UINT32_MAX;
this->selection_type = WORD;
mode = SELECT;
editor->selection_active = true;
this->selection_active = true;
} else if (click_count >= 3) {
if (editor->cursor < editor->selection) {
editor->cursor = {p.row, 0};
if (this->cursor < this->selection) {
this->cursor = {p.row, 0};
} else {
uint32_t line_len;
LineIterator *it = begin_l_iter(editor->root, p.row);
LineIterator *it = begin_l_iter(this->root, p.row);
char *line = next_line(it, &line_len);
if (!line)
return;
@@ -499,44 +498,44 @@ void handle_mouse(Editor *editor, KeyEvent event) {
line_len--;
free(it->buffer);
free(it);
editor->cursor = {p.row, line_len};
this->cursor = {p.row, line_len};
}
editor->cursor_preffered = UINT32_MAX;
editor->selection_type = LINE;
this->cursor_preffered = UINT32_MAX;
this->selection_type = LINE;
mode = SELECT;
editor->selection_active = true;
this->selection_active = true;
click_count = 3;
}
}
break;
case DRAG:
if (event.mouse_button == LEFT_BTN) {
Coord p = editor_hit_test(editor, event.mouse_x, event.mouse_y);
Coord p = this->click_coord(event.mouse_x, event.mouse_y);
if (p.row == UINT32_MAX && p.col == UINT32_MAX)
return;
editor->cursor_preffered = UINT32_MAX;
this->cursor_preffered = UINT32_MAX;
mode = SELECT;
if (!editor->selection_active) {
editor->selection_active = true;
editor->selection_type = CHAR;
if (!this->selection_active) {
this->selection_active = true;
this->selection_type = CHAR;
}
uint32_t prev_col, next_col, line_len;
switch (editor->selection_type) {
switch (this->selection_type) {
case CHAR:
editor->cursor = p;
this->cursor = p;
break;
case WORD:
word_boundaries(editor, p, &prev_col, &next_col, nullptr, nullptr);
if (editor->cursor < editor->selection)
editor->cursor = {p.row, prev_col};
this->word_boundaries(p, &prev_col, &next_col, nullptr, nullptr);
if (this->cursor < this->selection)
this->cursor = {p.row, prev_col};
else
editor->cursor = {p.row, next_col};
this->cursor = {p.row, next_col};
break;
case LINE:
if (editor->cursor < editor->selection) {
editor->cursor = {p.row, 0};
if (this->cursor < this->selection) {
this->cursor = {p.row, 0};
} else {
LineIterator *it = begin_l_iter(editor->root, p.row);
LineIterator *it = begin_l_iter(this->root, p.row);
char *line = next_line(it, &line_len);
if (!line)
return;
@@ -544,7 +543,7 @@ void handle_mouse(Editor *editor, KeyEvent event) {
line_len--;
free(it->buffer);
free(it);
editor->cursor = {p.row, line_len};
this->cursor = {p.row, line_len};
}
break;
}
@@ -552,10 +551,10 @@ void handle_mouse(Editor *editor, KeyEvent event) {
break;
case RELEASE:
if (event.mouse_button == LEFT_BTN)
if (editor->cursor.row == editor->selection.row &&
editor->cursor.col == editor->selection.col) {
if (this->cursor.row == this->selection.row &&
this->cursor.col == this->selection.col) {
mode = NORMAL;
editor->selection_active = false;
this->selection_active = false;
}
break;
}

View File

@@ -68,7 +68,6 @@ uint32_t IndentationEngine::indent_real(char *line, uint32_t len) {
}
uint32_t IndentationEngine::indent_expected(uint32_t row) {
std::shared_lock lock(editor->knot_mtx);
uint32_t line_idx = row;
if (row == 0)
return 0;
@@ -109,7 +108,6 @@ uint32_t IndentationEngine::indent_expected(uint32_t row) {
}
uint32_t IndentationEngine::set_indent(uint32_t row, int64_t new_indent) {
std::shared_lock lock(editor->knot_mtx);
LineIterator *it = begin_l_iter(editor->root, row);
if (!it)
return 0;
@@ -122,7 +120,6 @@ uint32_t IndentationEngine::set_indent(uint32_t row, int64_t new_indent) {
}
if (len > 0 && line[len - 1] == '\n')
--len;
lock.unlock();
if (new_indent <= 0)
new_indent = 0;
uint32_t ws_len = 0;
@@ -135,14 +132,13 @@ uint32_t IndentationEngine::set_indent(uint32_t row, int64_t new_indent) {
new_ws.assign(new_indent * indent, ' ');
Coord start = {row, 0};
Coord end = {row, ws_len};
edit_replace(editor, start, end, new_ws.c_str(), new_ws.length());
editor->edit_replace(start, end, new_ws.c_str(), new_ws.length());
free(it->buffer);
free(it);
return len - ws_len + (new_indent * indent);
}
uint32_t IndentationEngine::indent_line(uint32_t row) {
std::shared_lock lock(editor->knot_mtx);
LineIterator *it = begin_l_iter(editor->root, row);
if (!it)
return 0;
@@ -153,7 +149,6 @@ uint32_t IndentationEngine::indent_line(uint32_t row) {
free(it);
return 0;
}
lock.unlock();
if (len > 0 && line[len - 1] == '\n')
--len;
uint32_t new_indent = indent_real(line, len) + 1;
@@ -165,15 +160,14 @@ uint32_t IndentationEngine::indent_line(uint32_t row) {
new_ws.assign(new_indent, '\t');
else
new_ws.assign(new_indent * indent, ' ');
edit_replace(editor, {row, 0}, {row, ws_len}, new_ws.c_str(),
new_indent * indent);
editor->edit_replace({row, 0}, {row, ws_len}, new_ws.c_str(),
new_indent * indent);
free(it->buffer);
free(it);
return (uint32_t)ABS((int64_t)ws_len - (new_indent * indent));
}
uint32_t IndentationEngine::dedent_line(uint32_t row) {
std::shared_lock lock(editor->knot_mtx);
LineIterator *it = begin_l_iter(editor->root, row);
if (!it)
return 0;
@@ -184,7 +178,6 @@ uint32_t IndentationEngine::dedent_line(uint32_t row) {
free(it);
return 0;
}
lock.unlock();
if (len > 0 && line[len - 1] == '\n')
--len;
int64_t new_indent = (int64_t)indent_real(line, len) - 1;
@@ -198,8 +191,8 @@ uint32_t IndentationEngine::dedent_line(uint32_t row) {
new_ws.assign(new_indent, '\t');
else
new_ws.assign(new_indent * indent, ' ');
edit_replace(editor, {row, 0}, {row, ws_len}, new_ws.c_str(),
new_indent * indent);
editor->edit_replace({row, 0}, {row, ws_len}, new_ws.c_str(),
new_indent * indent);
free(it->buffer);
free(it);
return (uint32_t)ABS((int64_t)ws_len - (new_indent * indent));
@@ -262,12 +255,11 @@ void IndentationEngine::indent_block(uint32_t start_row, uint32_t end_row,
}
}
free(block);
edit_replace(editor, {start_row, 0}, {end_row, end_len}, out, out_len);
editor->edit_replace({start_row, 0}, {end_row, end_len}, out, out_len);
free(out);
}
void IndentationEngine::insert_tab(Coord cursor) {
std::shared_lock lock(editor->knot_mtx);
LineIterator *it = begin_l_iter(editor->root, cursor.row);
if (!it)
return;
@@ -278,7 +270,6 @@ void IndentationEngine::insert_tab(Coord cursor) {
free(it);
return;
}
lock.unlock();
if (len > 0 && line[len - 1] == '\n')
--len;
uint32_t ws_len = 0;
@@ -295,13 +286,12 @@ void IndentationEngine::insert_tab(Coord cursor) {
}
free(it->buffer);
free(it);
edit_insert(editor, cursor, (char *)insert.c_str(), insert.size());
editor->edit_insert(cursor, (char *)insert.c_str(), insert.size());
editor->cursor.col += insert.size();
}
void IndentationEngine::insert_new_line(Coord cursor) {
std::string formatted;
std::shared_lock lock(editor->knot_mtx);
LineIterator *it = begin_l_iter(editor->root, cursor.row);
if (!it)
return;
@@ -312,7 +302,6 @@ void IndentationEngine::insert_new_line(Coord cursor) {
free(it);
return;
}
lock.unlock();
if (len > 0 && line[len - 1] == '\n')
--len;
if (cursor.col >= len) {
@@ -332,7 +321,6 @@ void IndentationEngine::insert_new_line(Coord cursor) {
cursor.row, (int64_t)indent_expected(cursor.row) - (int64_t)1);
break;
}
lock.lock();
free(it->buffer);
free(it);
it = begin_l_iter(editor->root, cursor.row);
@@ -346,7 +334,6 @@ void IndentationEngine::insert_new_line(Coord cursor) {
}
if (len > 0 && line[len - 1] == '\n')
--len;
lock.unlock();
}
std::string ending = trim(std::string(line + cursor.col, len - cursor.col));
std::string before = trim(std::string(line, cursor.col));
@@ -407,15 +394,16 @@ void IndentationEngine::insert_new_line(Coord cursor) {
: std::string(c_indent * indent, ' ')) +
ending;
Coord new_cursor = {cursor.row + 1, (uint32_t)c_indent * indent};
edit_replace(editor, cursor, {cursor.row, len}, formatted.data(),
formatted.size());
editor->edit_replace(cursor, {cursor.row, len}, formatted.data(),
formatted.size());
editor->cursor = new_cursor;
editor->cursor_preffered = UINT32_MAX;
free(it->buffer);
free(it);
if (!editor->lsp || !editor->lsp->allow_formatting_on_type)
auto lsp = editor->lsp.load();
if (!lsp || !lsp->allow_formatting_on_type)
return;
for (char ch : editor->lsp->format_chars) {
for (char ch : lsp->format_chars) {
if (ch == '\n') {
LineIterator *it = begin_l_iter(editor->root, editor->cursor.row);
if (!it)
@@ -431,7 +419,9 @@ void IndentationEngine::insert_new_line(Coord cursor) {
free(it->buffer);
free(it);
int version = editor->lsp_version;
json message = {
auto message = std::make_unique<LSPMessage>();
message->editor = editor;
message->message = {
{"jsonrpc", "2.0"},
{"method", "textDocument/onTypeFormatting"},
{"params",
@@ -443,12 +433,10 @@ void IndentationEngine::insert_new_line(Coord cursor) {
{"insertSpaces", true},
{"trimTrailingWhitespace", true},
{"trimFinalNewlines", true}}}}}};
LSPPending *pending = new LSPPending();
pending->editor = editor;
pending->callback = [version](Editor *editor, const json &message) {
if (version != editor->lsp_version)
message->callback = [version](const LSPMessage &message) {
if (version != message.editor->lsp_version)
return;
auto &edits = message["result"];
auto &edits = message.message["result"];
if (edits.is_array()) {
std::vector<TextEdit> t_edits;
t_edits.reserve(edits.size());
@@ -459,14 +447,14 @@ void IndentationEngine::insert_new_line(Coord cursor) {
t_edit.start.col = edit["range"]["start"]["character"];
t_edit.end.row = edit["range"]["end"]["line"];
t_edit.end.col = edit["range"]["end"]["character"];
utf8_normalize_edit(editor, &t_edit);
message.editor->utf8_normalize_edit(&t_edit);
t_edits.push_back(t_edit);
}
apply_lsp_edits(editor, t_edits, false);
ensure_scroll(editor);
message.editor->apply_lsp_edits(t_edits, false);
message.editor->ensure_scroll();
}
};
lsp_send(editor->lsp, message, pending);
lsp->send(std::move(message));
break;
}
}

View File

@@ -2,52 +2,47 @@
#include "editor/editor.h"
#include "utils/utils.h"
void apply_lsp_edits(Editor *editor, std::vector<TextEdit> edits, bool move) {
void Editor::apply_lsp_edits(std::vector<TextEdit> edits, bool move) {
if (!edits.size())
return;
TextEdit first = edits[0];
Coord cursor = editor->cursor;
Coord cursor = this->cursor;
std::sort(
edits.begin(), edits.end(),
[](const TextEdit &a, const TextEdit &b) { return a.start > b.start; });
for (const auto &edit : edits)
edit_replace(editor, edit.start, edit.end, edit.text.c_str(),
edit.text.size());
this->edit_replace(edit.start, edit.end, edit.text.c_str(),
edit.text.size());
if (move) {
std::shared_lock lock(editor->knot_mtx);
editor->cursor = first.start;
editor->cursor =
move_right(editor, editor->cursor,
count_clusters(first.text.c_str(), first.text.size(), 0,
first.text.size()));
this->cursor = first.start;
this->cursor = this->move_right(
this->cursor, count_clusters(first.text.c_str(), first.text.size(), 0,
first.text.size()));
} else {
if (cursor.row >= editor->root->line_count) {
editor->cursor.row = editor->root->line_count - 1;
editor->cursor.col = 0;
if (cursor.row >= this->root->line_count) {
this->cursor.row = this->root->line_count - 1;
this->cursor.col = 0;
} else {
std::shared_lock lock(editor->knot_mtx);
uint32_t len;
line_to_byte(editor->root, cursor.row, &len);
line_to_byte(this->root, cursor.row, &len);
len--;
editor->cursor.row = cursor.row;
editor->cursor.col = cursor.col < len ? cursor.col : len;
this->cursor.row = cursor.row;
this->cursor.col = cursor.col < len ? cursor.col : len;
}
}
}
void editor_lsp_handle(Editor *editor, json msg) {
void Editor::lsp_handle(json msg) {
if (msg.contains("method") &&
msg["method"] == "textDocument/publishDiagnostics") {
std::unique_lock lock(editor->v_mtx);
editor->warnings.clear();
this->warnings.clear();
json diagnostics = msg["params"]["diagnostics"];
for (size_t i = 0; i < diagnostics.size(); i++) {
json d = diagnostics[i];
VWarn w;
w.line = d["range"]["start"]["line"];
w.start = d["range"]["start"]["character"];
std::shared_lock lock(editor->knot_mtx);
LineIterator *it = begin_l_iter(editor->root, w.line);
LineIterator *it = begin_l_iter(this->root, w.line);
if (!it)
continue;
uint32_t len;
@@ -59,7 +54,6 @@ void editor_lsp_handle(Editor *editor, json msg) {
}
if (len > 0 && line[len - 1] == '\n')
--len;
lock.unlock();
w.start = utf16_offset_to_utf8(line, len, w.start);
uint32_t end = d["range"]["end"]["character"];
if (d["range"]["end"]["line"] == w.line)
@@ -102,9 +96,9 @@ void editor_lsp_handle(Editor *editor, json msg) {
w.type = 1;
if (d.contains("severity"))
w.type = d["severity"].get<int>();
editor->warnings.push_back(w);
this->warnings.push_back(w);
}
std::sort(editor->warnings.begin(), editor->warnings.end());
editor->warnings_dirty = true;
std::sort(this->warnings.begin(), this->warnings.end());
this->warnings_dirty = true;
}
}

View File

@@ -1,120 +1,108 @@
#include "editor/editor.h"
#include "main.h"
void move_line_up(Editor *editor) {
if (!editor || !editor->root || editor->cursor.row == 0)
void Editor::move_line_up() {
if (!this->root || this->cursor.row == 0)
return;
if (mode == NORMAL || mode == INSERT) {
uint32_t line_len, line_cluster_len;
std::shared_lock lock(editor->knot_mtx);
LineIterator *it = begin_l_iter(editor->root, editor->cursor.row);
LineIterator *it = begin_l_iter(this->root, this->cursor.row);
char *line = next_line(it, &line_len);
if (!line) {
lock.unlock();
if (!line)
return;
}
if (line_len > 0 && line[line_len - 1] == '\n')
line_len--;
line_cluster_len = count_clusters(line, line_len, 0, line_len);
uint32_t target_row = editor->cursor.row - 1;
uint32_t up_by = editor->cursor.row - target_row;
uint32_t target_row = this->cursor.row - 1;
uint32_t up_by = this->cursor.row - target_row;
if (up_by > 1)
up_by--;
lock.unlock();
Coord cursor = editor->cursor;
edit_erase(editor, {cursor.row, 0}, line_cluster_len);
edit_erase(editor, {cursor.row, 0}, -1);
edit_insert(editor, {cursor.row - up_by, 0}, (char *)"\n", 1);
edit_insert(editor, {cursor.row - up_by, 0}, line, line_len);
Coord cursor = this->cursor;
edit_erase({cursor.row, 0}, line_cluster_len);
edit_erase({cursor.row, 0}, -1);
edit_insert({cursor.row - up_by, 0}, (char *)"\n", 1);
edit_insert({cursor.row - up_by, 0}, line, line_len);
free(it->buffer);
free(it);
editor->cursor = {cursor.row - up_by, cursor.col};
this->cursor = {cursor.row - up_by, cursor.col};
} else if (mode == SELECT) {
uint32_t start_row = MIN(editor->cursor.row, editor->selection.row);
uint32_t end_row = MAX(editor->cursor.row, editor->selection.row);
uint32_t start_byte = line_to_byte(editor->root, start_row, nullptr);
uint32_t end_byte = line_to_byte(editor->root, end_row + 1, nullptr);
char *selected_text = read(editor->root, start_byte, end_byte - start_byte);
uint32_t start_row = MIN(this->cursor.row, this->selection.row);
uint32_t end_row = MAX(this->cursor.row, this->selection.row);
uint32_t start_byte = line_to_byte(this->root, start_row, nullptr);
uint32_t end_byte = line_to_byte(this->root, end_row + 1, nullptr);
char *selected_text = read(this->root, start_byte, end_byte - start_byte);
if (!selected_text)
return;
uint32_t selected_len = count_clusters(selected_text, end_byte - start_byte,
0, end_byte - start_byte);
Coord cursor = editor->cursor;
Coord selection = editor->selection;
edit_erase(editor, {start_row, 0}, selected_len);
edit_insert(editor, {start_row - 1, 0}, selected_text,
end_byte - start_byte);
Coord cursor = this->cursor;
Coord selection = this->selection;
edit_erase({start_row, 0}, selected_len);
edit_insert({start_row - 1, 0}, selected_text, end_byte - start_byte);
free(selected_text);
editor->cursor = {cursor.row - 1, cursor.col};
editor->selection = {selection.row - 1, selection.col};
this->cursor = {cursor.row - 1, cursor.col};
this->selection = {selection.row - 1, selection.col};
}
}
void move_line_down(Editor *editor) {
if (!editor || !editor->root)
void Editor::move_line_down() {
if (!this->root)
return;
if (mode == NORMAL || mode == INSERT) {
if (editor->cursor.row >= editor->root->line_count - 1)
if (this->cursor.row >= this->root->line_count - 1)
return;
uint32_t line_len, line_cluster_len;
std::shared_lock lock(editor->knot_mtx);
LineIterator *it = begin_l_iter(editor->root, editor->cursor.row);
LineIterator *it = begin_l_iter(this->root, this->cursor.row);
char *line = next_line(it, &line_len);
if (!line) {
lock.unlock();
if (!line)
return;
}
if (line_len && line[line_len - 1] == '\n')
line_len--;
line_cluster_len = count_clusters(line, line_len, 0, line_len);
uint32_t target_row = editor->cursor.row + 1;
if (target_row >= editor->root->line_count) {
free(line);
lock.unlock();
uint32_t target_row = this->cursor.row + 1;
if (target_row >= this->root->line_count) {
free(it->buffer);
free(it);
return;
}
uint32_t down_by = target_row - editor->cursor.row;
uint32_t down_by = target_row - this->cursor.row;
if (down_by > 1)
down_by--;
uint32_t ln;
line_to_byte(editor->root, editor->cursor.row + down_by - 1, &ln);
lock.unlock();
Coord cursor = editor->cursor;
edit_erase(editor, {cursor.row, 0}, line_cluster_len);
edit_erase(editor, {cursor.row, 0}, -1);
edit_insert(editor, {cursor.row + down_by, 0}, (char *)"\n", 1);
edit_insert(editor, {cursor.row + down_by, 0}, line, line_len);
line_to_byte(this->root, this->cursor.row + down_by - 1, &ln);
Coord cursor = this->cursor;
edit_erase({cursor.row, 0}, line_cluster_len);
edit_erase({cursor.row, 0}, -1);
edit_insert({cursor.row + down_by, 0}, (char *)"\n", 1);
edit_insert({cursor.row + down_by, 0}, line, line_len);
free(it->buffer);
free(it);
editor->cursor = {cursor.row + down_by, cursor.col};
this->cursor = {cursor.row + down_by, cursor.col};
} else if (mode == SELECT) {
if (editor->cursor.row >= editor->root->line_count - 1 ||
editor->selection.row >= editor->root->line_count - 1)
if (this->cursor.row >= this->root->line_count - 1 ||
this->selection.row >= this->root->line_count - 1)
return;
std::shared_lock lock(editor->knot_mtx);
uint32_t start_row = MIN(editor->cursor.row, editor->selection.row);
uint32_t end_row = MAX(editor->cursor.row, editor->selection.row);
uint32_t start_row = MIN(this->cursor.row, this->selection.row);
uint32_t end_row = MAX(this->cursor.row, this->selection.row);
uint32_t target_row = end_row + 1;
if (target_row >= editor->root->line_count)
if (target_row >= this->root->line_count)
return;
uint32_t down_by = target_row - end_row;
if (down_by > 1)
down_by--;
uint32_t start_byte = line_to_byte(editor->root, start_row, nullptr);
uint32_t end_byte = line_to_byte(editor->root, end_row + 1, nullptr);
char *selected_text = read(editor->root, start_byte, end_byte - start_byte);
lock.unlock();
uint32_t start_byte = line_to_byte(this->root, start_row, nullptr);
uint32_t end_byte = line_to_byte(this->root, end_row + 1, nullptr);
char *selected_text = read(this->root, start_byte, end_byte - start_byte);
if (!selected_text)
return;
uint32_t selected_len = count_clusters(selected_text, end_byte - start_byte,
0, end_byte - start_byte);
Coord cursor = editor->cursor;
Coord selection = editor->selection;
edit_erase(editor, {start_row, 0}, selected_len);
edit_insert(editor, {start_row + down_by, 0}, selected_text,
end_byte - start_byte);
Coord cursor = this->cursor;
Coord selection = this->selection;
edit_erase({start_row, 0}, selected_len);
edit_insert({start_row + down_by, 0}, selected_text, end_byte - start_byte);
free(selected_text);
editor->cursor = {cursor.row + down_by, cursor.col};
editor->selection = {selection.row + down_by, selection.col};
this->cursor = {cursor.row + down_by, cursor.col};
this->selection = {selection.row + down_by, selection.col};
}
}

View File

@@ -3,27 +3,24 @@
#include "main.h"
#include "syntax/decl.h"
#include "syntax/parser.h"
#include <cstdint>
void render_editor(Editor *editor) {
void Editor::render(std::vector<ScreenCell> &buffer, Coord size, Coord pos) {
this->size = size;
uint32_t sel_start = 0, sel_end = 0;
std::shared_lock knot_lock(editor->knot_mtx);
uint32_t numlen =
EXTRA_META + static_cast<int>(std::log10(editor->root->line_count + 1));
uint32_t render_width = editor->size.col - numlen;
uint32_t render_x = editor->position.col + numlen + 1;
EXTRA_META + static_cast<int>(std::log10(this->root->line_count + 1));
uint32_t render_width = size.col - numlen;
uint32_t render_x = pos.col + numlen + 1;
std::vector<std::pair<uint32_t, char>> v;
for (size_t i = 0; i < 94; ++i)
if (editor->hooks[i] != 0)
v.push_back({editor->hooks[i], '!' + i});
if (this->hooks[i] != 0)
v.push_back({this->hooks[i], '!' + i});
std::sort(v.begin(), v.end());
auto hook_it = v.begin();
while (hook_it != v.end() && hook_it->first <= editor->scroll.row)
while (hook_it != v.end() && hook_it->first <= this->scroll.row)
++hook_it;
std::unique_lock warn_lock(editor->v_mtx);
auto warn_it = editor->warnings.begin();
while (warn_it != editor->warnings.end() &&
warn_it->line < editor->scroll.row)
auto warn_it = this->warnings.begin();
while (warn_it != this->warnings.end() && warn_it->line < this->scroll.row)
++warn_it;
LineData *line_data = nullptr;
auto get_type = [&](uint32_t col) {
@@ -34,40 +31,54 @@ void render_editor(Editor *editor) {
return (int)token.type;
return 0;
};
if (editor->selection_active) {
Coord screen = get_size();
auto update = [&](uint32_t row, uint32_t col, std::string text, uint32_t fg,
uint32_t bg, uint8_t flags, uint32_t u_color,
uint32_t width) {
if (row >= screen.row || col >= screen.col)
return;
ScreenCell &c = buffer[row * screen.col + col];
c.utf8 = text;
c.width = width;
c.fg = fg;
c.bg = bg;
c.flags = flags;
c.ul_color = u_color;
};
if (this->selection_active) {
Coord start, end;
if (editor->cursor >= editor->selection) {
if (this->cursor >= this->selection) {
uint32_t prev_col, next_col;
switch (editor->selection_type) {
switch (this->selection_type) {
case CHAR:
start = editor->selection;
end = move_right(editor, editor->cursor, 1);
start = this->selection;
end = this->move_right(this->cursor, 1);
break;
case WORD:
word_boundaries(editor, editor->selection, &prev_col, &next_col,
nullptr, nullptr);
start = {editor->selection.row, prev_col};
end = editor->cursor;
this->word_boundaries(this->selection, &prev_col, &next_col, nullptr,
nullptr);
start = {this->selection.row, prev_col};
end = this->cursor;
break;
case LINE:
start = {editor->selection.row, 0};
end = editor->cursor;
start = {this->selection.row, 0};
end = this->cursor;
break;
}
} else {
start = editor->cursor;
start = this->cursor;
uint32_t prev_col, next_col, line_len;
switch (editor->selection_type) {
switch (this->selection_type) {
case CHAR:
end = move_right(editor, editor->selection, 1);
end = this->move_right(this->selection, 1);
break;
case WORD:
word_boundaries(editor, editor->selection, &prev_col, &next_col,
nullptr, nullptr);
end = {editor->selection.row, next_col};
this->word_boundaries(this->selection, &prev_col, &next_col, nullptr,
nullptr);
end = {this->selection.row, next_col};
break;
case LINE:
LineIterator *it = begin_l_iter(editor->root, editor->selection.row);
LineIterator *it = begin_l_iter(this->root, this->selection.row);
char *line = next_line(it, &line_len);
if (!line)
return;
@@ -75,40 +86,40 @@ void render_editor(Editor *editor) {
line_len--;
free(it->buffer);
free(it);
end = {editor->selection.row, line_len};
end = {this->selection.row, line_len};
break;
}
}
sel_start = line_to_byte(editor->root, start.row, nullptr) + start.col;
sel_end = line_to_byte(editor->root, end.row, nullptr) + end.col;
sel_start = line_to_byte(this->root, start.row, nullptr) + start.col;
sel_end = line_to_byte(this->root, end.row, nullptr) + end.col;
}
Coord cursor = {UINT32_MAX, UINT32_MAX};
uint32_t line_index = editor->scroll.row;
LineIterator *it = begin_l_iter(editor->root, line_index);
uint32_t line_index = this->scroll.row;
LineIterator *it = begin_l_iter(this->root, line_index);
if (!it)
return;
uint32_t prev_col, next_col;
std::string word;
word_boundaries_exclusive(editor, editor->cursor, &prev_col, &next_col);
this->word_boundaries_exclusive(this->cursor, &prev_col, &next_col);
if (next_col - prev_col > 0 && next_col - prev_col < 256 - 4) {
uint32_t offset = line_to_byte(editor->root, editor->cursor.row, nullptr);
char *word_ptr = read(editor->root, offset + prev_col, next_col - prev_col);
uint32_t offset = line_to_byte(this->root, this->cursor.row, nullptr);
char *word_ptr = read(this->root, offset + prev_col, next_col - prev_col);
if (word_ptr) {
word = std::string(word_ptr, next_col - prev_col);
free(word_ptr);
}
}
editor->extra_hl.render(editor->root, line_index, word, editor->is_css_color);
this->extra_hl.render(this->root, line_index, word, this->is_css_color);
uint32_t rendered_rows = 0;
uint32_t global_byte_offset = line_to_byte(editor->root, line_index, nullptr);
while (rendered_rows < editor->size.row) {
uint32_t global_byte_offset = line_to_byte(this->root, line_index, nullptr);
while (rendered_rows < this->size.row) {
uint32_t line_len;
char *line = next_line(it, &line_len);
if (editor->parser) {
if (this->parser) {
if (line_data)
line_data = editor->parser->line_tree.next();
line_data = this->parser->line_tree.next();
else
line_data = editor->parser->line_tree.start_iter(line_index);
line_data = this->parser->line_tree.start_iter(line_index);
}
if (!line)
break;
@@ -123,54 +134,51 @@ void render_editor(Editor *editor) {
(line[content_start] == ' ' || line[content_start] == '\t'))
content_start++;
std::vector<VWarn> line_warnings;
while (warn_it != editor->warnings.end() && warn_it->line == line_index) {
while (warn_it != this->warnings.end() && warn_it->line == line_index) {
line_warnings.push_back(*warn_it);
++warn_it;
}
uint32_t current_byte_offset = 0;
if (rendered_rows == 0)
current_byte_offset += editor->scroll.col;
while (current_byte_offset < line_len && rendered_rows < editor->size.row) {
uint32_t color = editor->cursor.row == line_index ? 0x222222 : 0;
current_byte_offset += this->scroll.col;
while (current_byte_offset < line_len && rendered_rows < this->size.row) {
uint32_t color = this->cursor.row == line_index ? 0x222222 : 0;
if (current_byte_offset == 0 || rendered_rows == 0) {
const char *hook = nullptr;
const char *hook = "";
char h[2] = {0, 0};
if (hook_it != v.end() && hook_it->first == line_index + 1) {
h[0] = hook_it->second;
hook = h;
hook_it++;
}
update(editor->position.row + rendered_rows, editor->position.col, hook,
0xAAAAAA, 0, 0);
update(pos.row + rendered_rows, pos.col, hook, 0xAAAAAA, 0, 0, 0, 1);
char buf[16];
int len = snprintf(buf, sizeof(buf), "%*u ", numlen, line_index + 1);
uint32_t num_color =
editor->cursor.row == line_index ? 0xFFFFFF : 0x555555;
this->cursor.row == line_index ? 0xFFFFFF : 0x555555;
for (int i = 0; i < len; i++)
update(editor->position.row + rendered_rows, editor->position.col + i,
(char[2]){buf[i], 0}, num_color, 0, 0);
update(pos.row + rendered_rows, pos.col + i, (char[2]){buf[i], 0},
num_color, 0, 0, 0, 1);
} else {
for (uint32_t i = 0; i < numlen + 1; i++)
update(editor->position.row + rendered_rows, editor->position.col + i,
" ", 0, 0, 0);
update(pos.row + rendered_rows, pos.col + i, " ", 0, 0, 0, 0, 1);
}
uint32_t col = 0;
uint32_t local_render_offset = 0;
uint32_t line_left = line_len - current_byte_offset;
while (line_left > 0 && col < render_width) {
if (line_index == editor->cursor.row &&
editor->cursor.col == (current_byte_offset + local_render_offset)) {
cursor.row = editor->position.row + rendered_rows;
if (line_index == this->cursor.row &&
this->cursor.col == (current_byte_offset + local_render_offset)) {
cursor.row = pos.row + rendered_rows;
cursor.col = render_x + col;
}
uint32_t absolute_byte_pos =
global_byte_offset + current_byte_offset + local_render_offset;
const Highlight *hl = nullptr;
if (editor->parser)
if (this->parser)
hl = &highlights[get_type(current_byte_offset + local_render_offset)];
std::optional<std::pair<uint32_t, uint32_t>> extra =
editor->extra_hl.get(
{line_index, current_byte_offset + local_render_offset});
std::optional<std::pair<uint32_t, uint32_t>> extra = this->extra_hl.get(
{line_index, current_byte_offset + local_render_offset});
uint32_t fg = extra && extra->second != UINT32_MAX
? extra->first
: (hl ? hl->fg : 0xFFFFFF);
@@ -181,7 +189,7 @@ void render_editor(Editor *editor) {
(hl ? hl->flags : 0) |
(extra ? (extra->second != UINT32_MAX ? CF_BOLD : CF_UNDERLINE)
: 0);
if (editor->selection_active && absolute_byte_pos >= sel_start &&
if (this->selection_active && absolute_byte_pos >= sel_start &&
absolute_byte_pos < sel_end)
bg = bg | 0x555555;
uint32_t u_color = 0;
@@ -217,40 +225,39 @@ void render_editor(Editor *editor) {
break;
if (current_byte_offset + local_render_offset >= content_start &&
current_byte_offset + local_render_offset < content_end) {
update(editor->position.row + rendered_rows, render_x + col,
cluster.c_str(), fg, bg | color, fl, u_color);
update(pos.row + rendered_rows, render_x + col, cluster.c_str(), fg,
bg | color, fl, u_color, width);
} else {
if (cluster[0] == ' ') {
update(editor->position.row + rendered_rows, render_x + col, "·",
0x282828, bg | color, fl, u_color);
update(pos.row + rendered_rows, render_x + col, "·", 0x282828,
bg | color, fl, u_color, 1);
} else {
update(editor->position.row + rendered_rows, render_x + col, "-> ",
0x282828, bg | color, (fl & ~CF_BOLD) | CF_ITALIC, u_color);
update(pos.row + rendered_rows, render_x + col, "-> ", 0x282828,
bg | color, (fl & ~CF_BOLD) | CF_ITALIC, u_color, 4);
}
}
local_render_offset += cluster_len;
line_left -= cluster_len;
col += width;
while (width-- > 1)
update(editor->position.row + rendered_rows, render_x + col - width,
"\x1b", fg, bg | color, fl);
update(pos.row + rendered_rows, render_x + col - width, "\x1b", fg,
bg | color, fl, u_color, 0);
}
if (line_index == editor->cursor.row &&
editor->cursor.col == (current_byte_offset + local_render_offset)) {
cursor.row = editor->position.row + rendered_rows;
if (line_index == this->cursor.row &&
this->cursor.col == (current_byte_offset + local_render_offset)) {
cursor.row = pos.row + rendered_rows;
cursor.col = render_x + col;
}
if (editor->selection_active &&
if (this->selection_active &&
global_byte_offset + line_len + 1 > sel_start &&
global_byte_offset + line_len + 1 <= sel_end && col < render_width) {
update(editor->position.row + rendered_rows, render_x + col, " ", 0,
0x555555 | color, 0);
update(pos.row + rendered_rows, render_x + col, " ", 0,
0x555555 | color, 0, 0, 1);
col++;
}
if (!line_warnings.empty() && line_left == 0) {
VWarn warn = line_warnings.front();
update(editor->position.row + rendered_rows, render_x + col, " ", 0,
color, 0);
update(pos.row + rendered_rows, render_x + col, " ", 0, color, 0, 0, 1);
col++;
for (size_t i = 0; i < line_warnings.size(); i++) {
if (line_warnings[i].type < warn.type)
@@ -276,18 +283,18 @@ void render_editor(Editor *editor) {
goto final;
final:
if (col < render_width) {
update(editor->position.row + rendered_rows, render_x + col,
err_sym, fg_color, color, 0);
update(pos.row + rendered_rows, render_x + col, err_sym, fg_color,
color, 0, 0, 1);
col++;
update(editor->position.row + rendered_rows, render_x + col, " ",
fg_color, color, 0);
update(pos.row + rendered_rows, render_x + col, " ", fg_color,
color, 0, 0, 1);
col++;
}
}
}
if (col < render_width) {
update(editor->position.row + rendered_rows, render_x + col, " ", 0,
0 | color, 0);
update(pos.row + rendered_rows, render_x + col, " ", 0, 0 | color, 0,
0, 1);
col++;
}
size_t warn_idx = 0;
@@ -313,19 +320,19 @@ void render_editor(Editor *editor) {
int width = display_width(cluster.c_str(), cluster_len);
if (col + width > render_width)
break;
update(editor->position.row + rendered_rows, render_x + col,
cluster.c_str(), fg_color, color, 0);
update(pos.row + rendered_rows, render_x + col, cluster.c_str(),
fg_color, color, 0, 0, width);
col += width;
warn_idx += cluster_len;
while (width-- > 1)
update(editor->position.row + rendered_rows, render_x + col - width,
"\x1b", fg_color, color, 0);
update(pos.row + rendered_rows, render_x + col - width, "\x1b",
fg_color, color, 0, 0, 0);
}
line_warnings.clear();
}
while (col < render_width) {
update(editor->position.row + rendered_rows, render_x + col, " ", 0,
0 | color, 0);
update(pos.row + rendered_rows, render_x + col, " ", 0, 0 | color, 0, 0,
1);
col++;
}
rendered_rows++;
@@ -333,39 +340,36 @@ void render_editor(Editor *editor) {
}
if (line_len == 0 ||
(current_byte_offset >= line_len && rendered_rows == 0)) {
uint32_t color = editor->cursor.row == line_index ? 0x222222 : 0;
const char *hook = nullptr;
uint32_t color = this->cursor.row == line_index ? 0x222222 : 0;
const char *hook = "";
char h[2] = {0, 0};
if (hook_it != v.end() && hook_it->first == line_index + 1) {
h[0] = hook_it->second;
hook = h;
hook_it++;
}
update(editor->position.row + rendered_rows, editor->position.col, hook,
0xAAAAAA, 0, 0);
update(pos.row + rendered_rows, pos.col, hook, 0xAAAAAA, 0, 0, 0, 1);
char buf[16];
int len = snprintf(buf, sizeof(buf), "%*u ", numlen, line_index + 1);
uint32_t num_color =
editor->cursor.row == line_index ? 0xFFFFFF : 0x555555;
uint32_t num_color = this->cursor.row == line_index ? 0xFFFFFF : 0x555555;
for (int i = 0; i < len; i++)
update(editor->position.row + rendered_rows, editor->position.col + i,
(char[2]){buf[i], 0}, num_color, 0, 0);
if (editor->cursor.row == line_index) {
cursor.row = editor->position.row + rendered_rows;
update(pos.row + rendered_rows, pos.col + i, (char[2]){buf[i], 0},
num_color, 0, 0, 0, 1);
if (this->cursor.row == line_index) {
cursor.row = pos.row + rendered_rows;
cursor.col = render_x;
}
uint32_t col = 0;
if (editor->selection_active &&
if (this->selection_active &&
global_byte_offset + line_len + 1 > sel_start &&
global_byte_offset + line_len + 1 <= sel_end) {
update(editor->position.row + rendered_rows, render_x + col, " ", 0,
0x555555 | color, 0);
update(pos.row + rendered_rows, render_x + col, " ", 0,
0x555555 | color, 0, 0, 1);
col++;
}
if (!line_warnings.empty()) {
VWarn warn = line_warnings.front();
update(editor->position.row + rendered_rows, render_x + col, " ", 0,
color, 0);
update(pos.row + rendered_rows, render_x + col, " ", 0, color, 0, 0, 1);
col++;
for (size_t i = 0; i < line_warnings.size(); i++) {
if (line_warnings[i].type < warn.type)
@@ -391,18 +395,18 @@ void render_editor(Editor *editor) {
goto final2;
final2:
if (col < render_width) {
update(editor->position.row + rendered_rows, render_x + col,
err_sym, fg_color, color, 0);
update(pos.row + rendered_rows, render_x + col, err_sym, fg_color,
color, 0, 0, 1);
col++;
update(editor->position.row + rendered_rows, render_x + col, " ",
fg_color, color, 0);
update(pos.row + rendered_rows, render_x + col, " ", fg_color,
color, 0, 0, 1);
col++;
}
}
}
if (col < render_width) {
update(editor->position.row + rendered_rows, render_x + col, " ", 0,
0 | color, 0);
update(pos.row + rendered_rows, render_x + col, " ", 0, 0 | color, 0,
0, 1);
col++;
}
size_t warn_idx = 0;
@@ -428,18 +432,18 @@ void render_editor(Editor *editor) {
int width = display_width(cluster.c_str(), cluster_len);
if (col + width > render_width)
break;
update(editor->position.row + rendered_rows, render_x + col,
cluster.c_str(), fg_color, color, 0);
update(pos.row + rendered_rows, render_x + col, cluster.c_str(),
fg_color, color, 0, 0, width);
col += width;
warn_idx += cluster_len;
while (width-- > 1)
update(editor->position.row + rendered_rows, render_x + col - width,
"\x1b", fg_color, color, 0);
update(pos.row + rendered_rows, render_x + col - width, "\x1b",
fg_color, color, 0, 0, 0);
}
}
while (col < render_width) {
update(editor->position.row + rendered_rows, render_x + col, " ", 0,
0 | color, 0);
update(pos.row + rendered_rows, render_x + col, " ", 0, 0 | color, 0, 0,
1);
col++;
}
rendered_rows++;
@@ -447,10 +451,9 @@ void render_editor(Editor *editor) {
global_byte_offset += line_len + 1;
line_index++;
}
while (rendered_rows < editor->size.row) {
for (uint32_t col = 0; col < editor->size.col; col++)
update(editor->position.row + rendered_rows, editor->position.col + col,
" ", 0xFFFFFF, 0, 0);
while (rendered_rows < this->size.row) {
for (uint32_t col = 0; col < this->size.col; col++)
update(pos.row + rendered_rows, pos.col + col, " ", 0xFFFFFF, 0, 0, 0, 1);
rendered_rows++;
}
if (cursor.row != UINT32_MAX && cursor.col != UINT32_MAX) {
@@ -468,15 +471,17 @@ void render_editor(Editor *editor) {
break;
}
set_cursor(cursor.row, cursor.col, type, true);
if (editor->completion.active && !editor->completion.box.hidden)
editor->completion.box.render(cursor);
else if (editor->hover_active)
editor->hover.render(cursor);
else if (editor->diagnostics_active)
editor->diagnostics.render(cursor);
// if (this->completion.active && !this->completion.box.hidden)
// this->completion.box.render(cursor);
// else if (this->hover_active)
// this->hover.render(cursor);
// else if (this->diagnostics_active)
// this->diagnostics.render(cursor);
if (this->hover_active)
ui::hover_popup->pos = cursor;
}
free(it->buffer);
free(it);
if (editor->parser)
editor->parser->scroll(line_index + 5);
if (this->parser)
this->parser->scroll(line_index + 5);
}

View File

@@ -1,13 +1,13 @@
#include "editor/editor.h"
void scroll_up(Editor *editor, int32_t number) {
if (!editor || number == 0)
void Editor::scroll_up(uint32_t number) {
if (number == 0)
return;
uint32_t numlen =
EXTRA_META + static_cast<int>(std::log10(editor->root->line_count + 1));
uint32_t render_width = editor->size.col - numlen;
uint32_t line_index = editor->scroll.row;
LineIterator *it = begin_l_iter(editor->root, line_index);
EXTRA_META + static_cast<int>(std::log10(this->root->line_count + 1));
uint32_t render_width = this->size.col - numlen;
uint32_t line_index = this->scroll.row;
LineIterator *it = begin_l_iter(this->root, line_index);
if (!it)
return;
uint32_t len;
@@ -23,10 +23,9 @@ void scroll_up(Editor *editor, int32_t number) {
uint32_t col = 0;
std::vector<uint32_t> segment_starts;
segment_starts.reserve(16);
if (current_byte_offset < editor->scroll.col)
if (current_byte_offset < this->scroll.col)
segment_starts.push_back(0);
while (current_byte_offset < editor->scroll.col &&
current_byte_offset < len) {
while (current_byte_offset < this->scroll.col && current_byte_offset < len) {
uint32_t cluster_len = grapheme_next_character_break_utf8(
line + current_byte_offset, len - current_byte_offset);
int width = display_width(line + current_byte_offset, cluster_len);
@@ -40,7 +39,7 @@ void scroll_up(Editor *editor, int32_t number) {
for (auto it_seg = segment_starts.rbegin(); it_seg != segment_starts.rend();
++it_seg) {
if (--number == 0) {
editor->scroll = {line_index, *it_seg};
this->scroll = {line_index, *it_seg};
free(it->buffer);
free(it);
return;
@@ -48,7 +47,7 @@ void scroll_up(Editor *editor, int32_t number) {
}
line = prev_line(it, &len);
if (!line) {
editor->scroll = {0, 0};
this->scroll = {0, 0};
free(it->buffer);
free(it);
return;
@@ -57,7 +56,7 @@ void scroll_up(Editor *editor, int32_t number) {
line_index--;
line = prev_line(it, &len);
if (!line) {
editor->scroll = {0, 0};
this->scroll = {0, 0};
free(it->buffer);
free(it);
return;
@@ -83,7 +82,7 @@ void scroll_up(Editor *editor, int32_t number) {
for (auto it_seg = segment_starts.rbegin(); it_seg != segment_starts.rend();
++it_seg) {
if (--number == 0) {
editor->scroll = {line_index, *it_seg};
this->scroll = {line_index, *it_seg};
free(it->buffer);
free(it);
return;
@@ -94,17 +93,17 @@ void scroll_up(Editor *editor, int32_t number) {
free(it);
}
void scroll_down(Editor *editor, uint32_t number) {
if (!editor || number == 0)
void Editor::scroll_down(uint32_t number) {
if (number == 0)
return;
uint32_t numlen =
EXTRA_META + static_cast<int>(std::log10(editor->root->line_count + 1));
uint32_t render_width = editor->size.col - numlen;
uint32_t line_index = editor->scroll.row;
LineIterator *it = begin_l_iter(editor->root, line_index);
EXTRA_META + static_cast<int>(std::log10(this->root->line_count + 1));
uint32_t render_width = this->size.col - numlen;
uint32_t line_index = this->scroll.row;
LineIterator *it = begin_l_iter(this->root, line_index);
if (!it)
return;
const uint32_t max_visual_lines = editor->size.row;
const uint32_t max_visual_lines = this->size.row;
Coord *scroll_queue = (Coord *)malloc(sizeof(Coord) * max_visual_lines);
uint32_t q_head = 0;
uint32_t q_size = 0;
@@ -119,7 +118,7 @@ void scroll_down(Editor *editor, uint32_t number) {
line_len--;
uint32_t current_byte_offset = 0;
if (first_visual_line) {
current_byte_offset += editor->scroll.col;
current_byte_offset += this->scroll.col;
first_visual_line = false;
}
while (current_byte_offset < line_len ||
@@ -134,7 +133,7 @@ void scroll_down(Editor *editor, uint32_t number) {
}
visual_seen++;
if (visual_seen >= number + max_visual_lines) {
editor->scroll = scroll_queue[q_head];
this->scroll = scroll_queue[q_head];
free(scroll_queue);
free(it->buffer);
free(it);
@@ -162,7 +161,7 @@ void scroll_down(Editor *editor, uint32_t number) {
}
if (q_size > 0) {
uint32_t advance = (q_size > number) ? number : (q_size - 1);
editor->scroll = scroll_queue[(q_head + advance) % max_visual_lines];
this->scroll = scroll_queue[(q_head + advance) % max_visual_lines];
}
free(it->buffer);
free(it);

View File

@@ -1,47 +1,46 @@
#include "editor/editor.h"
#include "utils/utils.h"
void selection_bounds(Editor *editor, Coord *out_start, Coord *out_end) {
std::shared_lock lock(editor->knot_mtx);
void Editor::selection_bounds(Coord *out_start, Coord *out_end) {
Coord start, end;
if (editor->cursor >= editor->selection) {
if (this->cursor >= this->selection) {
uint32_t prev_col;
switch (editor->selection_type) {
switch (this->selection_type) {
case CHAR:
start = editor->selection;
end = move_right(editor, editor->cursor, 1);
start = this->selection;
end = this->move_right(this->cursor, 1);
break;
case WORD:
word_boundaries(editor, editor->selection, &prev_col, nullptr, nullptr,
nullptr);
start = {editor->selection.row, prev_col};
end = editor->cursor;
this->word_boundaries(this->selection, &prev_col, nullptr, nullptr,
nullptr);
start = {this->selection.row, prev_col};
end = this->cursor;
break;
case LINE:
start = {editor->selection.row, 0};
end = editor->cursor;
start = {this->selection.row, 0};
end = this->cursor;
break;
}
} else {
start = editor->cursor;
start = this->cursor;
uint32_t next_col, line_len;
switch (editor->selection_type) {
switch (this->selection_type) {
case CHAR:
end = move_right(editor, editor->selection, 1);
end = this->move_right(this->selection, 1);
break;
case WORD:
word_boundaries(editor, editor->selection, nullptr, &next_col, nullptr,
nullptr);
end = {editor->selection.row, next_col};
this->word_boundaries(this->selection, nullptr, &next_col, nullptr,
nullptr);
end = {this->selection.row, next_col};
break;
case LINE:
LineIterator *it = begin_l_iter(editor->root, editor->selection.row);
LineIterator *it = begin_l_iter(this->root, this->selection.row);
char *line = next_line(it, &line_len);
if (!line)
return;
if (line_len > 0 && line[line_len - 1] == '\n')
line_len--;
end = {editor->selection.row, line_len};
end = {this->selection.row, line_len};
free(it->buffer);
free(it);
break;
@@ -53,47 +52,46 @@ void selection_bounds(Editor *editor, Coord *out_start, Coord *out_end) {
*out_end = end;
}
char *get_selection(Editor *editor, uint32_t *out_len, Coord *out_start) {
std::shared_lock lock(editor->knot_mtx);
char *Editor::get_selection(uint32_t *out_len, Coord *out_start) {
Coord start, end;
if (editor->cursor >= editor->selection) {
if (this->cursor >= this->selection) {
uint32_t prev_col;
switch (editor->selection_type) {
switch (this->selection_type) {
case CHAR:
start = editor->selection;
end = move_right(editor, editor->cursor, 1);
start = this->selection;
end = this->move_right(this->cursor, 1);
break;
case WORD:
word_boundaries(editor, editor->selection, &prev_col, nullptr, nullptr,
nullptr);
start = {editor->selection.row, prev_col};
end = editor->cursor;
this->word_boundaries(this->selection, &prev_col, nullptr, nullptr,
nullptr);
start = {this->selection.row, prev_col};
end = this->cursor;
break;
case LINE:
start = {editor->selection.row, 0};
end = editor->cursor;
start = {this->selection.row, 0};
end = this->cursor;
break;
}
} else {
start = editor->cursor;
start = this->cursor;
uint32_t next_col, line_len;
switch (editor->selection_type) {
switch (this->selection_type) {
case CHAR:
end = move_right(editor, editor->selection, 1);
end = this->move_right(this->selection, 1);
break;
case WORD:
word_boundaries(editor, editor->selection, nullptr, &next_col, nullptr,
nullptr);
end = {editor->selection.row, next_col};
this->word_boundaries(this->selection, nullptr, &next_col, nullptr,
nullptr);
end = {this->selection.row, next_col};
break;
case LINE:
LineIterator *it = begin_l_iter(editor->root, editor->selection.row);
LineIterator *it = begin_l_iter(this->root, this->selection.row);
char *line = next_line(it, &line_len);
if (!line)
return nullptr;
if (line_len > 0 && line[line_len - 1] == '\n')
line_len--;
end = {editor->selection.row, line_len};
end = {this->selection.row, line_len};
free(it->buffer);
free(it);
break;
@@ -102,9 +100,9 @@ char *get_selection(Editor *editor, uint32_t *out_len, Coord *out_start) {
if (out_start)
*out_start = start;
uint32_t start_byte =
line_to_byte(editor->root, start.row, nullptr) + start.col;
uint32_t end_byte = line_to_byte(editor->root, end.row, nullptr) + end.col;
char *text = read(editor->root, start_byte, end_byte - start_byte);
line_to_byte(this->root, start.row, nullptr) + start.col;
uint32_t end_byte = line_to_byte(this->root, end.row, nullptr) + end.col;
char *text = read(this->root, start_byte, end_byte - start_byte);
if (out_len)
*out_len = end_byte - start_byte;
return text;

View File

@@ -1,37 +1,38 @@
#include "editor/editor.h"
void hover_diagnostic(Editor *editor) {
std::shared_lock lock(editor->v_mtx);
static uint32_t last_line = UINT32_MAX;
if (last_line == editor->cursor.row && !editor->warnings_dirty)
return;
VWarn dummy;
dummy.line = editor->cursor.row;
editor->warnings_dirty = false;
last_line = editor->cursor.row;
auto first =
std::lower_bound(editor->warnings.begin(), editor->warnings.end(), dummy);
auto last =
std::upper_bound(editor->warnings.begin(), editor->warnings.end(), dummy);
std::vector<VWarn> warnings_at_line(first, last);
if (warnings_at_line.size() == 0) {
editor->diagnostics_active = false;
return;
}
editor->diagnostics.clear();
editor->diagnostics.warnings.swap(warnings_at_line);
editor->diagnostics.render_first();
editor->diagnostics_active = true;
}
// void hover_diagnostic(Editor *editor) {
// static uint32_t last_line = UINT32_MAX;
// if (last_line == editor->cursor.row && !editor->warnings_dirty)
// return;
// VWarn dummy;
// dummy.line = editor->cursor.row;
// editor->warnings_dirty = false;
// last_line = editor->cursor.row;
// auto first =
// std::lower_bound(editor->warnings.begin(), editor->warnings.end(),
// dummy);
// auto last =
// std::upper_bound(editor->warnings.begin(), editor->warnings.end(),
// dummy);
// std::vector<VWarn> warnings_at_line(first, last);
// if (warnings_at_line.size() == 0) {
// editor->diagnostics_active = false;
// return;
// }
// editor->diagnostics.clear();
// editor->diagnostics.warnings.swap(warnings_at_line);
// editor->diagnostics.render_first();
// editor->diagnostics_active = true;
// }
void editor_worker(Editor *editor) {
if (!editor || !editor->root)
void Editor::work() {
if (!this->root)
return;
if (editor->parser)
editor->parser->work();
hover_diagnostic(editor);
if (editor->completion.active && editor->completion.hover_dirty) {
editor->completion.hover.render_first();
editor->completion.hover_dirty = false;
}
if (this->parser)
this->parser->work();
// hover_diagnostic(this);
// if (this->completion.active && this->completion.hover_dirty) {
// this->completion.hover.render_first();
// this->completion.hover_dirty = false;
// }
}