-
Notifications
You must be signed in to change notification settings - Fork 22
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
Determine end of definition location #35
Determine end of definition location #35
Conversation
src/main/java/software/amazon/smithy/lsp/ext/SmithyProject.java
Outdated
Show resolved
Hide resolved
src/main/java/software/amazon/smithy/lsp/ext/SmithyProject.java
Outdated
Show resolved
Hide resolved
String shapeName = shape.getId().getName(); | ||
// Members get the same shapeName as their parent structure | ||
// so we ignore them, to avoid producing a location per-member | ||
// TODO: index members somehow as well? |
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 seems useful, since apply
syntax allows for targeting a member externally. Maybe the location
map should use the ShapeId
as the key instead of the name?
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.
When finding a token in a line, SmithyTextDocumentService only returns a potential shape name. We could use the shape name to try to find the appropriate ShapeId
and then change over the location map to use the ShapeId
as the key.
try (Harness hs = Harness.create(SmithyBuildExtensions.builder().build(), modelFiles)) { | ||
Map<String, List<Location>> locations = hs.getProject().getLocations(); | ||
|
||
correctLocation(locations, "SingleLine", 4, 5); |
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.
Seems a little strange that the starts for this are the line before, worth seeing if that's necessary to work properly.
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.
Positions for LSP are zero-based, so this is currently setting the end position to the start of the next line.
I'll add logic to properly determine the line length so we can determine the actual end of a shape on a given line.
be2e5d7
to
c288641
Compare
c288641
to
16893c0
Compare
7aa59d0
to
9444923
Compare
I've not read the code so bear with me, but could use these more precise locations to actually determine the actual shape the cursor is hovering over ? |
Yes, the member's location could be used to determine its actual definition which could then allow for jumping to its target. One nice side-effect of the current naive extraction is that tokens can be pulled out of line docs and you can still jump to the definition. |
I was thinking things along the lines of :
|
0b29f1c
to
29b4070
Compare
29b4070
to
a8405e4
Compare
private static String getUri(String fileName) { | ||
return Utils.isJarFile(fileName) | ||
? Utils.toSmithyJarFile(fileName) | ||
: !fileName.startsWith("file:") ? "file:" + fileName |
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.
Consider breaking this nested ternary out for readability.
return Optional.ofNullable(matchingShapes.get(0).getKey()); | ||
} | ||
|
||
private Predicate<Map.Entry<ShapeId, Location>> filterByLocation(Position position) { |
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 seems like it should be a Predicate<Location>
instead, since it doesn't use the key at all.
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 agree this looks a bit awkward, but the key (the shapeId) is what needs to be carried forward. If I mapped to a location first, I'd lose the reference to the shapeId. I did simplify this a bit by mapping to a shapeId in the stream after filtering.
|
||
// Find the end of a member's location by first trimming trailing commas, empty lines and closing | ||
// structure braces. | ||
if (shape.getType() == ShapeType.MEMBER) { |
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.
Is it reasonable to break these branches up in to their own methods for readability?
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 broke out the non-member branch since it only updates the end marker, but the non-member branch is responsible for updating two separate markers and the end position of a member shape. I think it made readability worse for separate method to do all of that.
// Use location on target, or else default to initial shape. | ||
locations = Collections.singletonList(project.getLocations().get(target.orElse(initialShapeId.get()))); | ||
} else { | ||
// If cursor location doesn't correspond to definition, return locations of all shapes that match token. |
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.
Not sure what this comment means.
@@ -254,8 +262,30 @@ private String findToken(String path, Position p) throws IOException { | |||
public CompletableFuture<Either<List<? extends Location>, List<? extends LocationLink>>> definition( | |||
DefinitionParams params) { | |||
try { | |||
List<Location> locations; |
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 would be nice to have a description of what this is doing behaviorally.
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.
Added with an example.
Currently, the source location of a shape is used to set both the start and end positions of a location range when building the map of definition locations used by the definition provider.
This CR improves the definition locations by finding the appropriate end position of a shape. By working from the bottom of a file to the top, the real end of a shape definition can be found by ignoring the traits and comments of the shape beneath it in a file.
This also adds a
getShapeIdFromLocation
method which returns the shapeId of the shape defined at the given location within the model.With improved definition locations, clients can render more accurate definitions.
In VS Code, the Peek Definition pane currently shows the following definition for a shape:

With the improved definition location, the entire shape is highlighted:

When using the "Go to Definition" context option, the cursor still moves to the beginning of the shape. With this CR, when selecting "Go to Definition" when the cursor is already within a shape, the cursor will no longer move. Currently, the cursor moves to the beginning of the shape definition due to the definition location being a zero-length location range that precedes the actual shape definition.
This CR also cleans up the unused
reload
method in SmithyProject.By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.