racket-langserver
racket-langserver copied to clipboard
Function Parameter/Field Name Virtual Text Inference
rust-analyzer provides a very neat feature in that it will print out virtual text of struct field names and function param names when you call said function.
This feature would be a huge productivity gain for racket as structs will be much easier to work with, along with functions. Currently I create a lot of keyword functions for structs that are very large because I don't want to keep guessing what they are by position. (I have looked into the rebellion packages and etc but ehh, I prefer to minimize dependencies)

pub struct Rect {
pub x: u32,
pub y: u32,
pub w: u32,
pub h: u32,
}
impl Rect {
pub fn new(x: u32, y: u32, w: u32, h: u32) -> Self {
Self { x, y, w, h }
}
}
//so we can have a more ergonomic syntax for creating structs by position
let r = Rect::new(0, 5, 32, 32);
Hmm. What would Rust suggest for f in the following code (when written in Rust, of course)?
(define (test f)
(f 1 2 3))
(define (g a b c)
(+ a b c))
(define (h x y z)
(- x y z))
(test g)
(test h)

fn test(f: fn(i32, i32, i32) -> i32, _dummy: i32) -> i32 {
f(1, 2, 3)
}
fn g(a: i32, b: i32, c: i32) -> i32 {
a + b + c
}
fn h(x: i32, y: i32, z: i32) -> i32 {
x - y - z
}
fn main() {
test(g, 1);
test(h, 0);
Is this something that can be handled entirely by the language server? Does the protocol have a standard way for servers to tell editors to show that kind of overlay?
@jackfirth I would think that its something entirely handled by the language server yes.
As for a standard way:
According to https://rust-analyzer.github.io/manual.html#inlay-hints , the source file says:
VS Code does not have native support for inlay hints https://github.com/microsoft/vscode/issues/16221[yet] and the hints are implemented using decorations.
https://github.com/microsoft/vscode/issues/16221#issuecomment-363087092
I want to look into implementing this at some point but I don't know much about language server among other things.... If someone does get this working, I will love you forever :heart: !
Oh wow, that's really cool. This definitely seems worth looking into then.
https://code.visualstudio.com/updates/v1_64#_inlay-hint-api https://code.visualstudio.com/updates/v1_66#_language-server-protocol
the feature is stable now in vscode!
NOTE: LSP specification
- https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_inlayHint
@jestarray the method part is merged, the rest is how to collect struct fields information and put them into “inlayHint” method.
@dannypsnl awesome work! Read your PR, so the main blocker is official support from racket syncheck-annotations<%>? Should an issue be filed in drracket for it?
syncheck-annotations<%> supporting will make things easier, but not totally a block, it's still possible to read field information back. The following steps should work
Steps
- collects definition from
syncheck-annotations<%>(very easy) - use
racket:text%'s methods likesexp-backwardto ensure if it's a structure or a procedure definition - then read the s-expr
(struct s-name ps-name? (fields ...))and parsing - now stores the meta info into a new
hashinto the collector for file - when finding an application via
syncheck-annotations<%>(very easy), lookup the meta info for procedure location and build a hint
Challenge
Though the above will work, the biggest problem is performance. If you check text-document.rkt and go to definition procedure part, you can find that I use text% rather than racket:text%, use racket:text% will bring significantly slow down the reaction somehow. However, the racket:text% used for did-open! cannot be changed, it has real usage.
The core problem of the architecture is, it should prepare a collector for each file in the project open(as IDE) to provide ready information for usage like inlay hints, but we have did-open!, did-close! only for now.
A redesigned picture would be
did-open!only opensracket:text%that collects certain usage like formatting, etc- prefetching data when workspace ready(related to #74)
- refers to https://github.com/racket-tw/sauron for the concrete implementation, below are my related blog posts
- https://dannypsnl.me/blog/2022-07-25-sauron-dev-log/
- https://dannypsnl.me/blog/2022-09-03-racket-future/
- parallelly build collectors for files
- use prepared data for jump to definition and find references such features
- refers to https://github.com/racket-tw/sauron for the concrete implementation, below are my related blog posts
However, threading will not help, other solutions also have their own problem
racket/placeis too big(basically is a system thread size on a UNIX-like system), in this case, per file per thread is a bad idearacket/futurewould be thin enough but lack control and computation properties
Based on the second solution, I'm thinking of a draft idea, hope these will help