Lsp completion logic

This commit is contained in:
2026-01-04 03:27:17 +00:00
parent ac04754318
commit a905e333fc
24 changed files with 624 additions and 136 deletions

View File

@@ -0,0 +1,44 @@
#ifndef EDITOR_COMPLETIONS_H
#define EDITOR_COMPLETIONS_H
#include "editor/decl.h"
#include "pch.h"
#include "ui/completionbox.h"
#include "utils/utils.h"
struct CompletionItem {
std::string label; // Shown in the autocomplete box
uint8_t kind; // Function, variable, class, etc.
std::optional<std::string> detail; // Shown greyed in autocomplete box
std::optional<std::string> documentation; // Hover box (can be lazy-loaded)
bool is_markup = false;
bool deprecated = false; // Shown with strikethrough, may push down in list
std::string sort; // Used for sorting
std::string filter; // Used for filtering (default: label)
bool snippet = false;
std::vector<TextEdit> edits;
json original;
std::vector<char> end_chars; // Ends completion session if typed
};
struct CompletionSession {
std::shared_mutex mtx;
bool active = false;
Coord hook; // set to start of word
std::optional<std::string> prefix; // text between hook and cursor
uint8_t select = 0; // index of selected item (defualts to preselcted one
// when data requested)
std::vector<CompletionItem> items;
std::vector<uint8_t> visible;
bool complete = true; // If false, client may request more items on filter
// (but doesnt try filtering on its own)
std::optional<char> trigger_char; // Character that triggered completion sent
// to lsp for isIncomplete resolving
uint8_t trigger = 0; // Type of trigger (1: manual, 2: trigger char, 3: auto)
CompletionBox box;
CompletionSession() : box(this) {}
};
#endif

View File

@@ -3,6 +3,14 @@
#include "utils/utils.h"
struct TextEdit {
// NOTE: start.col is in utf16 index and not clusters or utf8
Coord start;
// NOTE: end.col is in utf16 index and not clusters or utf8
Coord end;
std::string text;
};
struct Fold {
uint32_t start;
uint32_t end;

View File

@@ -1,10 +1,12 @@
#ifndef EDITOR_H
#define EDITOR_H
#include "editor/completions.h"
#include "editor/spans.h"
#include "io/knot.h"
#include "io/sysio.h"
#include "ts/decl.h"
#include "ui/completionbox.h"
#include "ui/diagnostics.h"
#include "ui/hover.h"
#include "utils/utils.h"
@@ -49,6 +51,7 @@ struct Editor {
bool diagnostics_active;
DiagnosticBox diagnostics;
int lsp_version = 1;
CompletionSession completion;
};
Editor *new_editor(const char *filename_arg, Coord position, Coord size);
@@ -73,6 +76,8 @@ void ensure_scroll(Editor *editor);
void handle_editor_event(Editor *editor, KeyEvent event);
void edit_erase(Editor *editor, Coord pos, int64_t len);
void edit_insert(Editor *editor, Coord pos, char *data, uint32_t len);
void edit_replace(Editor *editor, Coord start, Coord end, const char *text,
uint32_t len);
Coord editor_hit_test(Editor *editor, uint32_t x, uint32_t y);
char *get_selection(Editor *editor, uint32_t *out_len, Coord *out_start);
void editor_worker(Editor *editor);
@@ -90,6 +95,13 @@ uint32_t leading_indent(const char *line, uint32_t len);
uint32_t get_indent(Editor *editor, Coord cursor);
bool closing_after_cursor(const char *line, uint32_t len, uint32_t col);
void editor_lsp_handle(Editor *editor, json msg);
void apply_lsp_edits(Editor *editor, std::vector<TextEdit> edits);
void completion_resolve_doc(Editor *editor);
void complete_accept(Editor *editor);
void complete_next(Editor *editor);
void complete_prev(Editor *editor);
void complete_select(Editor *editor, uint8_t index);
void handle_completion(Editor *editor, KeyEvent event);
inline void apply_hook_insertion(Editor *editor, uint32_t line, uint32_t rows) {
for (auto &hook : editor->hooks)

View File

@@ -62,19 +62,33 @@ struct ScreenCell {
};
struct KeyEvent {
/* KEY_CHAR, KEY_SPECIAL, KEY_MOUSE, KEY_PASTE, KEY_NONE */
uint8_t key_type;
/* the character / string if key_type == KEY_CHAR or KEY_PASTE */
char *c;
/* length of c */
uint32_t len;
/* KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_DELETE if key_type ==
* KEY_SPECIAL */
uint8_t special_key;
/* ALT, CNTRL, CNTRL_ALT, SHIFT if key_type == KEY_SPECIAL */
uint8_t special_modifier;
/* column of mouse click */
uint8_t mouse_x;
/* row of mouse click */
uint8_t mouse_y;
/* LEFT_BTN, MIDDLE_BTN, RIGHT_BTN, SCROLL_BTN, NONE_BTN if key_type ==
* KEY_MOUSE */
uint8_t mouse_button;
/* PRESS, RELEASE, DRAG, SCROLL if key_type == KEY_MOUSE */
uint8_t mouse_state;
/* SCROLL_UP, SCROLL_DOWN, SCROLL_LEFT, SCROLL_RIGHT if key_type ==
* KEY_MOUSE and mouse_state == SCROLL */
uint8_t mouse_direction;
/* ALT, CNTRL, CNTRL_ALT, SHIFT if key_type == KEY_MOUSE */
uint8_t mouse_modifier;
};
@@ -97,7 +111,8 @@ void update(uint32_t row, uint32_t col, std::string utf8, uint32_t fg,
uint32_t bg, uint8_t flags, uint32_t ul_color);
void update(uint32_t row, uint32_t col, const char *utf8, uint32_t fg,
uint32_t bg, uint8_t flags, uint32_t ul_color);
void set_cursor(int row, int col, int type, bool show_cursor_param);
void set_cursor(uint32_t row, uint32_t col, uint32_t type,
bool show_cursor_param);
void render();
Coord get_size();

View File

@@ -34,7 +34,9 @@ struct LSPInstance {
bool incremental_sync = false;
bool allow_hover = false;
bool allow_completion = false;
std::string trigger_chars;
bool allow_resolve = false;
std::vector<char> trigger_chars;
std::vector<char> end_chars;
uint32_t last_id = 0;
Queue<json> inbox;
Queue<json> outbox;
@@ -53,12 +55,15 @@ static json client_capabilities = {
{"hover", {{"contentFormat", {"markdown", "plaintext"}}}},
{"completion",
{{"completionItem",
{{"snippetSupport", true},
{{"commitCharactersSupport", true},
{"dynamicRegistration", false},
{"snippetSupport", true},
{"documentationFormat", {"markdown", "plaintext"}},
{"resolveSupport", {{"properties", {"documentation", "detail"}}}},
{"resolveSupport", {{"properties", {"documentation"}}}},
{"insertReplaceSupport", true},
{"labelDetailsSupport", true},
{"insertTextModeSupport", {{"valueSet", {1}}}}}},
{"insertTextModeSupport", {{"valueSet", {1}}}},
{"deprecatedSupport", true}}},
{"completionItemKind", {{"valueSet", {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}}},
{"contextSupport", true},
{"insertTextMode", 1}}}}}};

View File

@@ -4,6 +4,9 @@
#define PCRE2_CODE_UNIT_WIDTH 8
#define PCRE_WORKSPACE_SIZE 512
#include <magic.h>
#include <nlohmann/json.hpp>
#include <pcre2.h>
extern "C" {
#include "libgrapheme/grapheme.h"
#include "unicode_width/unicode_width.h"
@@ -25,12 +28,9 @@ extern "C" {
#include <fstream>
#include <functional>
#include <limits.h>
#include <magic.h>
#include <map>
#include <mutex>
#include <nlohmann/json.hpp>
#include <optional>
#include <pcre2.h>
#include <queue>
#include <shared_mutex>
#include <signal.h>

View File

@@ -7,9 +7,9 @@
#define TS_DEF(name) extern "C" const TSLanguage *LANG(name)()
struct Language {
std::string name;
const TSLanguage *(*fn)();
uint8_t lsp_id;
std::string name = "unknown";
const TSLanguage *(*fn)() = nullptr;
uint8_t lsp_id = 0;
uint32_t color = 0xFFFFFF;
const char *symbol = "";
};

View File

@@ -0,0 +1,20 @@
#ifndef UI_COMPLETIONBOX_H
#define UI_COMPLETIONBOX_H
#include "io/sysio.h"
#include "pch.h"
#include "utils/utils.h"
struct CompletionBox {
struct CompletionSession *session;
bool hidden = true;
std::vector<ScreenCell> cells;
Coord size;
Coord position;
CompletionBox(CompletionSession *s) : session(s) {}
void render_update();
void render(Coord pos);
};
#endif

View File

@@ -9,8 +9,7 @@
struct DiagnosticBox {
std::vector<VWarn> warnings;
std::vector<ScreenCell> cells;
uint32_t box_width;
uint32_t box_height;
Coord size;
void clear();
void render_first();

View File

@@ -12,8 +12,7 @@ struct HoverBox {
std::atomic<bool> is_markup;
uint32_t scroll_;
std::vector<ScreenCell> cells;
uint32_t box_width;
uint32_t box_height;
Coord size;
std::vector<Highlight> highlights;
std::vector<Span> hover_spans;

View File

@@ -61,6 +61,8 @@ struct Match {
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define UNUSED(x) (void)(x)
#define USING(x) UNUSED(sizeof(x))
std::string clean_text(const std::string &input);
std::string percent_encode(const std::string &s);
@@ -74,6 +76,7 @@ uint32_t get_visual_col_from_bytes(const char *line, uint32_t len,
uint32_t get_bytes_from_visual_col(const char *line, uint32_t len,
uint32_t target_visual_col);
int utf8_byte_offset_to_utf16(const char *s, size_t byte_pos);
size_t utf16_offset_to_utf8(const char *s, int utf16_pos);
void log(const char *fmt, ...);