Skip to content

Commit

Permalink
Store model text in memory
Browse files Browse the repository at this point in the history
This is primarily a refactor of SmithyProject to store raw model
text in memory. Previously, we only stored file objects for the
model, and gave those to the model assembler. There are two issues
with this approach:
1. While a file is being editted, the source of truth for the file
contents should be what the client sends back to the server in the
`didChange` event, not whats actually in the file. To get around
this, we've been using a temporary file that stores the contents
of the file being editted, and giving that to the model assembler.
When publishing diagnostics however, we needed to re-map the file
location from the temporary file to the actual file on disk.
2. The language server needs literal text to provide some of its
features, meaning we need to read in files frequently.

These changes update SmithyProject to store a map of URI -> String
for each of the model files in the loaded model by walking the
shapes and collecting all unique file locations. SmithyTDS is
updated to use that when it needs to have literal text of the
model for formatting, version diagnostics, and other features.

Various other updates were also made:
- Added a list of errors to SmithyProject that store any errors
that occur while loading the project. Previously, any "load"
methods would return `Either<Exception, SmithyProject>`, which
isn't very ergonomic to use. These errors represent failures
in the project loading, not validation errors from loading
the model.
- SmithyProject's loading methods are reworked to provide
2 static methods: one for loading the project in a directory,
one for loading from specific smithy-build config, and 2
instance methods: one for regular reloading, one for reloading
with specific file changes. Previously, we had to manage the
loading of the temporary file (or its removal). This also
moves all the loading logic into SmithyProject.
- String-literal uris are replaced with URI class since LSP
guarantees uris will be valid (see https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#uri).
- SmithyInterface has new method to load from text-literal
sources.
- Completions updated to handle invalid model result, so callers
don't have to. This allows removing `getCompletions` from
SmithyProject.
- Various access modifiers adjusted to be more strict, tightening
the API to make it easier for us to change implementations.

The following test updates were made:
- Added multiple test cases for different project loading & reloading
situations.
- Some tests needed to use URI class instead of uri strings.
  • Loading branch information
milesziemer committed Sep 1, 2023
1 parent 067fcc9 commit e7483ab
Show file tree
Hide file tree
Showing 13 changed files with 624 additions and 485 deletions.
43 changes: 36 additions & 7 deletions src/main/java/software/amazon/smithy/lsp/SmithyInterface.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Collection;
import java.util.Map;
import org.eclipse.lsp4j.jsonrpc.messages.Either;
import software.amazon.smithy.lsp.ext.LspLog;
import software.amazon.smithy.model.Model;
Expand All @@ -43,13 +44,7 @@ private SmithyInterface() {
public static Either<Exception, ValidatedResult<Model>> readModel(Collection<File> files,
Collection<File> externalJars) {
try {
URL[] urls = externalJars.stream().map(SmithyInterface::fileToUrl).toArray(URL[]::new);
URLClassLoader urlClassLoader = new URLClassLoader(urls);
ModelAssembler assembler = Model.assembler(urlClassLoader)
.discoverModels(urlClassLoader)
// We don't want the model to be broken when there are unknown traits,
// because that will essentially disable language server features.
.putProperty(ModelAssembler.ALLOW_UNKNOWN_TRAITS, true);
ModelAssembler assembler = getModelAssembler(externalJars);

for (File file : files) {
assembler.addImport(file.getAbsolutePath());
Expand All @@ -62,6 +57,40 @@ public static Either<Exception, ValidatedResult<Model>> readModel(Collection<Fil
}
}

/**
* Reads in the specified model files, adding external jars to model builder.
*
* @param sources Map of model file URIs to their contents
* @param externalJars set of external jars
* @return either an exception encountered during model building, or the result
* of model building
*/
public static Either<Exception, ValidatedResult<Model>> readModel(
Map<String, String> sources,
Collection<File> externalJars
) {
try {
ModelAssembler assembler = getModelAssembler(externalJars);
for (String uri : sources.keySet()) {
assembler.addUnparsedModel(uri, sources.get(uri));
}
return Either.forRight(assembler.assemble());
} catch (Exception e) {
LspLog.println(e);
return Either.forLeft(e);
}
}

private static ModelAssembler getModelAssembler(Collection<File> externalJars) {
URL[] urls = externalJars.stream().map(SmithyInterface::fileToUrl).toArray(URL[]::new);
URLClassLoader urlClassLoader = new URLClassLoader(urls);
return Model.assembler(urlClassLoader)
.discoverModels(urlClassLoader)
// We don't want the model to be broken when there are unknown traits,
// because that will essentially disable language server features.
.putProperty(ModelAssembler.ALLOW_UNKNOWN_TRAITS, true);
}

private static URL fileToUrl(File file) {
try {
return file.toURI().toURL();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,15 +124,7 @@ public WorkspaceService getWorkspaceService() {

@Override
public TextDocumentService getTextDocumentService() {
File temp = null;
try {
temp = Files.createTempDirectory("smithy-lsp").toFile();
LspLog.println("Created a temporary folder for file contents " + temp);
temp.deleteOnExit();
} catch (IOException e) {
LspLog.println("Failed to create a temporary folder " + e);
}
SmithyTextDocumentService local = new SmithyTextDocumentService(this.client, temp);
SmithyTextDocumentService local = new SmithyTextDocumentService(this.client);
tds = Optional.of(local);
return local;
}
Expand Down
Loading

0 comments on commit e7483ab

Please sign in to comment.