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

A vision for consistent static vs dynamic registration #583

Open
michaelpj opened this issue May 25, 2024 · 1 comment
Open

A vision for consistent static vs dynamic registration #583

michaelpj opened this issue May 25, 2024 · 1 comment
Labels
v3 Next really big release

Comments

@michaelpj
Copy link
Collaborator

At the moment static versus dynamic registration works quite differently.

Specifically:

  • When you register a method dynamically, you have to provide the RegistrationOptions
  • When you register a method statically, you don't have to provide the ServerCapability (from Mappings for capabilities #581)
    • Instead, we try to infer the appropriate capability. See inferServerCapabilities
    • But, this requires a bunch of choices that we can't guess! So we put in a side channel in the form of Options, which basically lets us pass in things that need to go in the capabilities.

I think we could unify these. Specifically, I think we should make the user provide the capability in both cases. That means that we don't need to pass the extra information out-of-band in Options, instead the user can just set things in the capability directly.

Of course, we probably want a way to provide a sensible default capability... but we also want this for the dynamically registered capabilities! So we should try and provide this for everything.

The main complication is that for both static and dynamic registration we may need to register several method handlers under the same capability, and what the capability is will depend on all of them. For example:

  • textDocument/completion and completionItem/resolve. The latter is not registered separately, but is rather indicated by a field in the completion capability.
  • textDocument/semanticTokens/full and the other semantic tokens methods. Similar.

I think we can do this reasonably nicely by pretending that we can register everything independently, and then merging all the capabilities when we actually do the registration. So for example, we might have a default capability for the textDocument/completion handler that doesn't say it supports resolve, and then a capability for completionItem/resolve that says it supports resolve, and then we merge those together into the final capability that we register. I think this should work for both static and dynamic capabilities.

So I think we want something like this:

-- We might not be able to have these actually instances due to singletons stuff, but morally we want them
instance Semigroup (ServerCapability m)
instance Semigroup (ClientCapability m)
instance Semigroup (RegistrationOptions m)

type StaticRegistration m = (Handler m, ServerCapability m)
type DynamicRegistration m = (Handler m, RegistrationOptions m)

We probably also need the server definition to tell us its static registrations as part of the initialize handler instead of beforehand. This is necessary anyway, since you might need to decide whether to use static or dynamic registration depending on the client's capabilities.

(It would also be nice if we could provide a relatively simple way to have a handler that is either statically or dynamically registered depending on whether the client supports dynamic registration...)

@michaelpj
Copy link
Collaborator Author

The story for clients who want to use dynamic registration will then probably look something like defining a config change handler which will a) check which things should be enabled, b) adjust registrations to match.

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

No branches or pull requests

1 participant