diff options
| author | 2026-10-14 09:39:22 +0000 | |
|---|---|---|
| committer | 2026-10-14 09:39:22 +0000 | |
| commit | 6bb3d79cbd853601623095b497a1807489c3ef6e (patch) | |
| tree | 188bc9ceb6d6db1670427f4355529eb8d46d1494 /src/lsp | |
| parent | todo: record the reverted unchecked trial and what it showed (diff) | |
add c-style typedef and a built-in string alias
typedef T name; binds name to the type record of T, at the top level or
in a function (scoped to its block). string is a built-in alias for char*.
A type name straight before , or ) in a parameter list is the parameter's
name, so fn f(string) still works. The language server shows typedef T
name; on hover and highlights typedef as a keyword.
Diffstat (limited to 'src/lsp')
| -rw-r--r-- | src/lsp/server.zc | 50 |
1 files changed, 45 insertions, 5 deletions
diff --git a/src/lsp/server.zc b/src/lsp/server.zc index 1608c4c..3262e39 100644 --- a/src/lsp/server.zc +++ b/src/lsp/server.zc @@ -390,7 +390,7 @@ int isopc(int c) { int iskeyword(int n) { return n == run.s_fn || n == run.s_var || n == run.s_const || n == run.s_else || n == run.s_as || n == run.s_unchecked || n == run.s_immediate || n == run.s_case || n == run.s_default || n == run.s_do || n == run.s_while || n == run.s_enum || n == run.s_include || n == run.s_memdebug - || n == run.s_enhance || n == run.s_micro || n == run.s_vm || n == run.s_struct || n == run.s_type || n == run.s_typecheck || n == run.s_static; + || n == run.s_enhance || n == run.s_micro || n == run.s_vm || n == run.s_struct || n == run.s_type || n == run.s_typedef || n == run.s_typecheck || n == run.s_static; } // the record of the name at byte offset o (see rs_note in the compiler), or -1. // the records are sorted by offset, so this is a binary search. @@ -934,7 +934,7 @@ int reply_error(int code) { return 0; } -int hs_name = -1, hs_first = -1, hs_const; +int hs_name = -1, hs_first = -1, hs_const, hs_typedef, hs_tname; int bs_k, bs_off; // the embedded source and name offset found by bs_find // ---- hover ---- @@ -999,8 +999,8 @@ word hover_decl(int base, int ls, int le) { // it (hcs is -1 when none) which runs to the line at hdl. a declaration needs // no comment, so the signature still shows without one. int hover_scan(int i) { - hs_name = -1; hs_first = -1; hs_const = 0; - if (hover_source_decl(i) || hover_source_function(i)) return 1; + hs_name = -1; hs_first = -1; hs_const = 0; hs_typedef = 0; + if (hover_typedef(i) || hover_source_decl(i) || hover_source_function(i)) return 1; int base = doff[i], size = dsize[i], ls = 0, le, cs = 0 - 1, c0; while (ls < size) { le = ls; @@ -1182,6 +1182,12 @@ int hover_docs(int i, int head, int name, int length, int tail) { int hover_fill(int i) { int base = doff[i], o = hdl, c, cs, ls, typed = 0, k, run.start, end; hn = 0; + if (hs_typedef) { // typedef T name; as written, from its first word to its ; + hov_text("```zc\n"); c = hdl; + while (c < hdle) { hov_put(dc(base, c)); c++; } + hov_text("\n```"); hover_docs(i, hdl, hdl, 0 - 1, hdle); + return hn; + } if (hs_name >= 0) { hov_text("```zc\n"); c = hdl; while (c < hs_first) { hov_put(dc(base, c)); c++; } @@ -1624,9 +1630,11 @@ int hover_type_span(int i) { } if (best < 0) return 0; t = run.ht_type[best]; + // a typedef name is shown as its typedef, then the type it stands for + if (width == rt.len_w(hname) && run.ht_start[best] == hoff && hover_typedef(i)) { hover_fill(i); hover_type_info(t); return 1; } hov_text("```zc\n"); hov_type(t); hov_text("\n```"); hover_type_info(t); k = kwtext(); - if (k && (hname_is("word") || hname_is("int") || hname_is("char") || hname_is("bool") || hname_is("void") || hname_is("float") || hname_is("f32") || hname_is("f64") || hname_is("byte") || hname_is("u8") || hname_is("i8") || hname_is("u16") || hname_is("i16") || hname_is("u32") || hname_is("i32"))) { + if (k && (hname_is("word") || hname_is("int") || hname_is("char") || hname_is("bool") || hname_is("void") || hname_is("float") || hname_is("f32") || hname_is("f64") || hname_is("byte") || hname_is("string") || hname_is("u8") || hname_is("i8") || hname_is("u16") || hname_is("i16") || hname_is("u32") || hname_is("i32"))) { while (*k && *k != '~') k++; if (*k) { hov_text("\n\n"); hov_text(k + 1); } } @@ -1686,6 +1694,8 @@ char* kwtext() { if (hname_is("return")) return "return e; or return;~leaves the function with a value, or leaves a void function. returning an owned local transfers it to the caller automatically."; if (hname_is("enum")) return "enum name { A, B = 5 };~global constants. under typecheck on they are a type of their own, and a member can carry fields to make a constructor."; if (hname_is("struct")) return "struct name { fields };~a record type. struct name<T> { } makes it generic, one copy for each set of type arguments."; + if (hname_is("typedef")) return "typedef T name;~an alias for a type, the same as type name = T; but in C order. the name is another way to write T, not a new type. inside a function it lasts to the end of its block."; + if (hname_is("string")) return "string~a built-in alias for char*, a word string, as if typedef char* string; were written."; if (hname_is("type")) return "type name = T;~an alias for a type, such as type row = int[3]; for a pointer to an array."; if (hname_is("include")) return "include \"path\"; / include std;~compiles a file or the embedded standard library at that point, its signatures first."; if (hname_is("embed")) return "embed \"path\" as [type] name;~declares name with the bytes of the file at path, read when the unit is compiled. with no type, or bstr, name is a byte string; char* holds one character per word; a number type reads the bytes little-endian; T[] and T[n] lay them out as array elements."; @@ -2160,6 +2170,7 @@ int bs_name(char* path) { } // the offset of the name a declaration line declares: the word before its first delimiter int decl_off(int base, int ls, int le) { + if (hs_typedef) return hs_tname; if (hs_name >= 0) return hs_name; int dl = ls, e, b; while (dl < le && !hdelim(dc(base, dl))) dl++; @@ -2441,6 +2452,35 @@ int hover_source_function(int i) { } return 0; } +// the statement typedef T name; that declares hname, found by tokens, at the top level or in a block +// (the last such one before the cursor, else the first). hdl and hdle are the typedef word and the end +// of the ;, and hs_tname is where the name is. +int hover_typedef(int i) { + int t = 0, w, depth, last, found = -1, first = -1, fend, fname, hend, hname_at; + fm_lex(i); + while (t < fm_nt) { + if (fm_k[t] == 7) break; + if (!fm_is(i, t, "typedef")) { t++; continue; } + w = t + 1; depth = 0; last = -1; + while (w < fm_nt && fm_k[w] != 7) { + if (fm_k[w] == 6 && fm_o[w] == 2 && !depth) break; + if (fm_k[w] == 6 && (fm_o[w] == 5 || fm_o[w] == 6)) break; + if (fm_k[w] == 6 && fm_o[w] == 3) depth++; + else if (fm_k[w] == 6 && fm_o[w] == 4) depth--; + else if (fm_k[w] == 1 && !depth) last = w; + w++; + } + if (w < fm_nt && fm_k[w] == 6 && fm_o[w] == 2 && last > t && hs_match(i, last)) { + if (first < 0) { first = t; fend = fm_e[w]; fname = fm_s[last]; } + if (fm_s[t] <= hcursor) { found = t; hend = fm_e[w]; hname_at = fm_s[last]; } + } + t = w + 1; + } + if (first < 0) return 0; + if (found < 0) { found = first; hend = fend; hname_at = fname; } + hdl = fm_s[found]; hdle = hend; hs_tname = hname_at; hs_typedef = 1; hs_name = -1; hs_first = -1; hs_const = 0; hcs = -1; + return 1; +} int hover_source_decl(int i) { int t = 0, head = -1, first = -1, candidate = -1, depth = 0, brackets = 0, init = 0, constant = 0, matched = 0, tail, prev = -1; fm_lex(i); |
