1 Commits

Author SHA1 Message Date
Ruben
48e0bc5605 feat: remove Diagnostic if it has been selected 2025-06-28 10:13:59 +02:00
6 changed files with 157 additions and 120 deletions

View File

@@ -1,44 +1 @@
# Welcome to your VS Code Extension LSP-Client for Java-TX
## What's in the folder
* This folder contains all of the files necessary for your extension.
* `package.json` - this is the manifest file in which you declare your extension and command.
* The sample plugin registers a command and defines its title and command name. With this information VS Code can show the command in the command palette. It doesnt yet need to load the plugin.
* `src/extension.ts` - this is the main file where you will provide the implementation of your command.
* The file exports one function, `activate`, which is called the very first time your extension is activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`.
* We pass the function containing the implementation of the command as the second parameter to `registerCommand`.
## Get up and running straight away
* Press `F5` to open a new window with your extension loaded.
* Run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Hello World`.
* Set breakpoints in your code inside `src/extension.ts` to debug your extension.
* Find output from your extension in the debug console.
## Make changes
* You can relaunch the extension from the debug toolbar after changing code in `src/extension.ts`.
* You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes.
## Explore the API
* You can open the full set of our API when you open the file `node_modules/@types/vscode/index.d.ts`.
## Run tests
* Install the [Extension Test Runner](https://marketplace.visualstudio.com/items?itemName=ms-vscode.extension-test-runner)
* Run the "watch" task via the **Tasks: Run Task** command. Make sure this is running, or tests might not be discovered.
* Open the Testing view from the activity bar and click the Run Test" button, or use the hotkey `Ctrl/Cmd + ; A`
* See the output of the test result in the Test Results view.
* Make changes to `src/test/extension.test.ts` or create new test files inside the `test` folder.
* The provided test runner will only consider files matching the name pattern `**.test.ts`.
* You can create folders inside the `test` folder to structure your tests any way you want.
## Go further
* [Follow UX guidelines](https://code.visualstudio.com/api/ux-guidelines/overview) to create extensions that seamlessly integrate with VS Code's native interface and patterns.
* Reduce the extension size and improve the startup time by [bundling your extension](https://code.visualstudio.com/api/working-with-extensions/bundling-extension).
* [Publish your extension](https://code.visualstudio.com/api/working-with-extensions/publishing-extension) on the VS Code extension marketplace.
* Automate builds by setting up [Continuous Integration](https://code.visualstudio.com/api/working-with-extensions/continuous-integration).
* Integrate to the [report issue](https://code.visualstudio.com/api/get-started/wrapping-up#issue-reporting) flow to get issue and feature requests reported by users.

View File

@@ -1,6 +1,7 @@
package de.dhbw; package de.dhbw;
import com.google.common.base.Stopwatch; import com.google.common.base.Stopwatch;
import de.dhbw.handler.UpdatePositionHandler;
import de.dhbw.helper.CodeSnippetOptions; import de.dhbw.helper.CodeSnippetOptions;
import de.dhbw.helper.TextHelper; import de.dhbw.helper.TextHelper;
import de.dhbw.helper.TypeResolver; import de.dhbw.helper.TypeResolver;
@@ -36,7 +37,6 @@ import java.util.stream.Stream;
*/ */
public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.TextDocumentService { public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.TextDocumentService {
private static final Logger logger = LogManager.getLogger(JavaTXTextDocumentService.class); private static final Logger logger = LogManager.getLogger(JavaTXTextDocumentService.class);
LanguageClient client; LanguageClient client;
HashMap<String, List<InlayHint>> globalInlayHintMap = new HashMap<>(); HashMap<String, List<InlayHint>> globalInlayHintMap = new HashMap<>();
@@ -84,7 +84,6 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
completions.add(item); completions.add(item);
} }
return CompletableFuture.completedFuture(Either.forLeft(completions)); return CompletableFuture.completedFuture(Either.forLeft(completions));
} }
@@ -132,7 +131,6 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
public Map<LineCharPosition, String> differenceLinePos(String first, String second, int line) { public Map<LineCharPosition, String> differenceLinePos(String first, String second, int line) {
Map<LineCharPosition, String> result = new HashMap<>(); Map<LineCharPosition, String> result = new HashMap<>();
int i = 0, j = 0; int i = 0, j = 0;
int startDiff = -1; int startDiff = -1;
@@ -181,6 +179,8 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
String newText = params.getContentChanges().getFirst().getText(); String newText = params.getContentChanges().getFirst().getText();
ArrayList<String> newTextLines = new ArrayList<>(Arrays.stream(newText.split("\n")).toList()); ArrayList<String> newTextLines = new ArrayList<>(Arrays.stream(newText.split("\n")).toList());
ArrayList<Integer> offsetPerLine = new ArrayList<>(); ArrayList<Integer> offsetPerLine = new ArrayList<>();
HashMap<Integer, List<String>> textChanges = new HashMap<>(); HashMap<Integer, List<String>> textChanges = new HashMap<>();
int index = 0; int index = 0;
@@ -194,6 +194,7 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
preciseChanges.putAll(lineDiffs); preciseChanges.putAll(lineDiffs);
textChanges.put(index, difference(currentTextLines.get(index), newTextLine).stream().map(el -> el.replaceAll(" ", "")).toList()); textChanges.put(index, difference(currentTextLines.get(index), newTextLine).stream().map(el -> el.replaceAll(" ", "")).toList());
client.logMessage(new MessageParams(MessageType.Info, "For Line " + index + " difference of " + (newTextLine.length() - currentTextLines.get(index).length())));
offsetPerLine.add(newTextLine.length() - currentTextLines.get(index).length()); offsetPerLine.add(newTextLine.length() - currentTextLines.get(index).length());
} }
@@ -224,22 +225,12 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
); );
}).toList(); }).toList();
client.publishDiagnostics(new PublishDiagnosticsParams(params.getTextDocument().getUri(), diagnosticsList));
// PublishDiagnosticsParams diagnosticsParams = new PublishDiagnosticsParams(params.getTextDocument().getUri(), diagnostics);
// client.publishDiagnostics(diagnosticsParams);
List<String> combinedList = new ArrayList<>();
for (List<String> list : textChanges.values()) {
combinedList.addAll(list);
}
typeResolver.reduceCurrent(preciseChanges, variables, client); typeResolver.reduceCurrent(preciseChanges, variables, client);
//Reduce and display Typehints and Diagnostics //Reduce and display Typehints and Diagnostics
if (!currentlyCalculating) {
currentlyCalculating = true;
ArrayList<Diagnostic> diagnostics = new ArrayList<>(); ArrayList<Diagnostic> diagnostics = new ArrayList<>();
var sWatch = Stopwatch.createUnstarted(); var sWatch = Stopwatch.createUnstarted();
@@ -256,17 +247,23 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
for (var variable : typesOfMethodAndParameters) { for (var variable : typesOfMethodAndParameters) {
InlayHint inlayHint = getInlayHint(variable); InlayHint inlayHint = getInlayHint(variable);
inlayHint.getPosition().setCharacter(inlayHint.getPosition().getCharacter() + offsetPerLine.get(inlayHint.getPosition().getLine()));
typeHint.add(inlayHint); typeHint.add(inlayHint);
//Diagnostics of Types //Diagnostics of Types
for (var type : variable.getPossibleTypes()) { for (var type : variable.getPossibleTypes()) {
Diagnostic diagnostic = getDiagnostic(variable, params.getTextDocument().getUri(), type); Diagnostic diagnostic = getDiagnostic(variable, params.getTextDocument().getUri(), type);
diagnostic.getRange().getStart().setCharacter(diagnostic.getRange().getStart().getCharacter() + offsetPerLine.get(diagnostic.getRange().getStart().getLine()));
diagnostic.getRange().getEnd().setCharacter(diagnostic.getRange().getEnd().getCharacter() + offsetPerLine.get(diagnostic.getRange().getEnd().getLine()));
diagnostics.add(diagnostic); diagnostics.add(diagnostic);
} }
} }
updateGlobalMaps(diagnostics, typeHint, params.getTextDocument().getUri());
globalDiagnosticsMap.put(params.getTextDocument().getUri(), diagnostics);
globalInlayHintMap.put(params.getTextDocument().getUri(), typeHint);
// updateGlobalMaps(diagnostics, typeHint, params.getTextDocument().getUri());
} catch (Exception e) { } catch (Exception e) {
@@ -279,21 +276,6 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
sWatch.stop(); sWatch.stop();
log("[didSave] Finished Calculating in [" + sWatch.elapsed().toSeconds() + "s]", MessageType.Info); log("[didSave] Finished Calculating in [" + sWatch.elapsed().toSeconds() + "s]", MessageType.Info);
} }
}
for (var inlayHint : globalInlayHintMap.get(params.getTextDocument().getUri())) {
inlayHint.getPosition().setCharacter(inlayHint.getPosition().getCharacter() + offsetPerLine.get(inlayHint.getPosition().getLine()));
}
for (var inlayHint : globalDiagnosticsMap.get(params.getTextDocument().getUri())) {
inlayHint.getRange().getStart().setCharacter(inlayHint.getRange().getStart().getCharacter() + offsetPerLine.get(inlayHint.getRange().getStart().getLine()));
inlayHint.getRange().getEnd().setCharacter(inlayHint.getRange().getEnd().getCharacter() + offsetPerLine.get(inlayHint.getRange().getEnd().getLine()));
}
for (var textChangeLine : textChanges.entrySet()) {
log(textChangeLine.getKey() + " - " + String.join(",", textChangeLine.getValue()), MessageType.Info);
}
globalInlayHintMap.put(params.getTextDocument().getUri(), globalInlayHintMap.get(params.getTextDocument().getUri()).stream().filter(el -> { globalInlayHintMap.put(params.getTextDocument().getUri(), globalInlayHintMap.get(params.getTextDocument().getUri()).stream().filter(el -> {
//TODO: Hier das Label aufspalten an | weil die Typehints immer mit und getrennt sind und so jeder Typhint für sich durchlaufen werden kann. //TODO: Hier das Label aufspalten an | weil die Typehints immer mit und getrennt sind und so jeder Typhint für sich durchlaufen werden kann.
@@ -306,6 +288,8 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
return !textChanges.get(el.getRange().getStart().getLine()).contains(el.getMessage().replaceAll(" ", "")); return !textChanges.get(el.getRange().getStart().getLine()).contains(el.getMessage().replaceAll(" ", ""));
}).toList()); }).toList());
updateClient(client); updateClient(client);
client.publishDiagnostics(new PublishDiagnosticsParams(params.getTextDocument().getUri(), globalDiagnosticsMap.get(params.getTextDocument().getUri()))); client.publishDiagnostics(new PublishDiagnosticsParams(params.getTextDocument().getUri(), globalDiagnosticsMap.get(params.getTextDocument().getUri())));
} }

View File

@@ -0,0 +1,96 @@
package de.dhbw.handler;
import de.dhbw.model.LSPVariable;
import de.dhbwstuttgart.syntaxtree.SourceFile;
import org.eclipse.lsp4j.Diagnostic;
import org.eclipse.lsp4j.InlayHint;
import org.eclipse.lsp4j.Position;
import org.eclipse.lsp4j.Range;
import java.util.ArrayList;
import java.util.List;
public class UpdatePositionHandler {
public static List<InlayHint> adjustInlayHintPositions(List<InlayHint> oldHints, List<String> newTextLines) {
List<InlayHint> adjusted = new ArrayList<>();
for (InlayHint hint : oldHints) {
Position oldPos = hint.getPosition();
int oldLine = oldPos.getLine();
String variableName = extractVariableNameFromHint(hint); // z.B. durch .getLabel()
int searchStart = Math.max(0, oldLine - 3);
int searchEnd = Math.min(newTextLines.size(), oldLine + 3);
boolean found = false;
for (int i = searchStart; i < searchEnd; i++) {
String lineText = newTextLines.get(i);
int column = lineText.indexOf(variableName);
if (column >= 0) {
Position newPos = new Position(i, column + variableName.length());
InlayHint adjustedHint = new InlayHint(newPos, hint.getLabel());
adjustedHint.setKind(hint.getKind());
adjustedHint.setPaddingLeft(false);
adjustedHint.setPaddingRight(true);
adjusted.add(adjustedHint);
found = true;
break;
}
}
if (!found) {
adjusted.add(hint); // fallback: alte Position beibehalten
}
}
return adjusted;
}
private static String extractVariableNameFromHint(InlayHint hint) {
// Beispiel: wenn dein Hint-Label z.B. "String ↤" ist, brauchst du Logik, um den Namen zu bestimmen
// Wenn du nur Typen zeigst, kannst du Position - Name aus anderer Quelle kombinieren
// Temporär: nutze z.B. eine Custom-Property
return hint.getLabel().getLeft(); // Pseudocode, je nach Labelstruktur anpassen
}
public static List<Diagnostic> adjustDiagnosticPositions(List<Diagnostic> oldDiagnostics, List<String> newTextLines) {
List<Diagnostic> adjusted = new ArrayList<>();
for (Diagnostic diag : oldDiagnostics) {
String keyword = extractKeywordFromDiagnostic(diag); // z.B. "inferred type"
int oldLine = diag.getRange().getStart().getLine();
int searchStart = Math.max(0, oldLine - 3);
int searchEnd = Math.min(newTextLines.size(), oldLine + 3);
boolean found = false;
for (int i = searchStart; i < searchEnd; i++) {
String lineText = newTextLines.get(i);
int col = lineText.indexOf(keyword);
if (col >= 0) {
Range newRange = new Range(new Position(i, col), new Position(i, col + keyword.length()));
Diagnostic adjustedDiag = new Diagnostic(newRange, diag.getMessage(), diag.getSeverity(), diag.getCode().getLeft(), diag.getSource());
adjusted.add(adjustedDiag);
found = true;
break;
}
}
if (!found) {
adjusted.add(diag); // fallback
}
}
return adjusted;
}
private static String extractKeywordFromDiagnostic(Diagnostic diag) {
// z.B. mit Regex oder fixer Konvention aus message
return "type"; // Beispiel
}
}

View File

@@ -29,7 +29,6 @@ public class TextHelper {
for (int i = startChar; i < linesInChar.length; i++) { for (int i = startChar; i < linesInChar.length; i++) {
if(linesInChar[i].contains("{")){ if(linesInChar[i].contains("{")){
index = i; index = i;
found = true; found = true;
@@ -75,7 +74,6 @@ public class TextHelper {
} }
} }
return index-1; return index-1;
} }

View File

@@ -33,6 +33,8 @@ public class TypeResolver {
private static final Logger logger = LogManager.getLogger(TypeResolver.class); private static final Logger logger = LogManager.getLogger(TypeResolver.class);
private List<LSPVariable> currentTypes = new ArrayList<>();
private final boolean ENABLE_GENERICS = false; private final boolean ENABLE_GENERICS = false;
private LanguageServerTransferObject current; private LanguageServerTransferObject current;
@@ -62,19 +64,8 @@ public class TypeResolver {
public TypeResolver() { public TypeResolver() {
} }
public void updatePositions(String path, String input){
private LanguageServerTransferObject getCacheOrCalculate(String input, String path) throws IOException, ClassNotFoundException, URISyntaxException { LanguageServerTransferObject obj = new LanguageServerInterface().getResultSetAndAbstractSyntax(path, input);
logger.info("Trying to find cached Compiler-Answer for input with key [" + input.hashCode() + "].");
LanguageServerInterface languageServer = new LanguageServerInterface();
if (dataCache.containsKey(input.hashCode())) {
logger.info("Found Cache for the Input with key [" + input.hashCode() + "].");
return dataCache.get(input.hashCode());
} else {
logger.info("Could not find Cache for Input with key [" + input.hashCode() + "]. Using Compiler Interface and Saving the Answer in Cache.");
var transferObject = languageServer.getResultSetAndAbstractSyntax(path, input);
dataCache.put(input.hashCode(), transferObject);
return transferObject;
}
} }
public boolean isTypeImported(String input, String type) { public boolean isTypeImported(String input, String type) {
@@ -288,10 +279,21 @@ public class TypeResolver {
} }
} }
currentTypes.addAll(methodsWithParametersLSPVariableList);
return methodsWithParametersLSPVariableList; return methodsWithParametersLSPVariableList;
} }
public void updateTypehints(String input, String path) throws IOException, URISyntaxException, ClassNotFoundException {
LanguageServerTransferObject transferObj;
LanguageServerInterface languageServer = new LanguageServerInterface();
transferObj = languageServer.getResultSetAndAbstractSyntax(path, input);
var ast = transferObj.getAst();
}
public void reduceCurrent(HashMap<LineCharPosition, String> combinedList, List<LSPVariable> variables, LanguageClient client) { public void reduceCurrent(HashMap<LineCharPosition, String> combinedList, List<LSPVariable> variables, LanguageClient client) {
client.logMessage(new MessageParams(MessageType.Info, "Lenght is: " + combinedList.size())); client.logMessage(new MessageParams(MessageType.Info, "Lenght is: " + combinedList.size()));
for (var lines : combinedList.entrySet()) { for (var lines : combinedList.entrySet()) {