aboutsummaryrefslogtreecommitdiff
path: root/src/lsp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lsp')
-rw-r--r--src/lsp/server.zc50
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);