openlawlibrary/pygls

How to make `cmd` + `click` switch between `Go to definition` and `Go to reference`? (VSCode only)

Opened this issue · 3 comments

Context:
microsoft/vscode#73081 (comment)

In the Python extension, Cmd + Click trigger Go to Definition or Go to reference depending if the click is on a declaration or reference.

I have this pseudocode and it doesn't seem to trigger the action correctly. p.s. the language server is working properly, the example is simplified.

@LSP_SERVER.feature(TEXT_DOCUMENT_DEFINITION)
def definition(
    ls, params: TextDocumentPositionParams
):
   uri = params.text_document.uri
   pos = params.position
   curr_pos =  Position(line= pos.line, character=pos.character)
   return Location(uri = uri, range = Location (Range(start=curr_pos, end=curr_pos))

alternatively, I have tried:

@LSP_SERVER.feature(TEXT_DOCUMENT_DEFINITION)
def definition(ls, params):
  return params

p.s. I am not so sure What's the difference between TextDocumentPositionParams and a Location

I am not so sure What's the difference between TextDocumentPositionParams and a Location

The main difference is that TextDocumentPositionParams contains a Position and therefore describes a single location within the document e.g. where the cursor is. Whereas Location contains a Range which describes a region of text within the document e.g. the text you highlight just before you copy it.

I have this pseudocode and it doesn't seem to trigger the action correctly.

I think you are close, though you have an extra Location in your return statement, something like the following should work

return Location(uri=uri, range=Range(start=curr_pos, end=curr_pos))

Though I'm not sure how VSCode handles a zero-length range, it might not be obvious that it did anything, you may also want to try something like this

return Location(
    uri=uri, 
    range=Range(
        start=Position(line=pos.line, character=0), 
        end=Position(line=pos.line + 1, character=0)
    )
)

Now when you trigger Goto Definition, VSCode should highlight the whole line

In the Python extension, Cmd + Click trigger Go to Definition or Go to reference depending if the click is on a declaration or reference.

Unfortunately, I don't know for sure how to make this work - the LSP spec tries hard not to dictate how the UI for each method should work. The server provides the data and it's up to the client to decide how to show it.

However, I would start by also implementing TEXT_DOCUMENT_REFERENCES to return two Locations, one being the definition itself, the other being some other location in the document and see how VSCode handles it.

Hope that helps!

2024-05-07_12-53-11 (1)

return Location(uri=uri, range=Range(start=curr_pos, end=curr_pos)), I think my previous implementation has a bug as you have noticed. Once I return the current cursor it seems to behave as I expected.

Thanks a lot for the help! This issue can be closed

Unfortunately, I don't know for sure how to make this work - the LSP spec tries hard not to dictate how the UI for each method should work. The server provides the data and it's up to the client to decide how to show it.

You are correct that this is up to the client. I asked because

fyi - I have pushed a commit that adds settings like editor.gotoLocation.alternativeDefinitionCommand etc. They allow to define what happens when the corresponding go-to-command navigates to the current location microsoft/vscode#73081 (comment)

It's not clear to me whether "current location" is Location or if I can return an exact position like TextDocumentPositionParams. Is it possible if my LSP return TextDocumentPositionParams instead of Location? I assume ultimately they all get converted to a standard format (JSON like I assume)

I assume ultimately they all get converted to a standard format (JSON like I assume)

Everything in LSP is JSON under the hood, types like Location are just names given to a well defined JSON object with a specific structure

or if I can return an exact position like TextDocumentPositionParams.

As a general rule anything with Params in the name can't be sent as a response to a request.

The LSP specification itself is probably the best place to look for answers to questions like "what can I return here?"
Admittedly, it's not the easiest document to navigate, but the information is there. Taking your
Goto Definition request as an example, if you scroll down to just before the Goto Type Definition Request heading, you should see a Response section.

Under it the spec lists the valid responses to the request separated by | characters

result: Location | Location[] | LocationLink[] | null