diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleLanguageServer.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleLanguageServer.java index e344bb2ac8..21569701d8 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleLanguageServer.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleLanguageServer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016, 2023 VMware Inc. + * Copyright (c) 2016, 2024 VMware Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -111,6 +111,7 @@ import org.springframework.ide.vscode.commons.util.AsyncRunner; import org.springframework.ide.vscode.commons.util.BadLocationException; import org.springframework.ide.vscode.commons.util.CollectionUtil; +import org.springframework.ide.vscode.commons.util.text.LazyTextDocument; import org.springframework.ide.vscode.commons.util.text.TextDocument; import com.google.common.collect.ImmutableList; @@ -760,8 +761,15 @@ public void validateWith(TextDocumentIdentifier docId, IReconcileEngine engine) TextDocument doc = documents.getLatestSnapshot(docId.getUri()); if (doc == null) { - //Do not bother reconciling if document doesn't exist anymore (got closed in the meantime) - return; + // If document doesn't exist anymore it likely got closed in the meantime. Still needs validation. + LanguageComputer languageDetector = appContext.getBean(LanguageComputer.class); + if (languageDetector != null) { + doc = new LazyTextDocument(uri.toASCIIString(), languageDetector.computeLanguage(uri)); + } else { + // Cannot determine the language? Give up. + log.warn("Cannot determine the language for document: " + uri); + return; + } } if (testListener != null) { diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleTextDocumentService.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleTextDocumentService.java index 02e265d374..52b1e348f1 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleTextDocumentService.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleTextDocumentService.java @@ -640,6 +640,7 @@ public void didSave(DidSaveTextDocumentParams params) { if (url != null) { TextDocument doc = getLatestSnapshot(url); if (doc != null) { + doc.saved(); for (Consumer l : documentSaveListeners) { l.accept(new TextDocumentSaveChange(doc)); } diff --git a/headless-services/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/text/LazyTextDocument.java b/headless-services/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/text/LazyTextDocument.java index 224c034729..eaf55e086f 100644 --- a/headless-services/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/text/LazyTextDocument.java +++ b/headless-services/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/text/LazyTextDocument.java @@ -29,7 +29,7 @@ public LazyTextDocument(String uri, LanguageId languageId, Supplier load } public LazyTextDocument(String uri, LanguageId languageId) { - this(uri, LanguageId.JAVA, () -> { + this(uri, languageId, () -> { try { InputStream stream = URI.create(uri).toURL().openStream(); return IOUtil.toString(stream); diff --git a/headless-services/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/text/TextDocument.java b/headless-services/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/text/TextDocument.java index 2403a5dc71..8468ab3a54 100644 --- a/headless-services/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/text/TextDocument.java +++ b/headless-services/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/text/TextDocument.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016, 2021 Pivotal, Inc. + * Copyright (c) 2016, 2024 Pivotal, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -37,6 +37,7 @@ public class TextDocument implements IDocument { private final String uri; private Text text = new Text(""); private int version; + private boolean changedSinceLastSave = false; public TextDocument(String uri, LanguageId languageId) { this(uri, languageId, 0, ""); @@ -48,6 +49,7 @@ private TextDocument(TextDocument other) { this.text = other.text; this.lineTracker.set(text.toString()); this.version = other.version; + this.changedSinceLastSave = other.changedSinceLastSave; } public TextDocument(String uri, LanguageId languageId, int version, String text) { @@ -95,6 +97,7 @@ public synchronized void apply(DidChangeTextDocumentParams params) throws BadLoc apply(change); } this.version = newVersion; + this.changedSinceLastSave = true; } else { log.warn("Change event with bad version ignored"); } @@ -298,4 +301,12 @@ public TextDocumentIdentifier getId() { } return null; } + + public void saved() { + this.changedSinceLastSave = false; + } + + public boolean hasChangedSinceLastSave() { + return this.changedSinceLastSave; + } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguageServerInitializer.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguageServerInitializer.java index 64d15da6aa..f733918447 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguageServerInitializer.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguageServerInitializer.java @@ -190,7 +190,16 @@ private void startListening() { TextDocument doc = params.getDocument(); server.validateWith(doc.getId(), reconcileEngine); }); - + server.getTextDocumentService().onDidClose(doc -> { + if (doc.hasChangedSinceLastSave()) { + /* + * If doc is changed since last save closing it would ignore the latest changes. + * Therefore the file requires to be validated again. + */ + server.validateWith(doc.getId(), reconcileEngine); + } + + }); // ServerUtils.listenToClassFileChanges(server.getWorkspaceService().getFileObserver(), projectFinder, project -> validateAll(components, server, project)); }); config.addListener(evt -> {