-
Notifications
You must be signed in to change notification settings - Fork 275
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
Add LSP server #2662
Add LSP server #2662
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking really good!
I can't comment, but why is there a protovalidate.zip
checked in?
private/buf/buflsp/buflsp.go
Outdated
wellKnownTypesDescriptorProtoPath = normalpath.Join("google", "protobuf", "descriptor.proto") | ||
// v3WellKnownTypesCacheRelDirPath is the relative path to the cache directory for materialized | ||
// well-known types .proto files. | ||
v3WellKnownTypesCacheRelDirPath = normalpath.Join("v3", "wkt") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I talked to @Alfus about this, but this implies it's the same cache directory as the module cache - is that correct? If so, this should be in a different location - buf lsp
should not modify the module cache. We could have $BUF_CACHE_DIR/lsp/wkt/WKT_VERSION
as an example
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Putting the version there as a subdirectory seems like a good idea, though I don't see an obvious version in the generated datawkt package. Digest can easily work if that's sufficient/reasonable, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(For now I've addressed this by adding the digest of the wkt module into the resulting path.)
It's a terrible hack. Since we can't fetch modules yet due to missing APIs, the test literally pulls the zip as file data into an omni provider. Obviously, it would be better to get rid of this. Any opinion on how? I think the most obvious paths forward are:
|
I would just check in protovalidate as individual files, not as a zip file - we do this in other places too, theres not many files. ie just explode the zip file into its constituent files and check those in. |
Works for me, fixed. |
Do let me know if there's any more work you think I should take a look at on this. For now, I'm at a bit of a stopping point as everything I'm able to test seems to work as expected and I think most of the low hanging fruit for cleaning up the code to Buf's standards/style are taken care of. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leaving code organization alone for now, but some structural questions. I believe most of these are for @Alfus and not @jchadwick-buf but both feel free to chime in here.
if err != nil { | ||
return nil, err | ||
} | ||
omniProvider, err := bufmoduletesting.NewOmniProvider( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're providing protovalidate via this OmniProvider
, why do we still need to depend on it via a BSR dependency in buftest
? Is there some functionality under the hood we are testing? It's not immediately apparent to me that, if the *server
is using the controller
, which itself is just depending on the ModuleKeyProvider/ModuleDataProvider
given via OmniProvider
, why we also need to have a hard dependency on buf.build
here.
If not, we could get rid of buftest
entirely, and move all the lsp testing code into testdata
local to this package.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, SGTM. Now buftest
is no more, and I've reverted the changes made to the proto directory as well.
private/buf/buflsp/buflsp.go
Outdated
if entry, ok := buflsp.fileCache[event.Name]; ok { | ||
if entry.moduleSet != nil { | ||
if err := buflsp.refreshImage(context.Background(), entry.moduleSet, entry.bucket); err != nil { | ||
buflsp.logger.Sugar().Errorf("refreshImage error: %s", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will be displayed to users, we should make sure this error is meaningful, which I don't think it is if we are referencing an internal method refreshImage
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How should errors that have no one to report them to be handled in general? This can probably just be removed
private/buf/buflsp/buflsp.go
Outdated
var err error | ||
workspace, err := s.controller.GetWorkspace(ctx, params.TextDocument.URI.Filename()) | ||
if err != nil { | ||
s.logger.Warn("could not determine workspace", zap.Error(err)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will be displayed to the user, same comment above.
private/buf/buflsp/buflsp.go
Outdated
} | ||
|
||
// Create a new file entry for the file | ||
entry, err := s.createFileEntry(ctx, params.TextDocument, moduleSet) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moduleSet
can be nil, are we making sure that createFileEntry
is documented that one of its parameters may be nil?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've eliminated the intentionally-nil module set pointers.
private/buf/buflsp/buflsp.go
Outdated
bucket = s.wellKnownTypesBucket | ||
file, err = bucket.GetFile(ctx, path) | ||
if err != nil { | ||
s.logger.Warn("could not resolve import", zap.String("path", path)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why aren't we returning this error? We generally never want to using logging as a means of error propagation unless absolutely necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is going to be necessary to swallow some errors at some point because the LSP should provide some functionality even when the source code is partially broken, since the LSP will necessarily see source code as it is being typed. In this case, it doesn't actually matter since we bail out earlier in processText anyway, so there's really no point in swallowing this error, so now it does not do that.
private/buf/buflsp/buflsp.go
Outdated
workspace, err := s.controller.GetWorkspace(ctx, params.TextDocument.URI.Filename()) | ||
if err != nil { | ||
s.logger.Warn("could not determine workspace", zap.Error(err)) | ||
// Continue anyways if this fails. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe the reason for this is that we can still provide useful features even if we can't get a workspace.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The previous statement (that we still provide useful features even without a workspace) is still true, but this hack is no longer necessary as I've deferred workspace resolution until later, so we don't need to swallow this error here anymore.
Pushed this work to https://github.com/bufbuild/buf/tree/do-not-delete-buf-lsp-merge for long-term storage for now. We talked offline and agreed we need to rework this, which we hope to pick up relatively soon. Closing this PR as it is. |
I'd love to see the LSP released someday 🚀 |
Hey! I wonder if there are any updates here? Buf is the de-facto standard for proto generation for many teams, and it would be nice to have a compatible lsp as well. There are other solutions available, but they usually lack maintenance and features. Anyway, it would be awesome if this would be revived C: |
We're reviving this and working on it soon, cc @mcy |
Is there a place to follow the progress on the server? |
The first version of the LSP is already released: #3316. I guess you can follow the PRs in this repo to see the progress |
Passes tests and seems to work so far, unimplemented APIs aside. Source code is partially reorganized to try to be a bit closer to the rest of Buf, but there's plenty that could still be done. We'll probably need to work out how much of that should block.
P.S.: I think the path handling will need to be cleaned up for Windows to work fully. Have yet to test this.