From 71a1e41f937e828360a0d84978bc777da2d726f1 Mon Sep 17 00:00:00 2001 From: Will Anderson Date: Sun, 3 May 2026 16:16:11 -0500 Subject: [PATCH] =?UTF-8?q?lsp:=20type-aware=20field=20completions=20?= =?UTF-8?q?=E2=80=94=20scan=20type/let/param=20decls,=20complete=20on=20do?= =?UTF-8?q?t-access?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a document is opened or changed, scan for `type Name { field: Type }` blocks and `let var: Type` / `fn foo(param: Type)` annotations. On completion requests, if the text before the cursor ends with `identifier.`, look up the variable's type and return its fields as Field (kind=5) completion items instead of the full list. --- tools/lsp/dist/el-lsp | Bin 0 -> 360792 bytes tools/lsp/dist/el-lsp.c | 1252 +++++++++++++++++++++++++++++++++++++++ tools/lsp/el-lsp.el | 310 +++++++++- 3 files changed, 1560 insertions(+), 2 deletions(-) create mode 100755 tools/lsp/dist/el-lsp create mode 100644 tools/lsp/dist/el-lsp.c diff --git a/tools/lsp/dist/el-lsp b/tools/lsp/dist/el-lsp new file mode 100755 index 0000000000000000000000000000000000000000..6a74145b0e5f5f99e401def4e4bf23ce745280a2 GIT binary patch literal 360792 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 +#include +#include "el_runtime.h" + +el_val_t lsp_read_message(void); +el_val_t lsp_write_message(el_val_t body); +el_val_t lsp_json_escape(el_val_t s); +el_val_t lsp_response(el_val_t id, el_val_t result_json); +el_val_t lsp_error_response(el_val_t id, el_val_t code, el_val_t message); +el_val_t lsp_notification(el_val_t method, el_val_t params_json); +el_val_t lsp_doc_key(el_val_t uri); +el_val_t lsp_doc_store(el_val_t uri, el_val_t text); +el_val_t lsp_doc_get(el_val_t uri); +el_val_t lsp_doc_remove(el_val_t uri); +el_val_t lsp_builtin_catalog(void); +el_val_t lsp_builtin_find(el_val_t name, el_val_t catalog); +el_val_t lsp_types_key(el_val_t uri, el_val_t type_name); +el_val_t lsp_vartypes_key(el_val_t uri); +el_val_t lsp_scan_types(el_val_t uri, el_val_t source); +el_val_t lsp_get_type_fields(el_val_t uri, el_val_t type_name); +el_val_t lsp_varentry_name(el_val_t entry); +el_val_t lsp_varentry_type(el_val_t entry); +el_val_t lsp_scan_vartypes(el_val_t uri, el_val_t source); +el_val_t lsp_get_var_type(el_val_t uri, el_val_t var_name); +el_val_t lsp_scan_document(el_val_t uri, el_val_t source); +el_val_t lsp_dot_ident_before(el_val_t text); +el_val_t lsp_line_prefix(el_val_t source, el_val_t line_no, el_val_t char_no); +el_val_t lsp_field_completions(el_val_t uri, el_val_t type_name); +el_val_t lsp_extract_fns(el_val_t source); +el_val_t lsp_find_def(el_val_t source, el_val_t fn_name); +el_val_t lsp_word_at(el_val_t source, el_val_t line_no, el_val_t char_no); +el_val_t lsp_completion_item(el_val_t label, el_val_t kind, el_val_t detail); +el_val_t lsp_build_completions(el_val_t uri, el_val_t catalog, el_val_t line_no, el_val_t char_no); +el_val_t lsp_keyword_hover(el_val_t word); +el_val_t lsp_build_hover(el_val_t uri, el_val_t line_no, el_val_t char_no, el_val_t catalog); +el_val_t lsp_build_definition(el_val_t uri, el_val_t line_no, el_val_t char_no); +el_val_t lsp_make_diag(el_val_t line_no, el_val_t col_start, el_val_t col_end, el_val_t message, el_val_t severity); +el_val_t lsp_compute_diagnostics(el_val_t source); +el_val_t lsp_publish_diagnostics(el_val_t uri); +el_val_t lsp_handle_initialize(el_val_t id); +el_val_t lsp_handle_completion(el_val_t id, el_val_t params, el_val_t catalog); +el_val_t lsp_handle_hover(el_val_t id, el_val_t params, el_val_t catalog); +el_val_t lsp_handle_definition(el_val_t id, el_val_t params); +el_val_t lsp_handle_did_open(el_val_t params, el_val_t catalog); +el_val_t lsp_handle_did_change(el_val_t params); +el_val_t lsp_handle_did_close(el_val_t params); +el_val_t lsp_handle_did_save(el_val_t params); +el_val_t lsp_handle_shutdown(el_val_t id); +el_val_t lsp_dispatch(el_val_t msg, el_val_t catalog); + +el_val_t lsp_read_message(void) { + el_val_t header_buf = EL_STR(""); + el_val_t found_end = 0; + el_val_t max_header = 8192; + el_val_t hi = 0; + while (!found_end) { + if (hi >= max_header) { + return EL_STR(""); + } + el_val_t ch = __read_n(1); + if (str_eq(ch, EL_STR(""))) { + return EL_STR(""); + } + header_buf = el_str_concat(header_buf, ch); + el_val_t hlen = str_len(header_buf); + if (hlen >= 4) { + el_val_t tail = str_slice(header_buf, (hlen - 4), hlen); + if (str_eq(tail, EL_STR("\r\n\r\n"))) { + found_end = 1; + } + } + hi = (hi + 1); + } + el_val_t cl_key = EL_STR("Content-Length: "); + el_val_t cl_pos = str_index_of(header_buf, cl_key); + if (cl_pos < 0) { + return EL_STR(""); + } + el_val_t after = str_slice(header_buf, (cl_pos + str_len(cl_key)), str_len(header_buf)); + el_val_t cr_pos = str_index_of(after, EL_STR("\r")); + el_val_t num_str = EL_STR(""); + if (cr_pos >= 0) { + num_str = str_slice(after, 0, cr_pos); + } else { + el_val_t nl_pos = str_index_of(after, EL_STR("\n")); + if (nl_pos >= 0) { + num_str = str_slice(after, 0, nl_pos); + } + } + el_val_t body_len = str_to_int(str_trim(num_str)); + if (body_len <= 0) { + return EL_STR(""); + } + return __read_n(body_len); + return 0; +} + +el_val_t lsp_write_message(el_val_t body) { + el_val_t len = str_len(body); + __print_raw(el_str_concat(el_str_concat(el_str_concat(EL_STR("Content-Length: "), int_to_str(len)), EL_STR("\r\n\r\n")), body)); + return 0; +} + +el_val_t lsp_json_escape(el_val_t s) { + s = str_replace(s, EL_STR("\\"), EL_STR("\\\\")); + s = str_replace(s, EL_STR("\""), EL_STR("\\\"")); + s = str_replace(s, EL_STR("\n"), EL_STR("\\n")); + s = str_replace(s, EL_STR("\r"), EL_STR("\\r")); + s = str_replace(s, EL_STR("\t"), EL_STR("\\t")); + return s; + return 0; +} + +el_val_t lsp_response(el_val_t id, el_val_t result_json) { + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"jsonrpc\":\"2.0\",\"id\":"), id), EL_STR(",\"result\":")), result_json), EL_STR("}")); + return 0; +} + +el_val_t lsp_error_response(el_val_t id, el_val_t code, el_val_t message) { + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"jsonrpc\":\"2.0\",\"id\":"), id), EL_STR(",\"error\":{\"code\":")), int_to_str(code)), EL_STR(",\"message\":\"")), lsp_json_escape(message)), EL_STR("\"}}")); + return 0; +} + +el_val_t lsp_notification(el_val_t method, el_val_t params_json) { + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"jsonrpc\":\"2.0\",\"method\":\""), method), EL_STR("\",\"params\":")), params_json), EL_STR("}")); + return 0; +} + +el_val_t lsp_doc_key(el_val_t uri) { + return el_str_concat(EL_STR("doc:"), uri); + return 0; +} + +el_val_t lsp_doc_store(el_val_t uri, el_val_t text) { + state_set(lsp_doc_key(uri), text); + return 0; +} + +el_val_t lsp_doc_get(el_val_t uri) { + return state_get(lsp_doc_key(uri)); + return 0; +} + +el_val_t lsp_doc_remove(el_val_t uri) { + state_del(lsp_doc_key(uri)); + return 0; +} + +el_val_t lsp_builtin_catalog(void) { + el_val_t c = native_list_empty(); + c = native_list_append(c, EL_STR("println|println(s: String) -> Void|Print s followed by a newline to stdout.")); + c = native_list_append(c, EL_STR("print|print(s: String) -> Void|Print s to stdout without a newline.")); + c = native_list_append(c, EL_STR("readline|readline() -> String|Read one line from stdin (newline stripped).")); + c = native_list_append(c, EL_STR("str_eq|str_eq(a: String, b: String) -> Bool|Return true if a equals b.")); + c = native_list_append(c, EL_STR("str_len|str_len(s: String) -> Int|Return the byte length of s.")); + c = native_list_append(c, EL_STR("str_concat|str_concat(a: String, b: String) -> String|Concatenate a and b.")); + c = native_list_append(c, EL_STR("str_slice|str_slice(s: String, start: Int, end: Int) -> String|Substring [start, end).")); + c = native_list_append(c, EL_STR("str_contains|str_contains(s: String, sub: String) -> Bool|True if s contains sub.")); + c = native_list_append(c, EL_STR("str_starts_with|str_starts_with(s: String, prefix: String) -> Bool|True if s starts with prefix.")); + c = native_list_append(c, EL_STR("str_ends_with|str_ends_with(s: String, suffix: String) -> Bool|True if s ends with suffix.")); + c = native_list_append(c, EL_STR("str_replace|str_replace(s: String, from: String, to: String) -> String|Replace all occurrences of from with to.")); + c = native_list_append(c, EL_STR("str_to_upper|str_to_upper(s: String) -> String|Convert to uppercase.")); + c = native_list_append(c, EL_STR("str_to_lower|str_to_lower(s: String) -> String|Convert to lowercase.")); + c = native_list_append(c, EL_STR("str_trim|str_trim(s: String) -> String|Strip leading and trailing whitespace.")); + c = native_list_append(c, EL_STR("str_lstrip|str_lstrip(s: String) -> String|Strip leading whitespace.")); + c = native_list_append(c, EL_STR("str_rstrip|str_rstrip(s: String) -> String|Strip trailing whitespace.")); + c = native_list_append(c, EL_STR("str_index_of|str_index_of(s: String, sub: String) -> Int|First byte offset of sub, or -1.")); + c = native_list_append(c, EL_STR("str_last_index_of|str_last_index_of(s: String, sub: String) -> Int|Last byte offset of sub, or -1.")); + c = native_list_append(c, EL_STR("str_split|str_split(s: String, sep: String) -> [String]|Split on sep.")); + c = native_list_append(c, EL_STR("str_split_lines|str_split_lines(s: String) -> [String]|Split into lines.")); + c = native_list_append(c, EL_STR("str_split_n|str_split_n(s: String, sep: String, n: Int) -> [String]|Split at most n times.")); + c = native_list_append(c, EL_STR("str_join|str_join(parts: [String], sep: String) -> String|Join list with sep.")); + c = native_list_append(c, EL_STR("str_char_at|str_char_at(s: String, i: Int) -> String|Single character at byte index i.")); + c = native_list_append(c, EL_STR("str_char_code|str_char_code(s: String, i: Int) -> Int|Byte value at index i.")); + c = native_list_append(c, EL_STR("str_pad_left|str_pad_left(s: String, width: Int, pad: String) -> String|Pad on the left to width.")); + c = native_list_append(c, EL_STR("str_pad_right|str_pad_right(s: String, width: Int, pad: String) -> String|Pad on the right to width.")); + c = native_list_append(c, EL_STR("str_repeat|str_repeat(s: String, n: Int) -> String|Repeat s n times.")); + c = native_list_append(c, EL_STR("str_reverse|str_reverse(s: String) -> String|Reverse by codepoint.")); + c = native_list_append(c, EL_STR("str_strip_prefix|str_strip_prefix(s: String, prefix: String) -> String|Remove prefix if present.")); + c = native_list_append(c, EL_STR("str_strip_suffix|str_strip_suffix(s: String, suffix: String) -> String|Remove suffix if present.")); + c = native_list_append(c, EL_STR("str_strip_chars|str_strip_chars(s: String, chars: String) -> String|Strip chars from both ends.")); + c = native_list_append(c, EL_STR("str_count|str_count(s: String, sub: String) -> Int|Count non-overlapping occurrences.")); + c = native_list_append(c, EL_STR("str_count_lines|str_count_lines(s: String) -> Int|Number of lines.")); + c = native_list_append(c, EL_STR("str_find_chars|str_find_chars(s: String, any_of: String) -> Int|First index of any char in any_of.")); + c = native_list_append(c, EL_STR("str_index_of_all|str_index_of_all(s: String, sub: String) -> [Int]|All byte offsets of sub.")); + c = native_list_append(c, EL_STR("str_upper|str_upper(s: String) -> String|Convert to uppercase (alias).")); + c = native_list_append(c, EL_STR("str_lower|str_lower(s: String) -> String|Convert to lowercase (alias).")); + c = native_list_append(c, EL_STR("is_letter|is_letter(s: String) -> Bool|All ASCII letters.")); + c = native_list_append(c, EL_STR("is_digit|is_digit(s: String) -> Bool|All ASCII digits.")); + c = native_list_append(c, EL_STR("is_alphanumeric|is_alphanumeric(s: String) -> Bool|All ASCII alphanumeric.")); + c = native_list_append(c, EL_STR("is_whitespace|is_whitespace(s: String) -> Bool|All whitespace.")); + c = native_list_append(c, EL_STR("is_uppercase|is_uppercase(s: String) -> Bool|All uppercase ASCII.")); + c = native_list_append(c, EL_STR("is_lowercase|is_lowercase(s: String) -> Bool|All lowercase ASCII.")); + c = native_list_append(c, EL_STR("int_to_str|int_to_str(n: Int) -> String|Integer to decimal string.")); + c = native_list_append(c, EL_STR("str_to_int|str_to_int(s: String) -> Int|Parse decimal string to integer.")); + c = native_list_append(c, EL_STR("float_to_str|float_to_str(f: Float) -> String|Float to string.")); + c = native_list_append(c, EL_STR("str_to_float|str_to_float(s: String) -> Float|Parse string to float.")); + c = native_list_append(c, EL_STR("int_to_float|int_to_float(n: Int) -> Float|Integer to float.")); + c = native_list_append(c, EL_STR("float_to_int|float_to_int(f: Float) -> Int|Truncate float to integer.")); + c = native_list_append(c, EL_STR("format_float|format_float(f: Float, decimals: Int) -> String|Fixed decimal places.")); + c = native_list_append(c, EL_STR("decimal_round|decimal_round(f: Float, decimals: Int) -> Float|Round to N decimal places.")); + c = native_list_append(c, EL_STR("bool_to_str|bool_to_str(b: Bool) -> String|Bool to \"true\" or \"false\".")); + c = native_list_append(c, EL_STR("el_abs|el_abs(n: Int) -> Int|Absolute value.")); + c = native_list_append(c, EL_STR("el_max|el_max(a: Int, b: Int) -> Int|Maximum of two integers.")); + c = native_list_append(c, EL_STR("el_min|el_min(a: Int, b: Int) -> Int|Minimum of two integers.")); + c = native_list_append(c, EL_STR("math_sqrt|math_sqrt(f: Float) -> Float|Square root.")); + c = native_list_append(c, EL_STR("math_log|math_log(f: Float) -> Float|Base-10 logarithm.")); + c = native_list_append(c, EL_STR("math_ln|math_ln(f: Float) -> Float|Natural logarithm.")); + c = native_list_append(c, EL_STR("math_sin|math_sin(f: Float) -> Float|Sine (radians).")); + c = native_list_append(c, EL_STR("math_cos|math_cos(f: Float) -> Float|Cosine (radians).")); + c = native_list_append(c, EL_STR("math_pi|math_pi() -> Float|Value of pi.")); + c = native_list_append(c, EL_STR("el_list_empty|el_list_empty() -> [Any]|Create an empty list.")); + c = native_list_append(c, EL_STR("el_list_append|el_list_append(list: [Any], elem: Any) -> [Any]|Append and return updated list.")); + c = native_list_append(c, EL_STR("el_list_len|el_list_len(list: [Any]) -> Int|Number of elements.")); + c = native_list_append(c, EL_STR("el_list_get|el_list_get(list: [Any], index: Int) -> Any|Element at index.")); + c = native_list_append(c, EL_STR("el_list_clone|el_list_clone(list: [Any]) -> [Any]|Shallow copy.")); + c = native_list_append(c, EL_STR("list_push|list_push(list: [Any], elem: Any) -> [Any]|Append elem (alias).")); + c = native_list_append(c, EL_STR("list_push_front|list_push_front(list: [Any], elem: Any) -> [Any]|Prepend elem.")); + c = native_list_append(c, EL_STR("list_join|list_join(list: [Any], sep: String) -> String|Join list with sep.")); + c = native_list_append(c, EL_STR("list_range|list_range(start: Int, end: Int) -> [Int]|Integers from start to end-1.")); + c = native_list_append(c, EL_STR("el_map_get|el_map_get(map: Map, key: String) -> Any|Get by key.")); + c = native_list_append(c, EL_STR("el_map_set|el_map_set(map: Map, key: String, value: Any) -> Map|Set key.")); + c = native_list_append(c, EL_STR("el_get_field|el_get_field(map: Map, key: String) -> Any|Get field.")); + c = native_list_append(c, EL_STR("state_set|state_set(key: String, value: String) -> Void|Store in process state.")); + c = native_list_append(c, EL_STR("state_get|state_get(key: String) -> String|Retrieve from process state, empty if absent.")); + c = native_list_append(c, EL_STR("state_del|state_del(key: String) -> Void|Delete from process state.")); + c = native_list_append(c, EL_STR("state_keys|state_keys() -> [String]|All keys in process state.")); + c = native_list_append(c, EL_STR("json_get|json_get(json: String, key: String) -> String|Get string field from JSON object.")); + c = native_list_append(c, EL_STR("json_get_string|json_get_string(json: String, key: String) -> String|Get string field.")); + c = native_list_append(c, EL_STR("json_get_int|json_get_int(json: String, key: String) -> Int|Get integer field.")); + c = native_list_append(c, EL_STR("json_get_float|json_get_float(json: String, key: String) -> Float|Get float field.")); + c = native_list_append(c, EL_STR("json_get_bool|json_get_bool(json: String, key: String) -> Bool|Get boolean field.")); + c = native_list_append(c, EL_STR("json_get_raw|json_get_raw(json: String, key: String) -> String|Get raw JSON fragment.")); + c = native_list_append(c, EL_STR("json_set|json_set(json: String, key: String, value: String) -> String|Set key in JSON object.")); + c = native_list_append(c, EL_STR("json_parse|json_parse(s: String) -> String|Parse and validate JSON.")); + c = native_list_append(c, EL_STR("json_stringify|json_stringify(v: Any) -> String|Serialize to JSON.")); + c = native_list_append(c, EL_STR("json_array_len|json_array_len(json: String) -> Int|JSON array length.")); + c = native_list_append(c, EL_STR("json_array_get|json_array_get(json: String, index: Int) -> String|JSON array element.")); + c = native_list_append(c, EL_STR("json_array_get_string|json_array_get_string(json: String, index: Int) -> String|String element at index.")); + c = native_list_append(c, EL_STR("fs_read|fs_read(path: String) -> String|Read file contents.")); + c = native_list_append(c, EL_STR("fs_write|fs_write(path: String, content: String) -> Bool|Write file.")); + c = native_list_append(c, EL_STR("fs_list|fs_list(path: String) -> [String]|List directory entries.")); + c = native_list_append(c, EL_STR("fs_exists|fs_exists(path: String) -> Bool|True if path exists.")); + c = native_list_append(c, EL_STR("fs_mkdir|fs_mkdir(path: String) -> Bool|Create directory (mkdir -p).")); + c = native_list_append(c, EL_STR("http_get|http_get(url: String) -> String|HTTP GET, return response body.")); + c = native_list_append(c, EL_STR("http_post|http_post(url: String, body: String) -> String|HTTP POST with plain body.")); + c = native_list_append(c, EL_STR("http_post_json|http_post_json(url: String, json_body: String) -> String|HTTP POST with JSON.")); + c = native_list_append(c, EL_STR("http_get_with_headers|http_get_with_headers(url: String, headers: Map) -> String|GET with headers.")); + c = native_list_append(c, EL_STR("http_post_with_headers|http_post_with_headers(url: String, body: String, headers: Map) -> String|POST with headers.")); + c = native_list_append(c, EL_STR("http_serve|http_serve(port: Int, handler: Any) -> Void|Start HTTP server.")); + c = native_list_append(c, EL_STR("http_serve_v2|http_serve_v2(port: Int, handler: Any) -> Void|Start HTTP server v2 (method,path,headers,body).")); + c = native_list_append(c, EL_STR("http_response|http_response(status: Int, headers_json: String, body: String) -> String|Build HTTP response envelope.")); + c = native_list_append(c, EL_STR("url_encode|url_encode(s: String) -> String|URL-encode (RFC 3986).")); + c = native_list_append(c, EL_STR("url_decode|url_decode(s: String) -> String|URL-decode.")); + c = native_list_append(c, EL_STR("time_now|time_now() -> String|Current local time as ISO 8601.")); + c = native_list_append(c, EL_STR("time_now_utc|time_now_utc() -> String|Current UTC time as ISO 8601.")); + c = native_list_append(c, EL_STR("sleep_secs|sleep_secs(secs: Int) -> Void|Sleep N seconds.")); + c = native_list_append(c, EL_STR("sleep_ms|sleep_ms(ms: Int) -> Void|Sleep N milliseconds.")); + c = native_list_append(c, EL_STR("time_format|time_format(ts: String, fmt: String) -> String|Format timestamp.")); + c = native_list_append(c, EL_STR("time_add|time_add(ts: String, n: Int, unit: String) -> String|Add time to timestamp.")); + c = native_list_append(c, EL_STR("time_diff|time_diff(ts1: String, ts2: String, unit: String) -> Int|Diff two timestamps.")); + c = native_list_append(c, EL_STR("now|now() -> Instant|Current time as Instant.")); + c = native_list_append(c, EL_STR("unix_seconds|unix_seconds(n: Int) -> Instant|Instant from Unix seconds.")); + c = native_list_append(c, EL_STR("unix_millis|unix_millis(n: Int) -> Instant|Instant from Unix milliseconds.")); + c = native_list_append(c, EL_STR("uuid_new|uuid_new() -> String|Random UUID v4.")); + c = native_list_append(c, EL_STR("uuid_v4|uuid_v4() -> String|Random UUID v4 (alias).")); + c = native_list_append(c, EL_STR("env|env(key: String) -> String|Read environment variable.")); + c = native_list_append(c, EL_STR("args|args() -> [String]|Command-line arguments.")); + c = native_list_append(c, EL_STR("exit_program|exit_program(code: Int) -> Void|Exit with code.")); + c = native_list_append(c, EL_STR("exec_command|exec_command(cmd: String) -> Int|Run shell command, return exit code.")); + c = native_list_append(c, EL_STR("exec_capture|exec_capture(cmd: String) -> String|Run shell command, capture stdout.")); + c = native_list_append(c, EL_STR("sha256_hex|sha256_hex(input: String) -> String|SHA-256 as lowercase hex.")); + c = native_list_append(c, EL_STR("sha256_bytes|sha256_bytes(input: String) -> String|SHA-256 as raw bytes.")); + c = native_list_append(c, EL_STR("hmac_sha256_hex|hmac_sha256_hex(key: String, message: String) -> String|HMAC-SHA-256 hex.")); + c = native_list_append(c, EL_STR("base64_encode|base64_encode(input: String) -> String|Base64 encode.")); + c = native_list_append(c, EL_STR("base64_decode|base64_decode(input: String) -> String|Base64 decode.")); + c = native_list_append(c, EL_STR("base64url_encode|base64url_encode(input: String) -> String|URL-safe base64 encode.")); + c = native_list_append(c, EL_STR("base64url_decode|base64url_decode(input: String) -> String|URL-safe base64 decode.")); + c = native_list_append(c, EL_STR("llm_call|llm_call(model: String, prompt: String) -> String|LLM with user prompt.")); + c = native_list_append(c, EL_STR("llm_call_system|llm_call_system(model: String, system: String, user: String) -> String|LLM with system + user.")); + c = native_list_append(c, EL_STR("llm_call_agentic|llm_call_agentic(model: String, system: String, user: String, tools: String) -> String|Agentic LLM.")); + c = native_list_append(c, EL_STR("llm_vision|llm_vision(model: String, system: String, prompt: String, image: String) -> String|LLM with image.")); + c = native_list_append(c, EL_STR("llm_models|llm_models() -> String|List available LLM models.")); + c = native_list_append(c, EL_STR("llm_register_tool|llm_register_tool(name: String, handler_fn: String) -> Void|Register tool.")); + c = native_list_append(c, EL_STR("engram_node|engram_node(content: String, node_type: String, salience: Float) -> String|Create engram node.")); + c = native_list_append(c, EL_STR("engram_get_node|engram_get_node(id: String) -> Map|Get node by ID.")); + c = native_list_append(c, EL_STR("engram_strengthen|engram_strengthen(node_id: String) -> Void|Increase salience.")); + c = native_list_append(c, EL_STR("engram_forget|engram_forget(node_id: String) -> Void|Remove node.")); + c = native_list_append(c, EL_STR("engram_search|engram_search(query: String, limit: Int) -> [Map]|Semantic search.")); + c = native_list_append(c, EL_STR("engram_connect|engram_connect(from: String, to: String, weight: Float, rel: String) -> Void|Connect nodes.")); + c = native_list_append(c, EL_STR("engram_activate|engram_activate(query: String, depth: Int) -> [Map]|Activate nodes.")); + c = native_list_append(c, EL_STR("engram_save|engram_save(path: String) -> Bool|Save to file.")); + c = native_list_append(c, EL_STR("engram_load|engram_load(path: String) -> Bool|Load from file.")); + c = native_list_append(c, EL_STR("engram_node_count|engram_node_count() -> Int|Total nodes.")); + c = native_list_append(c, EL_STR("engram_edge_count|engram_edge_count() -> Int|Total edges.")); + c = native_list_append(c, EL_STR("engram_neighbors|engram_neighbors(node_id: String) -> [Map]|Neighboring nodes.")); + c = native_list_append(c, EL_STR("engram_search_json|engram_search_json(query: String, limit: Int) -> String|Search as JSON.")); + c = native_list_append(c, EL_STR("engram_stats_json|engram_stats_json() -> String|Graph stats as JSON.")); + c = native_list_append(c, EL_STR("dharma_connect|dharma_connect(cgi_id: String) -> Bool|Connect to peer CGI.")); + c = native_list_append(c, EL_STR("dharma_send|dharma_send(channel: String, content: String) -> String|Send to channel.")); + c = native_list_append(c, EL_STR("dharma_activate|dharma_activate(query: String) -> String|Activate across network.")); + c = native_list_append(c, EL_STR("dharma_emit|dharma_emit(event_type: String, payload: String) -> Void|Emit network event.")); + c = native_list_append(c, EL_STR("dharma_field|dharma_field(event_type: String) -> String|Block until event.")); + c = native_list_append(c, EL_STR("dharma_peers|dharma_peers() -> [String]|Connected peer IDs.")); + c = native_list_append(c, EL_STR("native_list_empty|native_list_empty() -> [Any]|Empty list (VM alias).")); + c = native_list_append(c, EL_STR("native_list_append|native_list_append(list: [Any], elem: Any) -> [Any]|Append (VM alias).")); + c = native_list_append(c, EL_STR("native_list_len|native_list_len(list: [Any]) -> Int|Length (VM alias).")); + c = native_list_append(c, EL_STR("native_list_get|native_list_get(list: [Any], i: Int) -> Any|Get element (VM alias).")); + c = native_list_append(c, EL_STR("native_list_clone|native_list_clone(list: [Any]) -> [Any]|Clone (VM alias).")); + c = native_list_append(c, EL_STR("native_string_chars|native_string_chars(s: String) -> [String]|Split into chars.")); + c = native_list_append(c, EL_STR("native_int_to_str|native_int_to_str(n: Int) -> String|Int to string (VM alias).")); + return c; + return 0; +} + +el_val_t lsp_builtin_find(el_val_t name, el_val_t catalog) { + el_val_t n = native_list_len(catalog); + el_val_t i = 0; + while (i < n) { + el_val_t entry = native_list_get(catalog, i); + el_val_t bar = str_index_of(entry, EL_STR("|")); + if (bar >= 0) { + el_val_t ename = str_slice(entry, 0, bar); + if (str_eq(ename, name)) { + return entry; + } + } + i = (i + 1); + } + return EL_STR(""); + return 0; +} + +el_val_t lsp_types_key(el_val_t uri, el_val_t type_name) { + return el_str_concat(el_str_concat(el_str_concat(EL_STR("types:"), uri), EL_STR(":")), type_name); + return 0; +} + +el_val_t lsp_vartypes_key(el_val_t uri) { + return el_str_concat(EL_STR("vartypes:"), uri); + return 0; +} + +el_val_t lsp_scan_types(el_val_t uri, el_val_t source) { + el_val_t lines = str_split_lines(source); + el_val_t n = native_list_len(lines); + el_val_t i = 0; + el_val_t in_type = 0; + el_val_t cur_type = EL_STR(""); + el_val_t fields = EL_STR(""); + while (i < n) { + el_val_t line = str_trim(native_list_get(lines, i)); + if (in_type) { + if (str_starts_with(line, EL_STR("}"))) { + state_set(lsp_types_key(uri, cur_type), fields); + in_type = 0; + cur_type = EL_STR(""); + fields = EL_STR(""); + } else { + el_val_t colon_pos = str_index_of(line, EL_STR(":")); + if (colon_pos > 0) { + el_val_t raw_name = str_trim(str_slice(line, 0, colon_pos)); + el_val_t after_colon = str_trim(str_slice(line, (colon_pos + 1), str_len(line))); + el_val_t type_name = after_colon; + el_val_t tlen = str_len(after_colon); + if (tlen > 0) { + el_val_t last_ch = str_slice(after_colon, (tlen - 1), tlen); + if (str_eq(last_ch, EL_STR(","))) { + type_name = str_trim(str_slice(after_colon, 0, (tlen - 1))); + } + } + if (str_len(raw_name) > 0) { + el_val_t fc = str_char_code(raw_name, 0); + el_val_t valid_start = 0; + if (fc >= 97) { + if (fc <= 122) { + valid_start = 1; + } + } + if (fc >= 65) { + if (fc <= 90) { + valid_start = 1; + } + } + if (fc == 95) { + valid_start = 1; + } + if (valid_start) { + if (str_len(fields) > 0) { + fields = el_str_concat(fields, EL_STR("|")); + } + fields = el_str_concat(el_str_concat(el_str_concat(fields, raw_name), EL_STR(":")), type_name); + } + } + } + } + } else { + if (str_starts_with(line, EL_STR("type "))) { + el_val_t after = str_slice(line, 5, str_len(line)); + el_val_t brace_pos = str_index_of(after, EL_STR("{")); + if (brace_pos > 0) { + el_val_t tname = str_trim(str_slice(after, 0, brace_pos)); + if (str_len(tname) > 0) { + in_type = 1; + cur_type = tname; + fields = EL_STR(""); + } + } + } + } + i = (i + 1); + } + return 0; +} + +el_val_t lsp_get_type_fields(el_val_t uri, el_val_t type_name) { + return state_get(lsp_types_key(uri, type_name)); + return 0; +} + +el_val_t lsp_varentry_name(el_val_t entry) { + el_val_t colon = str_index_of(entry, EL_STR(":")); + if (colon <= 0) { + return EL_STR(""); + } + return str_slice(entry, 0, colon); + return 0; +} + +el_val_t lsp_varentry_type(el_val_t entry) { + el_val_t colon = str_index_of(entry, EL_STR(":")); + if (colon < 0) { + return EL_STR(""); + } + return str_slice(entry, (colon + 1), str_len(entry)); + return 0; +} + +el_val_t lsp_scan_vartypes(el_val_t uri, el_val_t source) { + el_val_t lines = str_split_lines(source); + el_val_t n = native_list_len(lines); + el_val_t i = 0; + el_val_t entries = EL_STR(""); + while (i < n) { + el_val_t line = str_trim(native_list_get(lines, i)); + if (str_starts_with(line, EL_STR("let "))) { + el_val_t after_let = str_slice(line, 4, str_len(line)); + el_val_t colon_pos = str_index_of(after_let, EL_STR(":")); + if (colon_pos > 0) { + el_val_t var_name = str_trim(str_slice(after_let, 0, colon_pos)); + el_val_t after_colon = str_trim(str_slice(after_let, (colon_pos + 1), str_len(after_let))); + el_val_t eq_pos = str_index_of(after_colon, EL_STR("=")); + el_val_t raw_type = after_colon; + if (eq_pos > 0) { + raw_type = str_trim(str_slice(after_colon, 0, eq_pos)); + } else { + el_val_t sp_pos = str_index_of(after_colon, EL_STR(" ")); + if (sp_pos > 0) { + raw_type = str_trim(str_slice(after_colon, 0, sp_pos)); + } + } + if (str_len(var_name) > 0) { + if (str_len(raw_type) > 0) { + if (str_len(entries) > 0) { + entries = el_str_concat(entries, EL_STR("|")); + } + entries = el_str_concat(el_str_concat(el_str_concat(entries, var_name), EL_STR(":")), raw_type); + } + } + } + } + if (str_starts_with(line, EL_STR("fn "))) { + el_val_t paren_open = str_index_of(line, EL_STR("(")); + el_val_t paren_close = str_last_index_of(line, EL_STR(")")); + if (paren_open > 0) { + if (paren_close > paren_open) { + el_val_t params_str = str_slice(line, (paren_open + 1), paren_close); + el_val_t params = str_split(params_str, EL_STR(",")); + el_val_t pn = native_list_len(params); + el_val_t pi = 0; + while (pi < pn) { + el_val_t param = str_trim(native_list_get(params, pi)); + el_val_t pc = str_index_of(param, EL_STR(":")); + if (pc > 0) { + el_val_t pname = str_trim(str_slice(param, 0, pc)); + el_val_t ptype = str_trim(str_slice(param, (pc + 1), str_len(param))); + if (str_len(pname) > 0) { + if (str_len(ptype) > 0) { + if (str_len(entries) > 0) { + entries = el_str_concat(entries, EL_STR("|")); + } + entries = el_str_concat(el_str_concat(el_str_concat(entries, pname), EL_STR(":")), ptype); + } + } + } + pi = (pi + 1); + } + } + } + } + i = (i + 1); + } + state_set(lsp_vartypes_key(uri), entries); + return 0; +} + +el_val_t lsp_get_var_type(el_val_t uri, el_val_t var_name) { + el_val_t entries = state_get(lsp_vartypes_key(uri)); + if (str_eq(entries, EL_STR(""))) { + return EL_STR(""); + } + el_val_t parts = str_split(entries, EL_STR("|")); + el_val_t n = native_list_len(parts); + el_val_t i = 0; + while (i < n) { + el_val_t entry = native_list_get(parts, i); + el_val_t ename = lsp_varentry_name(entry); + if (str_eq(ename, var_name)) { + return lsp_varentry_type(entry); + } + i = (i + 1); + } + return EL_STR(""); + return 0; +} + +el_val_t lsp_scan_document(el_val_t uri, el_val_t source) { + lsp_scan_types(uri, source); + lsp_scan_vartypes(uri, source); + return 0; +} + +el_val_t lsp_dot_ident_before(el_val_t text) { + el_val_t tlen = str_len(text); + if (tlen < 2) { + return EL_STR(""); + } + el_val_t last_ch = str_slice(text, (tlen - 1), tlen); + if (!str_eq(last_ch, EL_STR("."))) { + return EL_STR(""); + } + el_val_t dot_pos = (tlen - 1); + el_val_t end_idx = dot_pos; + el_val_t start_idx = dot_pos; + el_val_t going = 1; + while (going) { + if (start_idx <= 0) { + going = 0; + } else { + el_val_t c = str_char_code(text, (start_idx - 1)); + el_val_t is_word = 0; + if (c >= 97) { + if (c <= 122) { + is_word = 1; + } + } + if (c >= 65) { + if (c <= 90) { + is_word = 1; + } + } + if (c >= 48) { + if (c <= 57) { + is_word = 1; + } + } + if (c == 95) { + is_word = 1; + } + if (is_word) { + start_idx = (start_idx - 1); + } else { + going = 0; + } + } + } + if (start_idx >= end_idx) { + return EL_STR(""); + } + return str_slice(text, start_idx, end_idx); + return 0; +} + +el_val_t lsp_line_prefix(el_val_t source, el_val_t line_no, el_val_t char_no) { + el_val_t lines = str_split_lines(source); + if (line_no >= native_list_len(lines)) { + return EL_STR(""); + } + el_val_t line = native_list_get(lines, line_no); + el_val_t line_len = str_len(line); + el_val_t end = char_no; + if (end > line_len) { + end = line_len; + } + return str_slice(line, 0, end); + return 0; +} + +el_val_t lsp_field_completions(el_val_t uri, el_val_t type_name) { + el_val_t fields_str = lsp_get_type_fields(uri, type_name); + if (str_eq(fields_str, EL_STR(""))) { + return EL_STR(""); + } + el_val_t field_entries = str_split(fields_str, EL_STR("|")); + el_val_t n = native_list_len(field_entries); + el_val_t items = native_list_empty(); + el_val_t i = 0; + while (i < n) { + el_val_t entry = native_list_get(field_entries, i); + el_val_t colon = str_index_of(entry, EL_STR(":")); + if (colon > 0) { + el_val_t fname = str_slice(entry, 0, colon); + el_val_t ftype = str_slice(entry, (colon + 1), str_len(entry)); + items = native_list_append(items, lsp_completion_item(fname, 5, ftype)); + } + i = (i + 1); + } + return el_str_concat(el_str_concat(EL_STR("["), str_join(items, EL_STR(","))), EL_STR("]")); + return 0; +} + +el_val_t lsp_extract_fns(el_val_t source) { + el_val_t result = native_list_empty(); + el_val_t lines = str_split_lines(source); + el_val_t n = native_list_len(lines); + el_val_t i = 0; + while (i < n) { + el_val_t line = str_trim(native_list_get(lines, i)); + if (str_starts_with(line, EL_STR("fn "))) { + el_val_t after = str_slice(line, 3, str_len(line)); + el_val_t paren = str_index_of(after, EL_STR("(")); + if (paren > 0) { + el_val_t name = str_trim(str_slice(after, 0, paren)); + if (str_len(name) > 0) { + result = native_list_append(result, name); + } + } + } + i = (i + 1); + } + return result; + return 0; +} + +el_val_t lsp_find_def(el_val_t source, el_val_t fn_name) { + el_val_t lines = str_split_lines(source); + el_val_t n = native_list_len(lines); + el_val_t target1 = el_str_concat(el_str_concat(EL_STR("fn "), fn_name), EL_STR("(")); + el_val_t target2 = el_str_concat(el_str_concat(EL_STR("fn "), fn_name), EL_STR(" (")); + el_val_t i = 0; + while (i < n) { + el_val_t line = native_list_get(lines, i); + el_val_t trimmed = str_trim(line); + if (str_starts_with(trimmed, target1)) { + el_val_t col = str_index_of(line, target1); + if (col < 0) { + col = 0; + } + return el_str_concat(el_str_concat(int_to_str(i), EL_STR(":")), int_to_str(col)); + } + if (str_starts_with(trimmed, target2)) { + el_val_t col = str_index_of(line, target2); + if (col < 0) { + col = 0; + } + return el_str_concat(el_str_concat(int_to_str(i), EL_STR(":")), int_to_str(col)); + } + i = (i + 1); + } + return EL_STR(""); + return 0; +} + +el_val_t lsp_word_at(el_val_t source, el_val_t line_no, el_val_t char_no) { + el_val_t lines = str_split_lines(source); + if (line_no >= native_list_len(lines)) { + return EL_STR(""); + } + el_val_t line = native_list_get(lines, line_no); + el_val_t line_len = str_len(line); + if (char_no >= line_len) { + return EL_STR(""); + } + el_val_t start = char_no; + el_val_t going_back = 1; + while (going_back) { + if (start <= 0) { + going_back = 0; + } else { + el_val_t c = str_char_code(line, (start - 1)); + el_val_t is_word = 0; + if (c >= 97) { + if (c <= 122) { + is_word = 1; + } + } + if (c >= 65) { + if (c <= 90) { + is_word = 1; + } + } + if (c >= 48) { + if (c <= 57) { + is_word = 1; + } + } + if (c == 95) { + is_word = 1; + } + if (is_word) { + start = (start - 1); + } else { + going_back = 0; + } + } + } + el_val_t end = char_no; + el_val_t going_fwd = 1; + while (going_fwd) { + if (end >= line_len) { + going_fwd = 0; + } else { + el_val_t c = str_char_code(line, end); + el_val_t is_word = 0; + if (c >= 97) { + if (c <= 122) { + is_word = 1; + } + } + if (c >= 65) { + if (c <= 90) { + is_word = 1; + } + } + if (c >= 48) { + if (c <= 57) { + is_word = 1; + } + } + if (c == 95) { + is_word = 1; + } + if (is_word) { + end = (end + 1); + } else { + going_fwd = 0; + } + } + } + if (end <= start) { + return EL_STR(""); + } + return str_slice(line, start, end); + return 0; +} + +el_val_t lsp_completion_item(el_val_t label, el_val_t kind, el_val_t detail) { + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"label\":\""), lsp_json_escape(label)), EL_STR("\",\"kind\":")), int_to_str(kind)), EL_STR(",\"detail\":\"")), lsp_json_escape(detail)), EL_STR("\"}")); + return 0; +} + +el_val_t lsp_build_completions(el_val_t uri, el_val_t catalog, el_val_t line_no, el_val_t char_no) { + el_val_t source = lsp_doc_get(uri); + el_val_t prefix = lsp_line_prefix(source, line_no, char_no); + el_val_t dot_ident = lsp_dot_ident_before(prefix); + if (!str_eq(dot_ident, EL_STR(""))) { + el_val_t var_type = lsp_get_var_type(uri, dot_ident); + if (!str_eq(var_type, EL_STR(""))) { + el_val_t field_items = lsp_field_completions(uri, var_type); + if (!str_eq(field_items, EL_STR(""))) { + return field_items; + } + } + } + el_val_t items = native_list_empty(); + el_val_t user_fns = lsp_extract_fns(source); + el_val_t fn_n = native_list_len(user_fns); + el_val_t i = 0; + while (i < fn_n) { + el_val_t name = native_list_get(user_fns, i); + items = native_list_append(items, lsp_completion_item(name, 3, EL_STR("user-defined fn"))); + i = (i + 1); + } + el_val_t bn = native_list_len(catalog); + el_val_t j = 0; + while (j < bn) { + el_val_t entry = native_list_get(catalog, j); + el_val_t bar1 = str_index_of(entry, EL_STR("|")); + if (bar1 >= 0) { + el_val_t bname = str_slice(entry, 0, bar1); + el_val_t rest = str_slice(entry, (bar1 + 1), str_len(entry)); + el_val_t bar2 = str_index_of(rest, EL_STR("|")); + el_val_t sig = EL_STR(""); + if (bar2 >= 0) { + sig = str_slice(rest, 0, bar2); + } else { + sig = rest; + } + items = native_list_append(items, lsp_completion_item(bname, 3, sig)); + } + j = (j + 1); + } + el_val_t kws = native_list_empty(); + kws = native_list_append(kws, EL_STR("fn")); + kws = native_list_append(kws, EL_STR("let")); + kws = native_list_append(kws, EL_STR("return")); + kws = native_list_append(kws, EL_STR("if")); + kws = native_list_append(kws, EL_STR("else")); + kws = native_list_append(kws, EL_STR("while")); + kws = native_list_append(kws, EL_STR("for")); + kws = native_list_append(kws, EL_STR("in")); + kws = native_list_append(kws, EL_STR("true")); + kws = native_list_append(kws, EL_STR("false")); + kws = native_list_append(kws, EL_STR("import")); + kws = native_list_append(kws, EL_STR("match")); + kws = native_list_append(kws, EL_STR("break")); + kws = native_list_append(kws, EL_STR("continue")); + el_val_t kw_n = native_list_len(kws); + el_val_t k = 0; + while (k < kw_n) { + el_val_t kw = native_list_get(kws, k); + items = native_list_append(items, lsp_completion_item(kw, 14, EL_STR("keyword"))); + k = (k + 1); + } + el_val_t types = native_list_empty(); + types = native_list_append(types, EL_STR("String")); + types = native_list_append(types, EL_STR("Int")); + types = native_list_append(types, EL_STR("Bool")); + types = native_list_append(types, EL_STR("Float")); + types = native_list_append(types, EL_STR("Void")); + types = native_list_append(types, EL_STR("Any")); + types = native_list_append(types, EL_STR("Instant")); + types = native_list_append(types, EL_STR("Duration")); + el_val_t t_n = native_list_len(types); + el_val_t t = 0; + while (t < t_n) { + el_val_t ty = native_list_get(types, t); + items = native_list_append(items, lsp_completion_item(ty, 8, EL_STR("type"))); + t = (t + 1); + } + return el_str_concat(el_str_concat(EL_STR("["), str_join(items, EL_STR(","))), EL_STR("]")); + return 0; +} + +el_val_t lsp_keyword_hover(el_val_t word) { + if (str_eq(word, EL_STR("fn"))) { + return EL_STR("Declare a function:\n```el\nfn name(param: Type) -> ReturnType { ... }\n```"); + } + if (str_eq(word, EL_STR("let"))) { + return EL_STR("Bind a local variable:\n```el\nlet name: Type = value\n```"); + } + if (str_eq(word, EL_STR("return"))) { + return EL_STR("Return a value from a function."); + } + if (str_eq(word, EL_STR("if"))) { + return EL_STR("Conditional:\n```el\nif condition { ... } else { ... }\n```"); + } + if (str_eq(word, EL_STR("else"))) { + return EL_STR("Else branch of an if statement."); + } + if (str_eq(word, EL_STR("while"))) { + return EL_STR("Loop while condition is true:\n```el\nwhile condition { ... }\n```"); + } + if (str_eq(word, EL_STR("for"))) { + return EL_STR("Range loop:\n```el\nfor i in 0..n { ... }\n```"); + } + if (str_eq(word, EL_STR("in"))) { + return EL_STR("Used in for-in range loops."); + } + if (str_eq(word, EL_STR("true"))) { + return EL_STR("Boolean literal true."); + } + if (str_eq(word, EL_STR("false"))) { + return EL_STR("Boolean literal false."); + } + if (str_eq(word, EL_STR("import"))) { + return EL_STR("Import a module:\n```el\nimport \"path/to/module.el\"\n```"); + } + if (str_eq(word, EL_STR("match"))) { + return EL_STR("Pattern match:\n```el\nmatch value { \"a\" => ... }\n```"); + } + if (str_eq(word, EL_STR("break"))) { + return EL_STR("Break out of the current while loop."); + } + if (str_eq(word, EL_STR("continue"))) { + return EL_STR("Skip to the next iteration of the current while loop."); + } + if (str_eq(word, EL_STR("String"))) { + return EL_STR("Built-in string type. Strings are immutable byte sequences."); + } + if (str_eq(word, EL_STR("Int"))) { + return EL_STR("Built-in 64-bit signed integer type."); + } + if (str_eq(word, EL_STR("Bool"))) { + return EL_STR("Built-in boolean type. Values: true or false."); + } + if (str_eq(word, EL_STR("Float"))) { + return EL_STR("Built-in 64-bit floating-point type (IEEE 754 double)."); + } + if (str_eq(word, EL_STR("Void"))) { + return EL_STR("Return type for functions that produce no value."); + } + if (str_eq(word, EL_STR("Any"))) { + return EL_STR("Dynamically typed value \xe2\x80\x94 accepts any El type."); + } + return EL_STR(""); + return 0; +} + +el_val_t lsp_build_hover(el_val_t uri, el_val_t line_no, el_val_t char_no, el_val_t catalog) { + el_val_t source = lsp_doc_get(uri); + el_val_t word = lsp_word_at(source, line_no, char_no); + if (str_eq(word, EL_STR(""))) { + return EL_STR("null"); + } + el_val_t kw_doc = lsp_keyword_hover(word); + if (!str_eq(kw_doc, EL_STR(""))) { + el_val_t content = el_str_concat(el_str_concat(el_str_concat(EL_STR("**"), word), EL_STR("** (keyword)\n\n")), kw_doc); + return el_str_concat(el_str_concat(EL_STR("{\"contents\":{\"kind\":\"markdown\",\"value\":\""), lsp_json_escape(content)), EL_STR("\"}}")); + } + el_val_t entry = lsp_builtin_find(word, catalog); + if (!str_eq(entry, EL_STR(""))) { + el_val_t bar1 = str_index_of(entry, EL_STR("|")); + el_val_t rest = str_slice(entry, (bar1 + 1), str_len(entry)); + el_val_t bar2 = str_index_of(rest, EL_STR("|")); + el_val_t sig = EL_STR(""); + el_val_t desc = EL_STR(""); + if (bar2 >= 0) { + sig = str_slice(rest, 0, bar2); + desc = str_slice(rest, (bar2 + 1), str_len(rest)); + } else { + sig = rest; + } + el_val_t content = el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("**"), word), EL_STR("** (builtin)\n\n```el\n")), sig), EL_STR("\n```\n\n")), desc); + return el_str_concat(el_str_concat(EL_STR("{\"contents\":{\"kind\":\"markdown\",\"value\":\""), lsp_json_escape(content)), EL_STR("\"}}")); + } + el_val_t user_fns = lsp_extract_fns(source); + el_val_t uf_n = native_list_len(user_fns); + el_val_t i = 0; + while (i < uf_n) { + el_val_t fn_name = native_list_get(user_fns, i); + if (str_eq(fn_name, word)) { + el_val_t lines = str_split_lines(source); + el_val_t ln = native_list_len(lines); + el_val_t j = 0; + while (j < ln) { + el_val_t line = str_trim(native_list_get(lines, j)); + if (str_starts_with(line, el_str_concat(el_str_concat(EL_STR("fn "), word), EL_STR("(")))) { + el_val_t content = el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("**"), word), EL_STR("** (user-defined)\n\n```el\n")), line), EL_STR("\n```")); + return el_str_concat(el_str_concat(EL_STR("{\"contents\":{\"kind\":\"markdown\",\"value\":\""), lsp_json_escape(content)), EL_STR("\"}}")); + } + j = (j + 1); + } + el_val_t content = el_str_concat(el_str_concat(EL_STR("**"), word), EL_STR("** (user-defined function)")); + return el_str_concat(el_str_concat(EL_STR("{\"contents\":{\"kind\":\"markdown\",\"value\":\""), lsp_json_escape(content)), EL_STR("\"}}")); + } + i = (i + 1); + } + return EL_STR("null"); + return 0; +} + +el_val_t lsp_build_definition(el_val_t uri, el_val_t line_no, el_val_t char_no) { + el_val_t source = lsp_doc_get(uri); + el_val_t word = lsp_word_at(source, line_no, char_no); + if (str_eq(word, EL_STR(""))) { + return EL_STR("null"); + } + el_val_t pos_str = lsp_find_def(source, word); + if (str_eq(pos_str, EL_STR(""))) { + return EL_STR("null"); + } + el_val_t colon = str_index_of(pos_str, EL_STR(":")); + if (colon < 0) { + return EL_STR("null"); + } + el_val_t def_line = str_to_int(str_slice(pos_str, 0, colon)); + el_val_t def_char = str_to_int(str_slice(pos_str, (colon + 1), str_len(pos_str))); + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"uri\":\""), lsp_json_escape(uri)), EL_STR("\",\"range\":{\"start\":{\"line\":")), int_to_str(def_line)), EL_STR(",\"character\":")), int_to_str(def_char)), EL_STR("},\"end\":{\"line\":")), int_to_str(def_line)), EL_STR(",\"character\":")), int_to_str((def_char + str_len(word)))), EL_STR("}}}")); + return 0; +} + +el_val_t lsp_make_diag(el_val_t line_no, el_val_t col_start, el_val_t col_end, el_val_t message, el_val_t severity) { + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"range\":{\"start\":{\"line\":"), int_to_str(line_no)), EL_STR(",\"character\":")), int_to_str(col_start)), EL_STR("},\"end\":{\"line\":")), int_to_str(line_no)), EL_STR(",\"character\":")), int_to_str(col_end)), EL_STR("}},\"severity\":")), int_to_str(severity)), EL_STR(",\"source\":\"el-lsp\",\"message\":\"")), lsp_json_escape(message)), EL_STR("\"}")); + return 0; +} + +el_val_t lsp_compute_diagnostics(el_val_t source) { + el_val_t diags = native_list_empty(); + el_val_t lines = str_split_lines(source); + el_val_t n = native_list_len(lines); + el_val_t brace_depth = 0; + el_val_t paren_depth = 0; + el_val_t bracket_depth = 0; + el_val_t brace_line = 0; + el_val_t paren_line = 0; + el_val_t bracket_line = 0; + el_val_t i = 0; + while (i < n) { + el_val_t line = native_list_get(lines, i); + el_val_t line_len = str_len(line); + el_val_t in_str = 0; + el_val_t escape_next = 0; + el_val_t str_start = 0; + el_val_t ci = 0; + while (ci < line_len) { + el_val_t ch = str_char_code(line, ci); + if (escape_next) { + escape_next = 0; + } else { + if (ch == 92) { + if (in_str) { + escape_next = 1; + } + } else { + if (ch == 34) { + if (in_str) { + in_str = 0; + } else { + in_str = 1; + str_start = ci; + } + } else { + if (!in_str) { + if (ch == 123) { + brace_depth = (brace_depth + 1); + brace_line = i; + } + if (ch == 125) { + if (brace_depth > 0) { + brace_depth = (brace_depth - 1); + } else { + diags = native_list_append(diags, lsp_make_diag(i, ci, (ci + 1), EL_STR("Unexpected '}'"), 1)); + } + } + if (ch == 40) { + paren_depth = (paren_depth + 1); + paren_line = i; + } + if (ch == 41) { + if (paren_depth > 0) { + paren_depth = (paren_depth - 1); + } else { + diags = native_list_append(diags, lsp_make_diag(i, ci, (ci + 1), EL_STR("Unexpected ')'"), 1)); + } + } + if (ch == 91) { + bracket_depth = (bracket_depth + 1); + bracket_line = i; + } + if (ch == 93) { + if (bracket_depth > 0) { + bracket_depth = (bracket_depth - 1); + } else { + diags = native_list_append(diags, lsp_make_diag(i, ci, (ci + 1), EL_STR("Unexpected ']'"), 1)); + } + } + } + } + } + } + ci = (ci + 1); + } + if (in_str) { + diags = native_list_append(diags, lsp_make_diag(i, str_start, line_len, EL_STR("Unterminated string literal"), 1)); + } + i = (i + 1); + } + if (brace_depth > 0) { + diags = native_list_append(diags, lsp_make_diag(brace_line, 0, 1, EL_STR("Unclosed '{' (opened near this line)"), 1)); + } + if (paren_depth > 0) { + diags = native_list_append(diags, lsp_make_diag(paren_line, 0, 1, EL_STR("Unclosed '(' (opened near this line)"), 1)); + } + if (bracket_depth > 0) { + diags = native_list_append(diags, lsp_make_diag(bracket_line, 0, 1, EL_STR("Unclosed '[' (opened near this line)"), 1)); + } + return el_str_concat(el_str_concat(EL_STR("["), str_join(diags, EL_STR(","))), EL_STR("]")); + return 0; +} + +el_val_t lsp_publish_diagnostics(el_val_t uri) { + el_val_t source = lsp_doc_get(uri); + el_val_t diags = lsp_compute_diagnostics(source); + el_val_t notif = lsp_notification(EL_STR("textDocument/publishDiagnostics"), el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"uri\":\""), lsp_json_escape(uri)), EL_STR("\",\"diagnostics\":")), diags), EL_STR("}"))); + lsp_write_message(notif); + return 0; +} + +el_val_t lsp_handle_initialize(el_val_t id) { + el_val_t caps = EL_STR("{\"textDocumentSync\":1,\"completionProvider\":{\"triggerCharacters\":[\".\",\"_\",\"(\"]},\"hoverProvider\":true,\"definitionProvider\":true}"); + el_val_t result = el_str_concat(el_str_concat(EL_STR("{\"capabilities\":"), caps), EL_STR(",\"serverInfo\":{\"name\":\"el-lsp\",\"version\":\"1.0.0\"}}")); + lsp_write_message(lsp_response(id, result)); + return 0; +} + +el_val_t lsp_handle_completion(el_val_t id, el_val_t params, el_val_t catalog) { + el_val_t td = json_get_raw(params, EL_STR("textDocument")); + el_val_t uri = json_get_string(td, EL_STR("uri")); + el_val_t pos = json_get_raw(params, EL_STR("position")); + el_val_t line_no = json_get_int(pos, EL_STR("line")); + el_val_t char_no = json_get_int(pos, EL_STR("character")); + el_val_t items = lsp_build_completions(uri, catalog, line_no, char_no); + el_val_t result = el_str_concat(el_str_concat(EL_STR("{\"isIncomplete\":false,\"items\":"), items), EL_STR("}")); + lsp_write_message(lsp_response(id, result)); + return 0; +} + +el_val_t lsp_handle_hover(el_val_t id, el_val_t params, el_val_t catalog) { + el_val_t td = json_get_raw(params, EL_STR("textDocument")); + el_val_t uri = json_get_string(td, EL_STR("uri")); + el_val_t pos = json_get_raw(params, EL_STR("position")); + el_val_t line_no = json_get_int(pos, EL_STR("line")); + el_val_t char_no = json_get_int(pos, EL_STR("character")); + el_val_t result = lsp_build_hover(uri, line_no, char_no, catalog); + lsp_write_message(lsp_response(id, result)); + return 0; +} + +el_val_t lsp_handle_definition(el_val_t id, el_val_t params) { + el_val_t td = json_get_raw(params, EL_STR("textDocument")); + el_val_t uri = json_get_string(td, EL_STR("uri")); + el_val_t pos = json_get_raw(params, EL_STR("position")); + el_val_t line_no = json_get_int(pos, EL_STR("line")); + el_val_t char_no = json_get_int(pos, EL_STR("character")); + el_val_t result = lsp_build_definition(uri, line_no, char_no); + lsp_write_message(lsp_response(id, result)); + return 0; +} + +el_val_t lsp_handle_did_open(el_val_t params, el_val_t catalog) { + el_val_t td = json_get_raw(params, EL_STR("textDocument")); + el_val_t uri = json_get_string(td, EL_STR("uri")); + el_val_t text = json_get_string(td, EL_STR("text")); + lsp_doc_store(uri, text); + lsp_scan_document(uri, text); + lsp_publish_diagnostics(uri); + return 0; +} + +el_val_t lsp_handle_did_change(el_val_t params) { + el_val_t td = json_get_raw(params, EL_STR("textDocument")); + el_val_t uri = json_get_string(td, EL_STR("uri")); + el_val_t changes = json_get_raw(params, EL_STR("contentChanges")); + el_val_t first = json_array_get(changes, 0); + el_val_t text = json_get_string(first, EL_STR("text")); + lsp_doc_store(uri, text); + lsp_scan_document(uri, text); + lsp_publish_diagnostics(uri); + return 0; +} + +el_val_t lsp_handle_did_close(el_val_t params) { + el_val_t td = json_get_raw(params, EL_STR("textDocument")); + el_val_t uri = json_get_string(td, EL_STR("uri")); + lsp_doc_remove(uri); + el_val_t notif = lsp_notification(EL_STR("textDocument/publishDiagnostics"), el_str_concat(el_str_concat(EL_STR("{\"uri\":\""), lsp_json_escape(uri)), EL_STR("\",\"diagnostics\":[]}"))); + lsp_write_message(notif); + return 0; +} + +el_val_t lsp_handle_did_save(el_val_t params) { + el_val_t td = json_get_raw(params, EL_STR("textDocument")); + el_val_t uri = json_get_string(td, EL_STR("uri")); + lsp_publish_diagnostics(uri); + return 0; +} + +el_val_t lsp_handle_shutdown(el_val_t id) { + lsp_write_message(lsp_response(id, EL_STR("null"))); + return 0; +} + +el_val_t lsp_dispatch(el_val_t msg, el_val_t catalog) { + el_val_t method = json_get_string(msg, EL_STR("method")); + el_val_t id_raw = json_get_raw(msg, EL_STR("id")); + el_val_t id = id_raw; + if (str_eq(id, EL_STR(""))) { + id = EL_STR("null"); + } + el_val_t params_raw = json_get_raw(msg, EL_STR("params")); + el_val_t params = params_raw; + if (str_eq(params, EL_STR(""))) { + params = EL_STR("{}"); + } + if (str_eq(method, EL_STR("initialize"))) { + lsp_handle_initialize(id); + return 1; + } + if (str_eq(method, EL_STR("initialized"))) { + return 1; + } + if (str_eq(method, EL_STR("shutdown"))) { + lsp_handle_shutdown(id); + return 1; + } + if (str_eq(method, EL_STR("exit"))) { + return 0; + } + if (str_eq(method, EL_STR("textDocument/didOpen"))) { + lsp_handle_did_open(params, catalog); + return 1; + } + if (str_eq(method, EL_STR("textDocument/didChange"))) { + lsp_handle_did_change(params); + return 1; + } + if (str_eq(method, EL_STR("textDocument/didClose"))) { + lsp_handle_did_close(params); + return 1; + } + if (str_eq(method, EL_STR("textDocument/didSave"))) { + lsp_handle_did_save(params); + return 1; + } + if (str_eq(method, EL_STR("textDocument/completion"))) { + lsp_handle_completion(id, params, catalog); + return 1; + } + if (str_eq(method, EL_STR("textDocument/hover"))) { + lsp_handle_hover(id, params, catalog); + return 1; + } + if (str_eq(method, EL_STR("textDocument/definition"))) { + lsp_handle_definition(id, params); + return 1; + } + if (!str_eq(id, EL_STR("null"))) { + lsp_write_message(lsp_error_response(id, (-32601), el_str_concat(EL_STR("Method not found: "), method))); + } + return 1; + return 0; +} + +int main(int _argc, char** _argv) { + el_runtime_init_args(_argc, _argv); + el_val_t catalog = lsp_builtin_catalog(); + el_val_t running = 1; + while (running) { + el_val_t msg = lsp_read_message(); + if (str_eq(msg, EL_STR(""))) { + running = 0; + } else { + el_val_t cont = lsp_dispatch(msg, catalog); + if (!cont) { + running = 0; + } + } + } + return 0; +} + diff --git a/tools/lsp/el-lsp.el b/tools/lsp/el-lsp.el index 340ec4c..765c4f1 100644 --- a/tools/lsp/el-lsp.el +++ b/tools/lsp/el-lsp.el @@ -299,6 +299,293 @@ fn lsp_builtin_find(name: String, catalog: [String]) -> String { "" } +// ── Type registry & variable type map ───────────────────────────────────── + +// Key helpers for type registry and vartype map in process state. +fn lsp_types_key(uri: String, type_name: String) -> String { + "types:" + uri + ":" + type_name +} + +fn lsp_vartypes_key(uri: String) -> String { + "vartypes:" + uri +} + +// Scan source for `type Name { field: Type, ... }` declarations. +// Stores each type's fields in state as "field1:Type1|field2:Type2|...". +fn lsp_scan_types(uri: String, source: String) -> Void { + let lines: [String] = str_split_lines(source) + let n: Int = native_list_len(lines) + let i: Int = 0 + let in_type: Bool = false + let cur_type: String = "" + let fields: String = "" + while i < n { + let line: String = str_trim(native_list_get(lines, i)) + if in_type { + // Check for closing brace (end of type block) + if str_starts_with(line, "}") { + // Save accumulated fields for cur_type + state_set(lsp_types_key(uri, cur_type), fields) + let in_type = false + let cur_type = "" + let fields = "" + } else { + // Try to parse "fieldName: TypeName," or "fieldName: TypeName" + let colon_pos: Int = str_index_of(line, ":") + if colon_pos > 0 { + let raw_name: String = str_trim(str_slice(line, 0, colon_pos)) + let after_colon: String = str_trim(str_slice(line, colon_pos + 1, str_len(line))) + // Strip trailing comma + let type_name: String = after_colon + let tlen: Int = str_len(after_colon) + if tlen > 0 { + let last_ch: String = str_slice(after_colon, tlen - 1, tlen) + if str_eq(last_ch, ",") { + let type_name = str_trim(str_slice(after_colon, 0, tlen - 1)) + } + } + // Validate field name (non-empty, starts with letter or _) + if str_len(raw_name) > 0 { + let fc: Int = str_char_code(raw_name, 0) + let valid_start: Bool = false + if fc >= 97 { if fc <= 122 { let valid_start = true } } + if fc >= 65 { if fc <= 90 { let valid_start = true } } + if fc == 95 { let valid_start = true } + if valid_start { + if str_len(fields) > 0 { + let fields = fields + "|" + } + let fields = fields + raw_name + ":" + type_name + } + } + } + } + } else { + // Look for "type Name {" pattern + if str_starts_with(line, "type ") { + let after: String = str_slice(line, 5, str_len(line)) + let brace_pos: Int = str_index_of(after, "{") + if brace_pos > 0 { + let tname: String = str_trim(str_slice(after, 0, brace_pos)) + if str_len(tname) > 0 { + let in_type = true + let cur_type = tname + let fields = "" + } + } + } + } + let i = i + 1 + } +} + +// Look up fields for a type name. Returns "field1:Type1|field2:Type2|..." or "". +fn lsp_get_type_fields(uri: String, type_name: String) -> String { + state_get(lsp_types_key(uri, type_name)) +} + +// Parse a single vartype entry "varName:TypeName" — extract the var name. +fn lsp_varentry_name(entry: String) -> String { + let colon: Int = str_index_of(entry, ":") + if colon <= 0 { + return "" + } + str_slice(entry, 0, colon) +} + +// Parse a single vartype entry "varName:TypeName" — extract the type name. +fn lsp_varentry_type(entry: String) -> String { + let colon: Int = str_index_of(entry, ":") + if colon < 0 { + return "" + } + str_slice(entry, colon + 1, str_len(entry)) +} + +// Scan source for variable type annotations: +// let varName: TypeName = ... +// fn foo(varName: TypeName, ...) -> RetType { +// Stores in state as "var1:Type1|var2:Type2|...". +fn lsp_scan_vartypes(uri: String, source: String) -> Void { + let lines: [String] = str_split_lines(source) + let n: Int = native_list_len(lines) + let i: Int = 0 + let entries: String = "" + while i < n { + let line: String = str_trim(native_list_get(lines, i)) + // Handle "let varName: TypeName" declarations + if str_starts_with(line, "let ") { + let after_let: String = str_slice(line, 4, str_len(line)) + let colon_pos: Int = str_index_of(after_let, ":") + if colon_pos > 0 { + let var_name: String = str_trim(str_slice(after_let, 0, colon_pos)) + let after_colon: String = str_trim(str_slice(after_let, colon_pos + 1, str_len(after_let))) + // Extract type — stop at '=' or whitespace + let eq_pos: Int = str_index_of(after_colon, "=") + let raw_type: String = after_colon + if eq_pos > 0 { + let raw_type = str_trim(str_slice(after_colon, 0, eq_pos)) + } else { + let sp_pos: Int = str_index_of(after_colon, " ") + if sp_pos > 0 { + let raw_type = str_trim(str_slice(after_colon, 0, sp_pos)) + } + } + if str_len(var_name) > 0 { + if str_len(raw_type) > 0 { + if str_len(entries) > 0 { + let entries = entries + "|" + } + let entries = entries + var_name + ":" + raw_type + } + } + } + } + // Handle "fn name(param: Type, ...)" — extract each parameter's type annotation + if str_starts_with(line, "fn ") { + let paren_open: Int = str_index_of(line, "(") + let paren_close: Int = str_last_index_of(line, ")") + if paren_open > 0 { + if paren_close > paren_open { + let params_str: String = str_slice(line, paren_open + 1, paren_close) + // Split by comma to get each param + let params: [String] = str_split(params_str, ",") + let pn: Int = native_list_len(params) + let pi: Int = 0 + while pi < pn { + let param: String = str_trim(native_list_get(params, pi)) + let pc: Int = str_index_of(param, ":") + if pc > 0 { + let pname: String = str_trim(str_slice(param, 0, pc)) + let ptype: String = str_trim(str_slice(param, pc + 1, str_len(param))) + if str_len(pname) > 0 { + if str_len(ptype) > 0 { + if str_len(entries) > 0 { + let entries = entries + "|" + } + let entries = entries + pname + ":" + ptype + } + } + } + let pi = pi + 1 + } + } + } + } + let i = i + 1 + } + state_set(lsp_vartypes_key(uri), entries) +} + +// Look up a variable's type. Returns type name or "". +fn lsp_get_var_type(uri: String, var_name: String) -> String { + let entries: String = state_get(lsp_vartypes_key(uri)) + if str_eq(entries, "") { + return "" + } + let parts: [String] = str_split(entries, "|") + let n: Int = native_list_len(parts) + let i: Int = 0 + while i < n { + let entry: String = native_list_get(parts, i) + let ename: String = lsp_varentry_name(entry) + if str_eq(ename, var_name) { + return lsp_varentry_type(entry) + } + let i = i + 1 + } + "" +} + +// Scan both types and vartypes from source — call on open/change. +fn lsp_scan_document(uri: String, source: String) -> Void { + lsp_scan_types(uri, source) + lsp_scan_vartypes(uri, source) +} + +// Given a line of text up to the cursor, extract the identifier before a trailing '.'. +// e.g. "let x = user." → "user" +// "foo.bar." → "bar" (innermost only — sufficient for one-level field access) +// Returns "" if the text doesn't end with "identifier.". +fn lsp_dot_ident_before(text: String) -> String { + let tlen: Int = str_len(text) + if tlen < 2 { + return "" + } + // Must end with '.' + let last_ch: String = str_slice(text, tlen - 1, tlen) + if !str_eq(last_ch, ".") { + return "" + } + // Find the identifier immediately before the dot + let dot_pos: Int = tlen - 1 + // Walk backwards from dot_pos-1 collecting word chars + let end_idx: Int = dot_pos + let start_idx: Int = dot_pos + let going: Bool = true + while going { + if start_idx <= 0 { + let going = false + } else { + let c: Int = str_char_code(text, start_idx - 1) + let is_word: Bool = false + if c >= 97 { if c <= 122 { let is_word = true } } + if c >= 65 { if c <= 90 { let is_word = true } } + if c >= 48 { if c <= 57 { let is_word = true } } + if c == 95 { let is_word = true } + if is_word { + let start_idx = start_idx - 1 + } else { + let going = false + } + } + } + if start_idx >= end_idx { + return "" + } + str_slice(text, start_idx, end_idx) +} + +// Extract text on the given line up to (not including) char_no. +fn lsp_line_prefix(source: String, line_no: Int, char_no: Int) -> String { + let lines: [String] = str_split_lines(source) + if line_no >= native_list_len(lines) { + return "" + } + let line: String = native_list_get(lines, line_no) + let line_len: Int = str_len(line) + let end: Int = char_no + if end > line_len { + let end = line_len + } + str_slice(line, 0, end) +} + +// Build field completion items for a given type. Returns JSON array string or "". +// Returns "" (not "[]") if no type/fields found, so caller can fall back. +fn lsp_field_completions(uri: String, type_name: String) -> String { + let fields_str: String = lsp_get_type_fields(uri, type_name) + if str_eq(fields_str, "") { + return "" + } + let field_entries: [String] = str_split(fields_str, "|") + let n: Int = native_list_len(field_entries) + let items: [String] = native_list_empty() + let i: Int = 0 + while i < n { + let entry: String = native_list_get(field_entries, i) + let colon: Int = str_index_of(entry, ":") + if colon > 0 { + let fname: String = str_slice(entry, 0, colon) + let ftype: String = str_slice(entry, colon + 1, str_len(entry)) + // kind=5 is Field in LSP + let items = native_list_append(items, lsp_completion_item(fname, 5, ftype)) + } + let i = i + 1 + } + "[" + str_join(items, ",") + "]" +} + // ── Source scanning ──────────────────────────────────────────────────────── // Extract user-defined function names from source text. @@ -415,8 +702,22 @@ fn lsp_completion_item(label: String, kind: Int, detail: String) -> String { "{\"label\":\"" + lsp_json_escape(label) + "\",\"kind\":" + int_to_str(kind) + ",\"detail\":\"" + lsp_json_escape(detail) + "\"}" } -fn lsp_build_completions(uri: String, catalog: [String]) -> String { +fn lsp_build_completions(uri: String, catalog: [String], line_no: Int, char_no: Int) -> String { let source: String = lsp_doc_get(uri) + // Check for dot-access: if the text before the cursor ends with "identifier.", + // return field completions for that variable's type. + let prefix: String = lsp_line_prefix(source, line_no, char_no) + let dot_ident: String = lsp_dot_ident_before(prefix) + if !str_eq(dot_ident, "") { + // Look up the variable's type + let var_type: String = lsp_get_var_type(uri, dot_ident) + if !str_eq(var_type, "") { + let field_items: String = lsp_field_completions(uri, var_type) + if !str_eq(field_items, "") { + return field_items + } + } + } let items: [String] = native_list_empty() // User-defined fns (kind=3 Function) let user_fns: [String] = lsp_extract_fns(source) @@ -708,7 +1009,10 @@ fn lsp_handle_initialize(id: String) -> Void { fn lsp_handle_completion(id: String, params: String, catalog: [String]) -> Void { let td: String = json_get_raw(params, "textDocument") let uri: String = json_get_string(td, "uri") - let items: String = lsp_build_completions(uri, catalog) + let pos: String = json_get_raw(params, "position") + let line_no: Int = json_get_int(pos, "line") + let char_no: Int = json_get_int(pos, "character") + let items: String = lsp_build_completions(uri, catalog, line_no, char_no) let result: String = "{\"isIncomplete\":false,\"items\":" + items + "}" lsp_write_message(lsp_response(id, result)) } @@ -738,6 +1042,7 @@ fn lsp_handle_did_open(params: String, catalog: [String]) -> Void { let uri: String = json_get_string(td, "uri") let text: String = json_get_string(td, "text") lsp_doc_store(uri, text) + lsp_scan_document(uri, text) lsp_publish_diagnostics(uri) } @@ -748,6 +1053,7 @@ fn lsp_handle_did_change(params: String) -> Void { let first: String = json_array_get(changes, 0) let text: String = json_get_string(first, "text") lsp_doc_store(uri, text) + lsp_scan_document(uri, text) lsp_publish_diagnostics(uri) }