Fix file permissions

This commit is contained in:
2026-07-01 18:53:49 +01:00
parent 013bffcad9
commit 10287e1750
107 changed files with 882 additions and 827 deletions
Executable → Regular
+4 -1
View File
@@ -17,7 +17,10 @@ void Editor::ensure_cursor() {
render_height < this->size.row) {
render_height++;
last_visible = vline.first;
if (cursor >= vline.first && cursor < vline.second)
log("Render H: %d, Cursor: %d,%d, Visible: %d,%d - %d,%d", render_height,
this->cursor.row, this->cursor.col, vline.first.row, vline.first.col,
vline.second.row, vline.second.col);
if (cursor >= vline.first && cursor <= vline.second)
return;
}
cursor = last_visible;
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
+456 -458
View File
@@ -1,458 +1,456 @@
// #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();
// }
/* #include "editor/editor.h"
#include "io/knot.h"
#include "io/sysio.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;
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();
}
*/
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
-68
View File
@@ -1,5 +1,4 @@
#include "editor/editor.h"
#include "editor/decl.h"
#include "lsp/lsp.h"
#include "main.h"
#include "syntax/langs.h"
@@ -58,7 +57,6 @@ Editor::~Editor() {
void Editor::save() {
if (!this->root)
return;
int version = this->lsp_version;
uint32_t char_count = this->root->char_count;
char *str = read(this->root, 0, char_count);
if (!str)
@@ -77,70 +75,4 @@ void Editor::save() {
free(str);
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 = msg.message["result"];
if (edits.is_array()) {
std::vector<TextEdit> t_edits;
t_edits.reserve(edits.size());
for (auto &edit : edits) {
TextEdit t_edit;
t_edit.text = edit.value("newText", "");
t_edit.start.row = edit["range"]["start"]["line"];
t_edit.start.col = edit["range"]["start"]["character"];
t_edit.end.row = edit["range"]["end"]["line"];
t_edit.end.col = edit["range"]["end"]["character"];
msg.editor->utf8_normalize_edit(&t_edit);
t_edits.push_back(t_edit);
}
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;
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');
out.put(str[i]);
}
} else {
out.write(str, char_count);
}
out.close();
free(str);
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(std::move(save_msg));
}
}
}
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
+69 -8
View File
@@ -238,6 +238,73 @@ void Editor::insert_char(char c) {
}
}
void Editor::format_full(int version) {
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) {
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) {
if (version != msg.editor->lsp_version)
return;
auto &edits = msg.message["result"];
if (edits.is_array()) {
std::vector<TextEdit> t_edits;
t_edits.reserve(edits.size());
for (auto &edit : edits) {
TextEdit t_edit;
t_edit.text = edit.value("newText", "");
t_edit.start.row = edit["range"]["start"]["line"];
t_edit.start.col = edit["range"]["start"]["character"];
t_edit.end.row = edit["range"]["end"]["line"];
t_edit.end.col = edit["range"]["end"]["character"];
msg.editor->utf8_normalize_edit(&t_edit);
t_edits.push_back(t_edit);
}
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;
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');
out.put(str[i]);
}
} else {
out.write(str, char_count);
}
out.close();
free(str);
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(std::move(save_msg));
}
}
}
void Editor::normal_mode() {
Coord prev_pos = this->cursor;
mode = NORMAL;
@@ -431,19 +498,13 @@ void Editor::handle_click(KeyEvent event, Coord size) {
case SCROLL:
switch (event.mouse_direction) {
case SCROLL_UP:
this->scroll_up(4);
this->scroll_up(1);
this->ensure_cursor();
break;
case SCROLL_DOWN:
this->scroll_down(4);
this->scroll_down(1);
this->ensure_cursor();
break;
case SCROLL_LEFT:
this->cursor_left(10);
break;
case SCROLL_RIGHT:
this->cursor_right(10);
break;
}
break;
case PRESS:
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
+1 -1
View File
@@ -9,7 +9,7 @@ void Editor::render(std::vector<ScreenCell> &buffer, Coord size, Coord pos) {
uint32_t sel_start = 0, sel_end = 0;
uint32_t numlen =
EXTRA_META + static_cast<int>(std::log10(this->root->line_count + 1));
uint32_t render_width = size.col - numlen;
uint32_t render_width = size.col - numlen - 1;
uint32_t render_x = pos.col + numlen + 1;
this->hooks.start_iter(this->scroll.row);
auto warn_it = this->warnings.begin();
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
+3 -2
View File
@@ -1,5 +1,4 @@
#include "extentions/diagnostics.h"
#include <cstdint>
DiagnosticBox *init_diagnostic() {
auto diagnostic = std::make_unique<DiagnosticBox>();
@@ -11,6 +10,8 @@ DiagnosticBox *init_diagnostic() {
return ptr;
}
// TODO: Make this code more readable, It works fine tho.
void DiagnosticBox::render(std::vector<ScreenCell> &buffer, Coord n_size,
Coord n_pos) {
pos = n_pos;
@@ -158,7 +159,7 @@ void DiagnosticBox::render(std::vector<ScreenCell> &buffer, Coord n_size,
set(r + 1, i, " ", 0x81cdc6, base_bg, 0, 1);
for (; i < see_also.length() + 5 && i < content_width; i++) {
set(r + 1, i, (char[2]){see_also[i - 5], 0}, fg, base_bg, 0, 1);
if (see_also[i] == ':')
if (see_also[i - 5] == ':')
colon_count++;
if (colon_count == 2)
fg = 0xFFFFFF;
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
+5 -1
View File
@@ -7,7 +7,7 @@ std::unordered_set<std::string> opened;
Queue<std::string> need_opening;
std::vector<Editor *> new_editors;
Queue<std::unique_ptr<LSPMessage>> response_queue;
} // namespace lsp
}
void lsp_worker() {
std::lock_guard lock(lsp::lsp_mutex);
@@ -22,6 +22,10 @@ void lsp_worker() {
for (auto it = lsp::new_editors.begin(); it != lsp::new_editors.end();) {
auto ed = *it;
auto lsp_id = ed->lang.lsp_name;
if (lsp_id.empty()) {
it = lsp::new_editors.erase(it);
continue;
}
if (lsp::opened.contains(lsp_id)) {
auto a_it = lsp::active_lsps.find(lsp_id);
if (a_it != lsp::active_lsps.end())
Executable → Regular
View File
Executable → Regular
+1
View File
@@ -1,6 +1,7 @@
#include "ruby/decl.h"
mrb_value get_config_file(mrb_state *mrb, mrb_value self) {
UNUSED(self);
return mrb_str_new_cstr(mrb, ruby_config_path.string().c_str());
}
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
+187 -187
View File
@@ -1,187 +1,187 @@
// #include "ui/completionbox.h"
// #include "editor/completions.h"
// #include "io/sysio.h"
// #include "utils/utils.h"
//
// std::string item_kind_name(uint8_t kind) {
// switch (kind) {
// case 1:
// return "Text";
// case 2:
// return "Method";
// case 3:
// return "Function";
// case 4:
// return "Constructor";
// case 5:
// return "Field";
// case 6:
// return "Variable";
// case 7:
// return "Class";
// case 8:
// return "Interface";
// case 9:
// return "Module";
// case 10:
// return "Property";
// case 11:
// return "Unit";
// case 12:
// return "Value";
// case 13:
// return "Enum";
// case 14:
// return "Keyword";
// case 15:
// return "Snippet";
// case 16:
// return "Color";
// case 17:
// return "File";
// case 18:
// return "Reference";
// case 19:
// return "Folder";
// case 20:
// return "EnumMember";
// case 21:
// return "Constant";
// case 22:
// return "Struct";
// case 23:
// return "Event";
// case 24:
// return "Operator";
// case 25:
// return "TypeParameter";
// default:
// return "Unknown";
// }
// }
//
// const char *item_symbol(uint8_t kind) { return "●"; }
//
// uint32_t kind_color(uint8_t kind) { return 0x82AAFF; }
//
// void CompletionBox::render_update() {
// if (hidden || session->visible.empty())
// return;
// std::unique_lock lock(mtx);
// uint32_t max_label_len = 0;
// uint32_t max_detail_len = 0;
// uint32_t max_kind_len = 0;
// for (uint32_t x = session->scroll;
// x < session->scroll + 8 && x < session->visible.size(); x++) {
// uint32_t i = session->visible[x];
// if (i >= session->items.size())
// continue;
// auto &item = session->items[i];
// max_label_len = MAX(max_label_len, (uint32_t)item.label.size());
// if (item.detail)
// max_detail_len = MAX(max_detail_len, (uint32_t)item.detail->size());
// max_kind_len =
// MAX(max_kind_len, (uint32_t)item_kind_name(item.kind).size());
// }
// uint32_t total = session->visible.size();
// uint32_t rows = MIN(total, 8);
// size.row = rows + 2;
// size.col = 2 + 2 + max_label_len + 1 + max_detail_len + 2 + max_kind_len +
// 1; cells.assign(size.row * size.col, {" ", 0, 0, 0, 0, 0}); auto set =
// [&](uint32_t r, uint32_t c, const char *text, uint32_t fg,
// uint32_t bg, uint8_t flags) {
// if (r < size.row && c < size.col)
// cells[r * size.col + c] = {std::string(text), 0, fg, bg, flags, 0};
// };
// uint32_t border_fg = 0x82AAFF;
// uint32_t sel_bg = 0x174225;
// set(0, 0, "┌", border_fg, 0, 0);
// for (uint32_t c = 1; c < size.col - 1; c++)
// set(0, c, "─", border_fg, 0, 0);
// set(0, size.col - 1, "┐", border_fg, 0, 0);
// uint32_t start = session->scroll;
// uint32_t end = MIN(start + 8, session->visible.size());
// for (uint32_t row_idx = start; row_idx < end; row_idx++) {
// uint32_t r = (row_idx - start) + 1;
// auto &item = session->items[session->visible[row_idx]];
// uint32_t bg = (session->visible[row_idx] == session->select) ? sel_bg :
// 1; uint32_t fg = 0xFFFFFF; set(r, 0, "│", border_fg, 0, 0); uint32_t c =
// 1; const char *sym = item_symbol(item.kind); set(r, c++, sym,
// kind_color(item.kind), bg, 0); set(r, c++, " ", fg, bg, 0); for (size_t i
// = 0; i < item.label.size(); i++)
// set(r, c + i, (char[2]){item.label[i], 0}, fg, bg,
// item.deprecated ? CF_STRIKETHROUGH : 0);
// c += item.label.size();
// set(r, c++, " ", fg, bg, 0);
// uint32_t detail_fg = 0xAAAAAA;
// if (item.detail) {
// for (size_t i = 0; i < item.detail->size(); i++)
// set(r, c + i, (char[2]){(*item.detail)[i], 0}, detail_fg, bg, 0);
// c += item.detail->size();
// }
// uint32_t pad = size.col - 1 - c - max_kind_len;
// for (uint32_t i = 0; i < pad; i++)
// set(r, c + i, " ", fg, bg, 0);
// c += pad;
// std::string kind_name = item_kind_name(item.kind);
// for (size_t i = 0; i < kind_name.size(); i++)
// set(r, c + i, (char[2]){kind_name[i], 0}, kind_color(item.kind), bg,
// 0);
// set(r, size.col - 1, "│", border_fg, 0, 0);
// }
// uint32_t bottom = size.row - 1;
// set(bottom, 0, "└", border_fg, 0, 0);
// for (uint32_t c = 1; c < size.col - 1; c++)
// set(bottom, c, "─", border_fg, 0, 0);
// set(bottom, size.col - 1, "┘", border_fg, 0, 0);
// if (session->visible.size() > 8) {
// std::string info = std::to_string(start + 1) + "-" + std::to_string(end)
// +
// "/" + std::to_string(session->visible.size());
// for (size_t i = 0; i < info.size() && i < size.col - 2; i++)
// set(bottom, 1 + i, (char[2]){info[i], 0}, border_fg, 0, 0);
// }
// }
//
// void CompletionBox::render(Coord pos) {
// if (hidden || session->visible.empty())
// return;
// std::shared_lock lock(mtx);
// int32_t start_row = (int32_t)pos.row - (int32_t)size.row;
// if (start_row < 0)
// start_row = pos.row + 1;
// int32_t start_col = pos.col;
// Coord screen_size = get_size();
// if (start_col + size.col > screen_size.col) {
// start_col = screen_size.col - size.col;
// if (start_col < 0)
// start_col = 0;
// }
// position = {(uint32_t)start_row, (uint32_t)start_col};
// for (uint32_t r = 0; r < size.row; r++)
// for (uint32_t c = 0; c < size.col; c++)
// update(start_row + r, start_col + c, cells[r * size.col + c].utf8,
// cells[r * size.col + c].fg, cells[r * size.col + c].bg,
// cells[r * size.col + c].flags);
// if (session->items.size() > session->select &&
// session->items[session->select].documentation &&
// *session->items[session->select].documentation != "" &&
// !session->hover_dirty) {
// if (session->doc != session->select) {
// session->doc = session->select;
// session->hover.clear();
// session->hover.text = *session->items[session->select].documentation;
// session->hover.is_markup = true;
// session->hover_dirty = true;
// } else {
// if ((int32_t)position.col - (int32_t)session->hover.size.col > 0) {
// session->hover.render({position.row + session->hover.size.row,
// position.col - session->hover.size.col});
// } else {
// session->hover.render(
// {position.row + session->hover.size.row, position.col +
// size.col});
// }
// }
// }
// }
/* #include "ui/completionbox.h"
#include "editor/completions.h"
#include "io/sysio.h"
#include "utils/utils.h"
std::string item_kind_name(uint8_t kind) {
switch (kind) {
case 1:
return "Text";
case 2:
return "Method";
case 3:
return "Function";
case 4:
return "Constructor";
case 5:
return "Field";
case 6:
return "Variable";
case 7:
return "Class";
case 8:
return "Interface";
case 9:
return "Module";
case 10:
return "Property";
case 11:
return "Unit";
case 12:
return "Value";
case 13:
return "Enum";
case 14:
return "Keyword";
case 15:
return "Snippet";
case 16:
return "Color";
case 17:
return "File";
case 18:
return "Reference";
case 19:
return "Folder";
case 20:
return "EnumMember";
case 21:
return "Constant";
case 22:
return "Struct";
case 23:
return "Event";
case 24:
return "Operator";
case 25:
return "TypeParameter";
default:
return "Unknown";
}
}
const char *item_symbol(uint8_t kind) { return "●"; }
uint32_t kind_color(uint8_t kind) { return 0x82AAFF; }
void CompletionBox::render_update() {
if (hidden || session->visible.empty())
return;
std::unique_lock lock(mtx);
uint32_t max_label_len = 0;
uint32_t max_detail_len = 0;
uint32_t max_kind_len = 0;
for (uint32_t x = session->scroll;
x < session->scroll + 8 && x < session->visible.size(); x++) {
uint32_t i = session->visible[x];
if (i >= session->items.size())
continue;
auto &item = session->items[i];
max_label_len = MAX(max_label_len, (uint32_t)item.label.size());
if (item.detail)
max_detail_len = MAX(max_detail_len, (uint32_t)item.detail->size());
max_kind_len =
MAX(max_kind_len, (uint32_t)item_kind_name(item.kind).size());
}
uint32_t total = session->visible.size();
uint32_t rows = MIN(total, 8);
size.row = rows + 2;
size.col = 2 + 2 + max_label_len + 1 + max_detail_len + 2 + max_kind_len +
1; cells.assign(size.row * size.col, {" ", 0, 0, 0, 0, 0}); auto set =
[&](uint32_t r, uint32_t c, const char *text, uint32_t fg,
uint32_t bg, uint8_t flags) {
if (r < size.row && c < size.col)
cells[r * size.col + c] = {std::string(text), 0, fg, bg, flags, 0};
};
uint32_t border_fg = 0x82AAFF;
uint32_t sel_bg = 0x174225;
set(0, 0, "┌", border_fg, 0, 0);
for (uint32_t c = 1; c < size.col - 1; c++)
set(0, c, "─", border_fg, 0, 0);
set(0, size.col - 1, "┐", border_fg, 0, 0);
uint32_t start = session->scroll;
uint32_t end = MIN(start + 8, session->visible.size());
for (uint32_t row_idx = start; row_idx < end; row_idx++) {
uint32_t r = (row_idx - start) + 1;
auto &item = session->items[session->visible[row_idx]];
uint32_t bg = (session->visible[row_idx] == session->select) ? sel_bg :
1; uint32_t fg = 0xFFFFFF; set(r, 0, "│", border_fg, 0, 0); uint32_t c =
1; const char *sym = item_symbol(item.kind); set(r, c++, sym,
kind_color(item.kind), bg, 0); set(r, c++, " ", fg, bg, 0); for (size_t i
= 0; i < item.label.size(); i++)
set(r, c + i, (char[2]){item.label[i], 0}, fg, bg,
item.deprecated ? CF_STRIKETHROUGH : 0);
c += item.label.size();
set(r, c++, " ", fg, bg, 0);
uint32_t detail_fg = 0xAAAAAA;
if (item.detail) {
for (size_t i = 0; i < item.detail->size(); i++)
set(r, c + i, (char[2]){(*item.detail)[i], 0}, detail_fg, bg, 0);
c += item.detail->size();
}
uint32_t pad = size.col - 1 - c - max_kind_len;
for (uint32_t i = 0; i < pad; i++)
set(r, c + i, " ", fg, bg, 0);
c += pad;
std::string kind_name = item_kind_name(item.kind);
for (size_t i = 0; i < kind_name.size(); i++)
set(r, c + i, (char[2]){kind_name[i], 0}, kind_color(item.kind), bg,
0);
set(r, size.col - 1, "│", border_fg, 0, 0);
}
uint32_t bottom = size.row - 1;
set(bottom, 0, "└", border_fg, 0, 0);
for (uint32_t c = 1; c < size.col - 1; c++)
set(bottom, c, "─", border_fg, 0, 0);
set(bottom, size.col - 1, "┘", border_fg, 0, 0);
if (session->visible.size() > 8) {
std::string info = std::to_string(start + 1) + "-" + std::to_string(end)
+
"/" + std::to_string(session->visible.size());
for (size_t i = 0; i < info.size() && i < size.col - 2; i++)
set(bottom, 1 + i, (char[2]){info[i], 0}, border_fg, 0, 0);
}
}
void CompletionBox::render(Coord pos) {
if (hidden || session->visible.empty())
return;
std::shared_lock lock(mtx);
int32_t start_row = (int32_t)pos.row - (int32_t)size.row;
if (start_row < 0)
start_row = pos.row + 1;
int32_t start_col = pos.col;
if (start_col + size.col > io::cols) {
start_col = io::cols - size.col;
if (start_col < 0)
start_col = 0;
}
position = {(uint32_t)start_row, (uint32_t)start_col};
for (uint32_t r = 0; r < size.row; r++)
for (uint32_t c = 0; c < size.col; c++)
update(start_row + r, start_col + c, cells[r * size.col + c].utf8,
cells[r * size.col + c].fg, cells[r * size.col + c].bg,
cells[r * size.col + c].flags);
if (session->items.size() > session->select &&
session->items[session->select].documentation &&
*session->items[session->select].documentation != "" &&
!session->hover_dirty) {
if (session->doc != session->select) {
session->doc = session->select;
session->hover.clear();
session->hover.text = *session->items[session->select].documentation;
session->hover.is_markup = true;
session->hover_dirty = true;
} else {
if ((int32_t)position.col - (int32_t)session->hover.size.col > 0) {
session->hover.render({position.row + session->hover.size.row,
position.col - session->hover.size.col});
} else {
session->hover.render(
{position.row + session->hover.size.row, position.col +
size.col});
}
}
}
}
*/
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File