diff --git a/include/editor/editor.h b/include/editor/editor.h index f652f32..52f8965 100644 --- a/include/editor/editor.h +++ b/include/editor/editor.h @@ -2,12 +2,12 @@ #define EDITOR_H #include "editor/indents.h" +#include "extentions/diagnostics.h" #include "extentions/hover.h" #include "io/knot.h" #include "io/sysio.h" #include "syntax/extras.h" #include "syntax/parser.h" -#include "ui/diagnostics.h" #include "utils/utils.h" #include "windows/decl.h" @@ -39,7 +39,7 @@ struct Editor : Window { std::shared_mutex lsp_mtx; std::atomic lsp = nullptr; HoverBox *hover_popup = init_hover(); - bool diagnostics_active = false; + DiagnosticBox *diagnostic_popup = init_diagnostic(); std::atomic lsp_version = 1; IndentationEngine indents = {}; Parser *parser = nullptr; diff --git a/include/extentions/diagnostics.h b/include/extentions/diagnostics.h new file mode 100644 index 0000000..6409a15 --- /dev/null +++ b/include/extentions/diagnostics.h @@ -0,0 +1,22 @@ +#ifndef EXTENTION_DIAGNOSTICS_H +#define EXTENTION_DIAGNOSTICS_H + +#include "editor/decl.h" +#include "io/sysio.h" +#include "pch.h" +#include "utils/utils.h" +#include "windows/decl.h" + +struct DiagnosticBox : Popup { + std::vector warnings; + + DiagnosticBox() { this->hidden = true; } + void clear() { this->warnings.clear(); } + void render(std::vector &buffer, Coord size, Coord pos) override; + void handle_click(KeyEvent, Coord) override { this->hidden = true; }; + ~DiagnosticBox() {}; +}; + +DiagnosticBox *init_diagnostic(); + +#endif diff --git a/include/ui/diagnostics.h b/include/ui/diagnostics.h deleted file mode 100644 index fe9fd88..0000000 --- a/include/ui/diagnostics.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef UI_DIAGNOSTICS_H -#define UI_DIAGNOSTICS_H - -#include "editor/decl.h" -#include "io/sysio.h" -#include "pch.h" -#include "utils/utils.h" - -struct DiagnosticBox { - std::vector warnings; - std::vector cells; - Coord size; - - void clear(); - void render_first(); - void render(Coord pos); -}; - -#endif diff --git a/include/windows/decl.h b/include/windows/decl.h index 65fa22c..93560b0 100644 --- a/include/windows/decl.h +++ b/include/windows/decl.h @@ -113,16 +113,6 @@ extern std::vector> popups; extern std::vector> floating_tiles; } // namespace layout -inline void close(Popup *handle) { - std::erase_if(layout::popups, - [handle](const auto &p) { return p.get() == handle; }); -} - -inline void close(TileBase *handle) { - std::erase_if(layout::floating_tiles, - [handle](const auto &p) { return p.get() == handle; }); -} - void render(); void handle_click(KeyEvent event); diff --git a/src/editor/renderer.cc b/src/editor/renderer.cc index 4e54d7c..8a6ed3f 100644 --- a/src/editor/renderer.cc +++ b/src/editor/renderer.cc @@ -467,14 +467,10 @@ void Editor::render(std::vector &buffer, Coord size, Coord pos) { break; } set_cursor(cursor.row, cursor.col, type, true); - // 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_popup->hidden) this->hover_popup->pos = cursor; + if (!this->diagnostic_popup->hidden) + this->diagnostic_popup->pos = cursor; } free(it->buffer); free(it); diff --git a/src/editor/worker.cc b/src/editor/worker.cc index 2c73aea..5aa09e8 100644 --- a/src/editor/worker.cc +++ b/src/editor/worker.cc @@ -1,36 +1,33 @@ #include "editor/editor.h" -// 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 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 warnings_at_line(first, last); + if (warnings_at_line.size() == 0) { + editor->diagnostic_popup->hidden = true; + return; + } + editor->diagnostic_popup->clear(); + editor->diagnostic_popup->warnings.swap(warnings_at_line); + editor->diagnostic_popup->hidden = false; +} void Editor::work() { if (!this->root) return; if (this->parser) this->parser->work(); - // hover_diagnostic(this); + hover_diagnostic(this); // if (this->completion.active && this->completion.hover_dirty) { // this->completion.hover.render_first(); // this->completion.hover_dirty = false; diff --git a/src/extentions/diagnostics.cc b/src/extentions/diagnostics.cc new file mode 100644 index 0000000..8e5c8a0 --- /dev/null +++ b/src/extentions/diagnostics.cc @@ -0,0 +1,187 @@ +#include "extentions/diagnostics.h" +#include + +DiagnosticBox *init_diagnostic() { + auto diagnostic = std::make_unique(); + diagnostic->pos = {0, 0}; + diagnostic->size = {1, 1}; + diagnostic->hidden = true; + DiagnosticBox *ptr = diagnostic.get(); + layout::popups.push_back(std::move(diagnostic)); + return ptr; +} + +void DiagnosticBox::render(std::vector &buffer, Coord n_size, + Coord n_pos) { + pos = n_pos; + size = n_size; + 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 = {io::rows, io::cols}; + if (start_col + size.col > screen_size.col) { + start_col = screen_size.col - size.col; + if (start_col < 0) + start_col = 0; + } + pos.col = start_col; + pos.row = start_row; + if (warnings.empty()) + return; + uint32_t longest_line = 8 + warnings[0].source.length(); + for (auto &warn : warnings) { + uint32_t longest = 0; + uint32_t cur = 0; + for (char ch : warn.text_full) + if (ch == '\n') { + longest = MAX(longest, cur); + cur = 0; + } else { + if (ch == '\t') + cur += 3; + ++cur; + } + longest = MAX(longest, cur); + longest_line = MAX(longest_line, longest + 7); + longest_line = MAX(longest_line, (uint32_t)warn.code.length() + 4); + for (auto &see_also : warn.see_also) + longest_line = MAX(longest_line, (uint32_t)see_also.length() + 4); + } + uint32_t content_width = MIN(longest_line, 150u); + size.col = content_width + 2; + auto set = [&](uint32_t r, uint32_t c, std::string text, uint32_t fg, + uint32_t bg, uint8_t flags, uint32_t width) { + if (r < 0 || r >= size.row || c < 0 || c >= size.col) + return; + r += pos.row; + c += pos.col; + if (r < 0 || r >= screen_size.row || c < 0 || c >= screen_size.col) + return; + ScreenCell &cell = buffer[r * screen_size.col + c]; + cell.utf8 = std::move(text); + cell.width = width; + cell.fg = fg; + cell.bg = bg; + cell.flags = flags; + cell.ul_color = 0; + }; + uint32_t base_bg = 0; + uint32_t border_fg = 0x82AAFF; + uint32_t r = 0; + if (warnings[0].source != "") { + std::string src_txt = "Source: "; + uint32_t i = 0; + for (; i < 8 && i < content_width; i++) + set(1, i + 1, (char[2]){src_txt[i], 0}, 0x3EAAFF, base_bg, 0, 1); + for (; i < 8 + warnings[0].source.length() && i < content_width; i++) + set(1, i + 1, (char[2]){warnings[0].source[i - 8], 0}, 0xffffff, base_bg, + 0, 1); + while (i < content_width) + set(1, ++i, " ", 0xffffff, base_bg, 0, 1); + r++; + } + int idx = 1; + for (auto &warn : warnings) { + char buf[4]; + std::snprintf(buf, sizeof(buf), "%2d", idx % 100); + std::string line_txt = std::string(buf) + ". "; + for (uint32_t i = 0; i < line_txt.length(); i++) + set(r + 1, i + 1, (char[2]){line_txt[i], 0}, 0xffffff, base_bg, 0, 1); + if (r >= 23) + break; + const char *err_sym = ""; + uint32_t c_sym = 0xAAAAAA; + switch (warn.type) { + case 1: + err_sym = ""; + c_sym = 0xFF0000; + break; + case 2: + err_sym = ""; + c_sym = 0xFFFF00; + break; + case 3: + err_sym = ""; + c_sym = 0xFF00FF; + break; + case 4: + err_sym = ""; + c_sym = 0xAAAAAA; + break; + } + std::string text = warn.text_full + " " + err_sym; + uint32_t i = 0; + while (i < text.length() && r < 23) { + uint32_t c = 4; + while (c < content_width && i < text.length()) { + if (text[i] == '\n') { + while (i < text.length() && text[i] == '\n') + i++; + break; + } + uint32_t cluster_len = grapheme_next_character_break_utf8( + text.c_str() + i, text.length() - i); + std::string cluster = text.substr(i, cluster_len); + int width = display_width(cluster.c_str(), cluster_len); + if (c + width > content_width) + break; + set(r + 1, c + 1, cluster.c_str(), c_sym, base_bg, 0, width); + c += width; + i += cluster_len; + for (int w = 1; w < width; w++) + set(r + 1, c - w + 1, "\x1b", c_sym, base_bg, 0, 0); + } + while (c < content_width) + set(r + 1, ++c, " ", 0xffffff, base_bg, 0, 1); + r++; + } + if (r >= 23) + break; + if (warn.code != "") { + uint32_t i = 0; + for (; i < 5 && i < content_width; i++) + set(r + 1, i, " ", 0x81cdc6, base_bg, 0, 1); + for (; i < warn.code.length() + 5 && i < content_width; i++) + set(r + 1, i, (char[2]){warn.code[i - 5], 0}, 0x81cdc6, base_bg, 0, 1); + while (i <= content_width) + set(r + 1, i++, " ", 0x81cdc6, base_bg, 0, 1); + r++; + } + if (r >= 23) + break; + for (std::string &see_also : warn.see_also) { + uint32_t fg = 0xB55EFF; + uint8_t colon_count = 0; + uint32_t i = 0; + for (; i < 5 && i < content_width; i++) + 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] == ':') + colon_count++; + if (colon_count == 2) + fg = 0xFFFFFF; + } + while (i <= content_width) + set(r + 1, i++, " ", fg, base_bg, 0, 1); + r++; + if (r >= 23) + break; + }; + idx++; + } + size.row = 2 + r; + set(0, 0, "┌", border_fg, base_bg, 0, 1); + for (uint32_t i = 1; i < size.col - 1; i++) + set(0, i, "─", border_fg, base_bg, 0, 1); + set(0, size.col - 1, "┐", border_fg, base_bg, 0, 1); + for (uint32_t r = 1; r < size.row - 1; r++) { + set(r, 0, "│", border_fg, base_bg, 0, 1); + set(r, size.col - 1, "│", border_fg, base_bg, 0, 1); + } + set(size.row - 1, 0, "└", border_fg, base_bg, 0, 1); + for (uint32_t i = 1; i < size.col - 1; i++) + set(size.row - 1, i, "─", border_fg, base_bg, 0, 1); + set(size.row - 1, size.col - 1, "┘", border_fg, base_bg, 0, 1); +} diff --git a/src/extentions/hover.cc b/src/extentions/hover.cc index 01d57c0..1676fca 100644 --- a/src/extentions/hover.cc +++ b/src/extentions/hover.cc @@ -36,7 +36,7 @@ void HoverBox::render(std::vector &buffer, Coord n_size, 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; // pos here is the cursor pos + int32_t start_col = pos.col; Coord screen_size = {io::rows, io::cols}; if (start_col + size.col > screen_size.col) { start_col = screen_size.col - size.col; diff --git a/src/syntax/parser.cc b/src/syntax/parser.cc index 12b3193..cdd33a0 100644 --- a/src/syntax/parser.cc +++ b/src/syntax/parser.cc @@ -45,14 +45,13 @@ void Parser::work() { if (!editor || !editor->root) return; std::vector batch; - uint32_t c_line; uint32_t line_count = editor->root->line_count + 1; - for (uint32_t i = MAX(0, (int64_t)scroll_max - MAX_LINES_LOOKBEHIND); - i <= scroll_max + 10 && i < line_count; ++i) { + int64_t start = MIN(scroll_max + 10, line_count - 1); + int64_t end = MAX(0, (int64_t)scroll_max - MAX_LINES_LOOKBEHIND); + for (int64_t i = start; i >= end; --i) { auto l_opt = line_map.at(i); if (!l_opt || (l_opt && !l_opt->out_state)) batch.push_back(i); - i++; } for (uint32_t c_line : batch) { if (!running.load(std::memory_order_relaxed)) diff --git a/src/ui/diagnostics.cc b/src/ui/diagnostics.cc deleted file mode 100644 index ae98033..0000000 --- a/src/ui/diagnostics.cc +++ /dev/null @@ -1,164 +0,0 @@ -// #include "ui/diagnostics.h" -// -// void DiagnosticBox::clear() { -// warnings.clear(); -// cells.clear(); -// size = {0, 0}; -// }; -// -// void DiagnosticBox::render_first() { -// if (warnings.empty()) -// return; -// uint32_t longest_line = 8 + warnings[0].source.length(); -// for (auto &warn : warnings) { -// uint32_t longest = 0; -// uint32_t cur = 0; -// for (char ch : warn.text_full) -// if (ch == '\n') { -// longest = MAX(longest, cur); -// cur = 0; -// } else { -// if (ch == '\t') -// cur += 3; -// ++cur; -// } -// longest = MAX(longest, cur); -// longest_line = MAX(longest_line, longest + 7); -// longest_line = MAX(longest_line, (uint32_t)warn.code.length() + 4); -// for (auto &see_also : warn.see_also) -// longest_line = MAX(longest_line, (uint32_t)see_also.length() + 4); -// } -// uint32_t content_width = MIN(longest_line, 150u); -// size.col = content_width + 2; -// cells.assign(size.col * 25, {" ", 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) { -// cells[r * size.col + c] = {std::string(text), 0, fg, bg, flags, 0}; -// }; -// uint32_t base_bg = 0; -// uint32_t border_fg = 0x82AAFF; -// uint32_t r = 0; -// if (warnings[0].source != "") { -// std::string src_txt = "Source: "; -// for (uint32_t i = 0; i < src_txt.length() && i < content_width; i++) -// set(1, i + 1, (char[2]){src_txt[i], 0}, 0x3EAAFF, base_bg, 0); -// for (uint32_t i = 0; i < warnings[0].source.length() && i < -// content_width; -// i++) -// set(1, i + 1 + src_txt.length(), (char[2]){warnings[0].source[i], 0}, -// 0xffffff, base_bg, 0); -// r++; -// } -// int idx = 1; -// for (auto &warn : warnings) { -// char buf[4]; -// std::snprintf(buf, sizeof(buf), "%2d", idx % 100); -// std::string line_txt = std::string(buf) + ". "; -// for (uint32_t i = 0; i < line_txt.length(); i++) -// set(r + 1, i + 1, (char[2]){line_txt[i], 0}, 0xffffff, base_bg, 0); -// if (r >= 23) -// break; -// const char *err_sym = ""; -// uint32_t c_sym = 0xAAAAAA; -// switch (warn.type) { -// case 1: -// err_sym = ""; -// c_sym = 0xFF0000; -// break; -// case 2: -// err_sym = ""; -// c_sym = 0xFFFF00; -// break; -// case 3: -// err_sym = ""; -// c_sym = 0xFF00FF; -// break; -// case 4: -// err_sym = ""; -// c_sym = 0xAAAAAA; -// break; -// } -// std::string text = warn.text_full + " " + err_sym; -// uint32_t i = 0; -// while (i < text.length() && r < 23) { -// uint32_t c = 4; -// while (c < content_width && i < text.length()) { -// if (text[i] == '\n') { -// while (i < text.length() && text[i] == '\n') -// i++; -// break; -// } -// uint32_t cluster_len = grapheme_next_character_break_utf8( -// text.c_str() + i, text.length() - i); -// std::string cluster = text.substr(i, cluster_len); -// int width = display_width(cluster.c_str(), cluster_len); -// if (c + width > content_width) -// break; -// set(r + 1, c + 1, cluster.c_str(), c_sym, base_bg, 0); -// c += width; -// i += cluster_len; -// for (int w = 1; w < width; w++) -// set(r + 1, c - w + 1, "\x1b", c_sym, base_bg, 0); -// } -// r++; -// } -// if (r >= 23) -// break; -// if (warn.code != "") { -// for (uint32_t i = 0; i < warn.code.length() && i + 5 < content_width; -// i++) -// set(r + 1, i + 5, (char[2]){warn.code[i], 0}, 0x81cdc6, base_bg, 0); -// r++; -// } -// if (r >= 23) -// break; -// for (std::string &see_also : warn.see_also) { -// uint32_t fg = 0xB55EFF; -// uint8_t colon_count = 0; -// for (uint32_t i = 0; i < see_also.length() && i + 5 < content_width; -// i++) { -// set(r + 1, i + 5, (char[2]){see_also[i], 0}, fg, base_bg, 0); -// if (see_also[i] == ':') -// colon_count++; -// if (colon_count == 2) -// fg = 0xFFFFFF; -// } -// r++; -// if (r >= 23) -// break; -// }; -// idx++; -// } -// size.row = 2 + r; -// set(0, 0, "┌", border_fg, base_bg, 0); -// for (uint32_t i = 1; i < size.col - 1; i++) -// set(0, i, "─", border_fg, base_bg, 0); -// set(0, size.col - 1, "┐", border_fg, base_bg, 0); -// for (uint32_t r = 1; r < size.row - 1; r++) { -// set(r, 0, "│", border_fg, base_bg, 0); -// set(r, size.col - 1, "│", border_fg, base_bg, 0); -// } -// set(size.row - 1, 0, "└", border_fg, base_bg, 0); -// for (uint32_t i = 1; i < size.col - 1; i++) -// set(size.row - 1, i, "─", border_fg, base_bg, 0); -// set(size.row - 1, size.col - 1, "┘", border_fg, base_bg, 0); -// cells.resize(size.col * size.row); -// } -// -// void DiagnosticBox::render(Coord pos) { -// 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; -// } -// 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); -// }