summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--autocomplete.c48
-rw-r--r--base.h53
-rw-r--r--hover.c87
-rw-r--r--lsp-parse.c11
-rw-r--r--lsp.c49
-rw-r--r--lsp.h28
-rw-r--r--main.c12
-rw-r--r--ted.h58
-rw-r--r--text.c30
-rw-r--r--text.h4
10 files changed, 226 insertions, 154 deletions
diff --git a/autocomplete.c b/autocomplete.c
index 1271fba..1d03c75 100644
--- a/autocomplete.c
+++ b/autocomplete.c
@@ -54,6 +54,8 @@ void autocomplete_scroll(Ted *ted, i32 by) {
static void autocomplete_move_cursor(Ted *ted, i32 by) {
Autocomplete *ac = &ted->autocomplete;
u32 ncompletions = arr_len(ac->suggested);
+ if (ncompletions == 0)
+ return;
i32 cursor = ac->cursor;
cursor += by;
cursor = (i32)mod_i32(cursor, (i32)ncompletions);
@@ -186,6 +188,52 @@ static void autocomplete_find_completions(Ted *ted, uint32_t trigger) {
autocomplete_update_suggested(ted);
}
+static SymbolKind lsp_completion_kind_to_ted(LSPCompletionKind kind) {
+ switch (kind) {
+ case LSP_COMPLETION_TEXT:
+ case LSP_COMPLETION_MODULE:
+ case LSP_COMPLETION_UNIT:
+ case LSP_COMPLETION_COLOR:
+ case LSP_COMPLETION_FILE:
+ case LSP_COMPLETION_REFERENCE:
+ case LSP_COMPLETION_FOLDER:
+ case LSP_COMPLETION_OPERATOR:
+ return SYMBOL_OTHER;
+
+ case LSP_COMPLETION_METHOD:
+ case LSP_COMPLETION_FUNCTION:
+ case LSP_COMPLETION_CONSTRUCTOR:
+ return SYMBOL_FUNCTION;
+
+ case LSP_COMPLETION_FIELD:
+ case LSP_COMPLETION_PROPERTY:
+ return SYMBOL_FIELD;
+
+ case LSP_COMPLETION_VARIABLE:
+ return SYMBOL_VARIABLE;
+
+ case LSP_COMPLETION_CLASS:
+ case LSP_COMPLETION_INTERFACE:
+ case LSP_COMPLETION_ENUM:
+ case LSP_COMPLETION_STRUCT:
+ case LSP_COMPLETION_EVENT:
+ case LSP_COMPLETION_TYPEPARAMETER:
+ return SYMBOL_TYPE;
+
+ case LSP_COMPLETION_VALUE:
+ case LSP_COMPLETION_ENUMMEMBER:
+ case LSP_COMPLETION_CONSTANT:
+ return SYMBOL_CONSTANT;
+
+ case LSP_COMPLETION_KEYWORD:
+ case LSP_COMPLETION_SNIPPET:
+ return SYMBOL_KEYWORD;
+ }
+ assert(0);
+ return SYMBOL_OTHER;
+}
+
+
static void autocomplete_process_lsp_response(Ted *ted, const LSPResponse *response) {
const LSPRequest *request = &response->request;
if (request->type != LSP_REQUEST_COMPLETION)
diff --git a/base.h b/base.h
index 26e874e..bbb1be5 100644
--- a/base.h
+++ b/base.h
@@ -175,4 +175,57 @@ static void print(char const *fmt, ...) {
#define debug_println(...)
#endif
+// NOTE: these have to be defined here because lsp.h uses them
+
+// If you are adding new languages, DO NOT change the constant values
+// of the previous languages. It will mess up config files which use :set-language!
+typedef enum {
+ LANG_NONE = 0,
+ LANG_C = 1,
+ LANG_CPP = 2,
+ LANG_RUST = 3,
+ LANG_PYTHON = 4,
+ LANG_TEX = 5,
+ LANG_MARKDOWN = 6,
+ LANG_HTML = 7,
+ LANG_CONFIG = 8, // .cfg files
+ LANG_JAVASCRIPT = 9,
+ LANG_JAVA = 10,
+ LANG_GO = 11,
+ LANG_TED_CFG = 12, // like LANG_CONFIG, but with multiline strings.
+ LANG_TYPESCRIPT = 13,
+ LANG_JSON = 14,
+ LANG_XML = 15,
+ LANG_GLSL = 16,
+ LANG_COUNT
+} Language;
+
+typedef struct {
+ Language lang;
+ char const *name;
+} LanguageName;
+
+static LanguageName const language_names[] = {
+ {LANG_NONE, "None"},
+ {LANG_C, "C"},
+ {LANG_CPP, "C++"},
+ {LANG_RUST, "Rust"},
+ {LANG_PYTHON, "Python"},
+ {LANG_TEX, "Tex"},
+ {LANG_MARKDOWN, "Markdown"},
+ {LANG_HTML, "HTML"},
+ {LANG_CONFIG, "Config"},
+ {LANG_JAVASCRIPT, "JavaScript"},
+ {LANG_JAVA, "Java"},
+ {LANG_GO, "Go"},
+ {LANG_TED_CFG, "TedCfg"},
+ {LANG_TYPESCRIPT, "TypeScript"},
+ {LANG_JSON, "JSON"},
+ {LANG_XML, "XML"},
+ {LANG_GLSL, "GLSL"},
+};
+
+static_assert_if_possible(arr_count(language_names) == LANG_COUNT)
+
+
#endif
diff --git a/hover.c b/hover.c
index 8b4794a..ebb3d8e 100644
--- a/hover.c
+++ b/hover.c
@@ -2,29 +2,37 @@
void hover_close(Ted *ted) {
Hover *hover = &ted->hover;
- hover->time = 0.0;
hover->open = false;
free(hover->text);
hover->text = NULL;
}
-void hover_send_request(Ted *ted) {
+static bool get_hover_position(Ted *ted, LSPDocumentPosition *pos, LSP **lsp) {
// find the buffer where the mouse is
for (int i = 0; i < TED_MAX_BUFFERS; ++i) {
TextBuffer *buffer = &ted->buffers[i];
if (!buffer->filename) continue;
- LSP *lsp = buffer_lsp(buffer);
- if (!lsp) continue;
+ LSP *l = buffer_lsp(buffer);
+ if (!l) continue;
BufferPos mouse_pos = {0};
if (buffer_pixels_to_pos(buffer, ted->mouse_pos, &mouse_pos)) {
- // send the request
- LSPRequest request = {.type = LSP_REQUEST_HOVER};
- LSPRequestHover *h = &request.data.hover;
- h->position = buffer_pos_to_lsp_document_position(buffer, mouse_pos);
- lsp_send_request(lsp, &request);
- break;
+ *pos = buffer_pos_to_lsp_document_position(buffer, mouse_pos);
+ *lsp = l;
+ return true;
}
}
+ return false;
+}
+void hover_send_request(Ted *ted) {
+ Hover *hover = &ted->hover;
+ LSPRequest request = {.type = LSP_REQUEST_HOVER};
+ LSPRequestHover *h = &request.data.hover;
+ LSP *lsp = NULL;
+ if (get_hover_position(ted, &h->position, &lsp)) {
+ hover->requested_position = h->position;
+ hover->requested_lsp = lsp->id;
+ lsp_send_request(lsp, &request);
+ }
}
void hover_process_lsp_response(Ted *ted, LSPResponse *response) {
@@ -50,30 +58,65 @@ void hover_process_lsp_response(Ted *ted, LSPResponse *response) {
void hover_frame(Ted *ted, double dt) {
Hover *hover = &ted->hover;
- if (ted->autocomplete.open) {
+ bool shift_down = SDL_GetKeyboardState(NULL)[SDL_SCANCODE_LSHIFT]
+ || SDL_GetKeyboardState(NULL)[SDL_SCANCODE_RSHIFT];
+
+ if (!shift_down) {
hover_close(ted);
}
+ (void)dt;
if (!hover->open) {
- hover->time += dt;
- if (hover->time > 1.0) {
+ if (shift_down) {
hover_send_request(ted);
hover->open = true;
}
return;
}
+ {
+ LSPDocumentPosition pos={0};
+ LSP *lsp=0;
+ if (get_hover_position(ted, &pos, &lsp)) {
+ if (lsp->id != hover->requested_lsp
+ || !lsp_document_position_eq(pos, hover->requested_position)) {
+ // refresh hover
+ hover_send_request(ted);
+ }
+ } else {
+ hover_close(ted);
+ return;
+ }
+ }
+
if (!hover->text)
return;
+ const Settings *settings = ted_active_settings(ted);
+ const u32 *colors = settings->colors;
const char *text = hover->text;
- u16 lines = 0; // number of lines of text
- for (int i = 0; text[i]; ++i)
- if (text[i] == '\n')
- ++lines;
-
- //Font *font = ted->font;
- //float width = 200, height = lines * font->char_height;
-
-
+ Font *font = ted->font;
+ float x = ted->mouse_pos.x, y = ted->mouse_pos.y;
+ TextRenderState state = text_render_state_default;
+ state.x = state.min_x = x;
+ state.y = state.min_y = y;
+ state.render = false;
+ state.wrap = true;
+ state.max_x = x + 400;
+ state.max_y = ted->window_height;
+ text_utf8_with_state(font, &state, text);
+ float width = (float)(state.x_largest - x);
+ float height = (float)(state.y_largest - y) + font->char_height;
+ if (height > 300) {
+ height = 300;
+ }
+ state.x = x;
+ state.y = y;
+ state.render = true;
+ state.max_y = y + height;
+ gl_geometry_rect(rect_xywh(x, y, width, height), colors[COLOR_AUTOCOMPLETE_BG]);
+ rgba_u32_to_floats(colors[COLOR_TEXT], state.color);
+ text_utf8_with_state(font, &state, text);
+ gl_geometry_draw();
+ text_render(font);
}
diff --git a/lsp-parse.c b/lsp-parse.c
index 7141485..c89a8c4 100644
--- a/lsp-parse.c
+++ b/lsp-parse.c
@@ -408,7 +408,14 @@ static bool parse_signature_help(LSP *lsp, const JSON *json, LSPResponse *respon
static bool parse_hover(LSP *lsp, const JSON *json, LSPResponse *response) {
LSPResponseHover *hover = &response->data.hover;
- JSONObject result = json_force_object(json_get(json, "result"));
+ JSONValue result_value = json_get(json, "result");
+ if (result_value.type == JSON_NULL)
+ return true; // no results
+ if (result_value.type != JSON_OBJECT) {
+ lsp_set_error(lsp, "Bad result type for textDocument/hover response.");
+ return false;
+ }
+ JSONObject result = json_force_object(result_value);
JSONValue range = json_object_get(json, result, "range");
parse_range(lsp, json, range, &hover->range);
@@ -446,7 +453,7 @@ static bool parse_hover(LSP *lsp, const JSON *json, LSPResponse *response) {
if (value.type == JSON_STRING) {
contents_string = value.val.string;
} else {
- lsp_set_error(lsp, "Bad contents field on textDocument/hover response.");
+ lsp_set_error(lsp, "Bad contents object in textDocument/hover response.");
return false;
}
}
diff --git a/lsp.c b/lsp.c
index bc14c60..678c638 100644
--- a/lsp.c
+++ b/lsp.c
@@ -477,6 +477,7 @@ void lsp_document_changed(LSP *lsp, const char *document, LSPDocumentChangeEvent
lsp_send_request(lsp, &request);
}
+#if 0
SymbolKind lsp_symbol_kind_to_ted(LSPSymbolKind kind) {
switch (kind) {
case LSP_SYMBOL_OTHER:
@@ -521,48 +522,14 @@ SymbolKind lsp_symbol_kind_to_ted(LSPSymbolKind kind) {
return SYMBOL_OTHER;
}
+#endif
-SymbolKind lsp_completion_kind_to_ted(LSPCompletionKind kind) {
- switch (kind) {
- case LSP_COMPLETION_TEXT:
- case LSP_COMPLETION_MODULE:
- case LSP_COMPLETION_UNIT:
- case LSP_COMPLETION_COLOR:
- case LSP_COMPLETION_FILE:
- case LSP_COMPLETION_REFERENCE:
- case LSP_COMPLETION_FOLDER:
- case LSP_COMPLETION_OPERATOR:
- return SYMBOL_OTHER;
-
- case LSP_COMPLETION_METHOD:
- case LSP_COMPLETION_FUNCTION:
- case LSP_COMPLETION_CONSTRUCTOR:
- return SYMBOL_FUNCTION;
-
- case LSP_COMPLETION_FIELD:
- case LSP_COMPLETION_PROPERTY:
- return SYMBOL_FIELD;
-
- case LSP_COMPLETION_VARIABLE:
- return SYMBOL_VARIABLE;
-
- case LSP_COMPLETION_CLASS:
- case LSP_COMPLETION_INTERFACE:
- case LSP_COMPLETION_ENUM:
- case LSP_COMPLETION_STRUCT:
- case LSP_COMPLETION_EVENT:
- case LSP_COMPLETION_TYPEPARAMETER:
- return SYMBOL_TYPE;
-
- case LSP_COMPLETION_VALUE:
- case LSP_COMPLETION_ENUMMEMBER:
- case LSP_COMPLETION_CONSTANT:
- return SYMBOL_CONSTANT;
-
- case LSP_COMPLETION_KEYWORD:
- case LSP_COMPLETION_SNIPPET:
- return SYMBOL_KEYWORD;
- }
+bool lsp_position_eq(LSPPosition a, LSPPosition b) {
+ return a.line == b.line && a.character == b.character;
+}
+
+bool lsp_document_position_eq(LSPDocumentPosition a, LSPDocumentPosition b) {
+ return a.document == b.document && lsp_position_eq(a.pos, b.pos);
}
#undef write_bool
diff --git a/lsp.h b/lsp.h
index 0b25091..389f38e 100644
--- a/lsp.h
+++ b/lsp.h
@@ -1,6 +1,17 @@
typedef u32 LSPDocumentID;
typedef u32 LSPID;
+typedef struct {
+ u32 line;
+ // NOTE: this is the UTF-16 character index!
+ u32 character;
+} LSPPosition;
+
+typedef struct {
+ LSPDocumentID document;
+ LSPPosition pos;
+} LSPDocumentPosition;
+
typedef enum {
LSP_REQUEST,
LSP_RESPONSE
@@ -11,12 +22,6 @@ typedef struct {
} LSPString;
typedef struct {
- u32 line;
- // NOTE: this is the UTF-16 character index!
- u32 character;
-} LSPPosition;
-
-typedef struct {
LSPPosition start;
LSPPosition end;
} LSPRange;
@@ -83,11 +88,6 @@ typedef struct {
char *message;
} LSPRequestMessage;
-typedef struct {
- LSPDocumentID document;
- LSPPosition pos;
-} LSPDocumentPosition;
-
// these triggers are used for completion context and signature help context.
#define LSP_TRIGGER_NONE 0 // not actually defined in LSP spec
@@ -375,8 +375,6 @@ typedef struct LSP {
char error[256];
} LSP;
-// @TODO: function declarations
-
// returns true if there's an error.
// returns false and sets error to "" if there's no error.
// if clear = true, the error will be cleared.
@@ -401,7 +399,7 @@ LSP *lsp_create(const char *root_dir, Language language, const char *analyzer_co
// with root directory `new_root_dir`.
bool lsp_try_add_root_dir(LSP *lsp, const char *new_root_dir);
bool lsp_next_message(LSP *lsp, LSPMessage *message);
+bool lsp_position_eq(LSPPosition a, LSPPosition b);
+bool lsp_document_position_eq(LSPDocumentPosition a, LSPDocumentPosition b);
void lsp_document_changed(LSP *lsp, const char *document, LSPDocumentChangeEvent change);
void lsp_free(LSP *lsp);
-SymbolKind lsp_symbol_kind_to_ted(LSPSymbolKind kind);
-SymbolKind lsp_completion_kind_to_ted(LSPCompletionKind kind);
diff --git a/main.c b/main.c
index ba759f8..39e659b 100644
--- a/main.c
+++ b/main.c
@@ -124,10 +124,10 @@ static void die(char const *fmt, ...) {
#include "command.h"
#include "colors.h"
#include "time.c"
+#include "lsp.h"
#include "ted.h"
#include "gl.c"
#include "text.c"
-#include "lsp.h"
#include "string32.c"
#include "colors.c"
@@ -660,8 +660,6 @@ int main(int argc, char **argv) {
switch (event.type) {
case SDL_QUIT:
- hover_close(ted);
-
command_execute(ted, CMD_QUIT, 1);
break;
case SDL_MOUSEWHEEL: {
@@ -676,8 +674,6 @@ int main(int argc, char **argv) {
}
} break;
case SDL_MOUSEBUTTONDOWN: {
- hover_close(ted);
-
Uint32 button = event.button.button;
u8 times = event.button.clicks; // number of clicks
float x = (float)event.button.x, y = (float)event.button.y;
@@ -744,8 +740,6 @@ int main(int argc, char **argv) {
}
} break;
case SDL_MOUSEMOTION: {
- hover_close(ted);
-
float x = (float)event.motion.x, y = (float)event.motion.y;
if (ted->drag_buffer != ted->active_buffer)
ted->drag_buffer = NULL;
@@ -758,15 +752,11 @@ int main(int argc, char **argv) {
}
} break;
case SDL_KEYDOWN: {
- hover_close(ted);
-
SDL_Scancode scancode = event.key.keysym.scancode;
SDL_Keymod modifier = event.key.keysym.mod;
ted_press_key(ted, scancode, modifier);
} break;
case SDL_TEXTINPUT: {
- hover_close(ted);
-
char *text = event.text.text;
if (buffer
// unfortunately, some key combinations like ctrl+minus still register as a "-" text input event
diff --git a/ted.h b/ted.h
index f1748b0..004cc2a 100644
--- a/ted.h
+++ b/ted.h
@@ -63,56 +63,6 @@ enum {
typedef u8 SyntaxState;
-// If you are adding new languages, DO NOT change the constant values
-// of the previous languages. It will mess up config files which use :set-language!
-typedef enum {
- LANG_NONE = 0,
- LANG_C = 1,
- LANG_CPP = 2,
- LANG_RUST = 3,
- LANG_PYTHON = 4,
- LANG_TEX = 5,
- LANG_MARKDOWN = 6,
- LANG_HTML = 7,
- LANG_CONFIG = 8, // .cfg files
- LANG_JAVASCRIPT = 9,
- LANG_JAVA = 10,
- LANG_GO = 11,
- LANG_TED_CFG = 12, // like LANG_CONFIG, but with multiline strings.
- LANG_TYPESCRIPT = 13,
- LANG_JSON = 14,
- LANG_XML = 15,
- LANG_GLSL = 16,
- LANG_COUNT
-} Language;
-
-typedef struct {
- Language lang;
- char const *name;
-} LanguageName;
-
-static LanguageName const language_names[] = {
- {LANG_NONE, "None"},
- {LANG_C, "C"},
- {LANG_CPP, "C++"},
- {LANG_RUST, "Rust"},
- {LANG_PYTHON, "Python"},
- {LANG_TEX, "Tex"},
- {LANG_MARKDOWN, "Markdown"},
- {LANG_HTML, "HTML"},
- {LANG_CONFIG, "Config"},
- {LANG_JAVASCRIPT, "JavaScript"},
- {LANG_JAVA, "Java"},
- {LANG_GO, "Go"},
- {LANG_TED_CFG, "TedCfg"},
- {LANG_TYPESCRIPT, "TypeScript"},
- {LANG_JSON, "JSON"},
- {LANG_XML, "XML"},
- {LANG_GLSL, "GLSL"},
-};
-
-static_assert_if_possible(arr_count(language_names) == LANG_COUNT)
-
ENUM_U8 {
SYNTAX_NORMAL,
SYNTAX_KEYWORD,
@@ -177,6 +127,8 @@ typedef struct {
u32 buffer;
} GlRcSAB;
+
+
typedef struct {
// NOTE: to add more options to ted, add fields here,
// and change the options_<type> global constant in config.c
@@ -450,10 +402,12 @@ typedef struct {
typedef struct {
// is some hover info being displayed?
bool open;
- // amount of time user has been hovering cursor for
- double time;
// text to display
char *text;
+ // where the hover data is coming from.
+ // we use this to check if we need to refresh it.
+ LSPDocumentPosition requested_position;
+ LSPID requested_lsp;
} Hover;
diff --git a/text.c b/text.c
index 6df77ff..d439b32 100644
--- a/text.c
+++ b/text.c
@@ -59,6 +59,7 @@ TextRenderState const text_render_state_default = {
.min_x = -FLT_MAX, .max_x = +FLT_MAX,
.min_y = -FLT_MAX, .max_y = +FLT_MAX,
.color = {1, 0, 1, 1},
+ .x_largest = -FLT_MAX, .y_largest = -FLT_MAX
};
static char text_err[200];
@@ -295,7 +296,7 @@ top:
if (state->wrap && c == '\n') {
state->x = state->min_x;
state->y += char_height;
- return;
+ goto ret;
}
{
@@ -334,7 +335,7 @@ top:
}
if (x0 > max_x || y0 > max_y || x1 < min_x || y1 < min_y)
- return;
+ goto ret;
if (x0 < min_x) {
// left side of character is clipped
s0 = (min_x-x0) / (x1-x0) * (s1-s0) + s0;
@@ -367,6 +368,11 @@ top:
arr_add(font->triangles[page], triangle2);
}
}
+ ret:
+ if (state->x > state->x_largest)
+ state->x_largest = state->x;
+ if (state->y > state->y_largest)
+ state->y_largest = state->y;
}
void text_utf8_with_state(Font *font, TextRenderState *state, char const *str) {
@@ -387,19 +393,21 @@ void text_utf8_with_state(Font *font, TextRenderState *state, char const *str) {
}
}
-static void text_render_utf8_internal(Font *font, char const *text, double *x, double *y, u32 color, bool render) {
+static v2 text_render_utf8_internal(Font *font, char const *text, double x, double y, u32 color, bool render) {
TextRenderState render_state = text_render_state_default;
render_state.render = render;
- render_state.x = *x;
- render_state.y = *y;
+ render_state.x = x;
+ render_state.y = y;
rgba_u32_to_floats(color, render_state.color);
text_utf8_with_state(font, &render_state, text);
- *x = render_state.x;
- *y = render_state.y;
+ return V2(
+ (float)(render_state.x_largest - x),
+ (float)(render_state.y_largest - y)
+ );
}
void text_utf8(Font *font, char const *text, double x, double y, u32 color) {
- text_render_utf8_internal(font, text, &x, &y, color, true);
+ text_render_utf8_internal(font, text, x, y, color, true);
}
void text_utf8_anchored(Font *font, char const *text, double x, double y, u32 color, Anchor anchor) {
@@ -422,9 +430,9 @@ void text_utf8_anchored(Font *font, char const *text, double x, double y, u32 co
void text_get_size(Font *font, char const *text, float *width, float *height) {
double x = 0, y = 0;
- text_render_utf8_internal(font, text, &x, &y, 0, false);
- if (width) *width = (float)x;
- if (height) *height = (float)y + font->char_height;
+ v2 size = text_render_utf8_internal(font, text, x, y, 0, false);
+ if (width) *width = size.x;
+ if (height) *height = size.y + font->char_height;
}
v2 text_get_size_v2(Font *font, char const *text) {
diff --git a/text.h b/text.h
index 882b4ae..dbf223d 100644
--- a/text.h
+++ b/text.h
@@ -23,6 +23,10 @@ typedef struct {
float min_x, max_x, min_y, max_y;
// [0] = r, [1] = g, [2] = b, [3] = a.
float color[4];
+
+ // largest x & y achieved (for computing size)
+ double x_largest;
+ double y_largest;
} TextRenderState;
typedef enum {