Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Function Parameter/Field Name Virtual Text Inference #29

Open
jestarray opened this issue Feb 22, 2021 · 10 comments
Open

Function Parameter/Field Name Virtual Text Inference #29

jestarray opened this issue Feb 22, 2021 · 10 comments

Comments

@jestarray
Copy link

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)

image

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);
@sorawee
Copy link

sorawee commented Feb 22, 2021

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)

@jestarray
Copy link
Author

image

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);

@jackfirth
Copy link
Contributor

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?

@jestarray
Copy link
Author

@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.

microsoft/vscode#16221 (comment)

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 ❤️ !

@jackfirth
Copy link
Contributor

Oh wow, that's really cool. This definitely seems worth looking into then.

@jestarray
Copy link
Author

jestarray commented Apr 18, 2022

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!

@dannypsnl
Copy link
Contributor

@dannypsnl
Copy link
Contributor

dannypsnl commented Nov 13, 2022

@jestarray the method part is merged, the rest is how to collect struct fields information and put them into “inlayHint” method.

@jestarray
Copy link
Author

@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?

@dannypsnl
Copy link
Contributor

dannypsnl commented Nov 13, 2022

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

  1. collects definition from syncheck-annotations<%>(very easy)
  2. use racket:text%'s methods like sexp-backward to ensure if it's a structure or a procedure definition
  3. then read the s-expr (struct s-name ps-name? (fields ...)) and parsing
  4. now stores the meta info into a new hash into the collector for file
  5. 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

  1. did-open! only opens racket:text% that collects certain usage like formatting, etc
  2. prefetching data when workspace ready(related to support "workspace/willRenameFiles" request #74)

However, threading will not help, other solutions also have their own problem

  1. racket/place is too big(basically is a system thread size on a UNIX-like system), in this case, per file per thread is a bad idea
  2. racket/future would 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants