i’m trying to optimize my end-user’s experience within vscode – which for me means that hover
, hints
, and intellisense
are as accurate and informative as possible… yes, i know that the current zls will someday be replaced with the “incremental compiler”; but that could be a long time from now, and i’d like to at least get some near-term improvement…
to keep it simple, my criterion for “success” is this: the end-user enters a “.” after some identifier and hopes to see a list of features they can select…
with a relatively simple source file, what we have today is certainly “good enough”… where i’ve noticed things start to break down is with the introduction of (some) generic functions that synthesize types in a rather complex fashion…
here’s some “simple” psuedo-code which the zls handles properly:
pub const Itab = struct {
foo: *const @TypeOf(foo) = &foo,
bar: *const @TypeOf(bar) = &bar,
};
pub fn foo() void {
...
}
pub fn bar(x: u32) u32 {
...
}
details aside, you can certainly see the pattern here… given an instance iobj: Itab
, typing “iobj.
” in vscode gives you choices bar
and foo
as you would expect…
it turns out that i’m able to “reify” the Itab
struct with a generic function that locates all the public functions of this source file… certainly less tedious than maintaining Itab
manually!!!
but now, zls
can’t really grok the reified Itab
; and the user gets no suggestions in the editor when typing “iobj.
” as the type of iobj
is “unknown”… but obviously the underlying compiler has no issue here, and outputs the same object code as the original “hand-generated” version…
[[ BTW, would a future zls that is based on the incremental compiler “fix” this deficiency??? ]]
standing back, i find that i’m applying a number of design patterns in my codebase which ultimately introduce some redunancy in the sources… in SOME cases, i can implement a generic function to handle the pattern (though with a downgraded zls experience)…
but then, there are other cases where the alternative to manually realizing some pattern would be some sort of source code transformation…
going back to original example, suppose i had simply declared Itab
as my interface specification:
const Itab = struct {
foo: *const fn() void,
bar: *const fn(x: u32) u32,
};
armed with this declaration, i would like generate a set of stub implementation functions – which basically swallow their args and return a “zero” value where necessary…
[[ when i worked with java in eclipse, the “experience” of implementing an interface was great; adding skeletal code to the file open in the editor was just a right-click away… ]]
using Ast.parse
and Ast.render
with the editor’s current contents, i can easily see my way through this… and these transformations can happen outside of zls itself, which simply needs to stay in sync with the editor’s contents…
as suggested earlier, these sorts of transformations should not only simplify the application of certain design patterns, but should also yield (in general) “more lines” of code that are otherwise “simpler” for zls to grok…
these ideas are not unrelated to this post, as well as discussions on “source-code templating”… given that i would like my user to “see” the zig code that is also “seen” by zls, how should i approach an “interactive” implementation within a smart editor???