From 678a343075a95a3d734b6c91b7299fa2378749e7 Mon Sep 17 00:00:00 2001 From: azerr Date: Wed, 23 Jul 2025 21:15:47 +0200 Subject: [PATCH 001/264] fix: DAP environment variables do not appear to persist Fixes #1114 Signed-off-by: azerr --- .../configurations/DAPRunConfiguration.java | 33 ++++++++++++++++--- .../DAPRunConfigurationOptions.java | 13 ++++---- .../dap/configurations/DAPSettingsEditor.java | 2 ++ .../settings/ui/DebugAdapterServerPanel.java | 20 +++++++++-- .../settings/ui/DebugAdapterServerView.java | 8 ++--- .../ui/NewDebugAdapterServerDialog.java | 4 +-- 6 files changed, 60 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfiguration.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfiguration.java index 6791a286f..443d3b004 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfiguration.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfiguration.java @@ -11,10 +11,12 @@ package com.redhat.devtools.lsp4ij.dap.configurations; import com.intellij.execution.Executor; +import com.intellij.execution.configuration.EnvironmentVariablesData; import com.intellij.execution.configurations.*; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.openapi.options.SettingsEditor; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.vfs.VirtualFile; import com.redhat.devtools.lsp4ij.dap.DebugMode; import com.redhat.devtools.lsp4ij.dap.DebugServerWaitStrategy; @@ -25,8 +27,9 @@ import com.redhat.devtools.lsp4ij.dap.descriptors.DebugAdapterDescriptorFactory; import com.redhat.devtools.lsp4ij.dap.descriptors.DefaultDebugAdapterDescriptor; import com.redhat.devtools.lsp4ij.internal.StringUtils; -import com.redhat.devtools.lsp4ij.templates.ServerMappingSettings; import com.redhat.devtools.lsp4ij.settings.ServerTrace; +import com.redhat.devtools.lsp4ij.templates.ServerMappingSettings; +import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -39,6 +42,8 @@ public class DAPRunConfiguration extends RunConfigurationBase userEnvironmentVariables = this.debugAdapterServerPanel.getEnvironmentVariables().getEnvs(); - boolean includeSystemEnvironmentVariables = this.debugAdapterServerPanel.getEnvironmentVariables().isPassParentEnvs(); + Map userEnvironmentVariables = this.debugAdapterServerPanel.getEnvData().getEnvs(); + boolean includeSystemEnvironmentVariables = this.debugAdapterServerPanel.getEnvData().isPassParentEnvs(); String commandLine = this.debugAdapterServerPanel.getCommandLine(); int connectTimeout = this.debugAdapterServerPanel.getDebugServerWaitStrategyPanel().getConnectTimeout(); String trackTrace = this.debugAdapterServerPanel.getDebugServerWaitStrategyPanel().getTrace(); From 96d47918fe64ce7685a7dee741480ebf5259e5f6 Mon Sep 17 00:00:00 2001 From: azerr Date: Thu, 24 Jul 2025 15:43:22 +0200 Subject: [PATCH 002/264] feat: improve DAP completions Signed-off-by: azerr --- .../features/LSPCompletionProposal.java | 55 +----- .../completion/DAPCompletionProcessor.java | 7 +- .../completion/DAPLookupElementDecorator.java | 173 ++++++++++++------ .../lsp4ij/internal/CompletionUtils.java | 68 +++++++ 4 files changed, 195 insertions(+), 108 deletions(-) create mode 100644 src/main/java/com/redhat/devtools/lsp4ij/internal/CompletionUtils.java diff --git a/src/main/java/com/redhat/devtools/lsp4ij/client/features/LSPCompletionProposal.java b/src/main/java/com/redhat/devtools/lsp4ij/client/features/LSPCompletionProposal.java index da5b9cdc4..faaed0a62 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/client/features/LSPCompletionProposal.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/client/features/LSPCompletionProposal.java @@ -63,6 +63,7 @@ import static com.redhat.devtools.lsp4ij.features.documentation.LSPDocumentationHelper.getValidMarkupContents; import static com.redhat.devtools.lsp4ij.internal.CompletableFutures.isDoneNormally; import static com.redhat.devtools.lsp4ij.internal.CompletableFutures.waitUntilDone; +import static com.redhat.devtools.lsp4ij.internal.CompletionUtils.computePrefixStartFromInsertText; /** * LSP completion lookup element. @@ -539,11 +540,8 @@ private int getPrefixStartOffset(@NotNull Document document, int completionOffse // case 2: text edit is undefined, try to compute the prefix start offset by using insertText String insertText = getInsertText(); - Integer prefixStartOffset = computePrefixStartFromInsertText(document, completionOffset, insertText); - if (prefixStartOffset != null) { - return prefixStartOffset; - } - return completionOffset; + Integer prefixStartOffset = computePrefixStartFromInsertText(document, file, completionOffset, insertText); + return Objects.requireNonNullElse(prefixStartOffset, completionOffset); } @@ -562,53 +560,6 @@ private static int getPrefixStartOffsetFromTextEdit(@NotNull Document document, return LSPIJUtils.toOffset(textEdit.getRight().getInsert().getStart(), document); } - @Nullable - private Integer computePrefixStartFromInsertText(@NotNull Document document, - int completionOffset, - String insertText) { - - // case 2.1: first strategy, we collect word range at - // ex : - // insertText= '(let [${1:binding} ${2:value}])' - // document= le - // we have to return |le as prefix start offset - - TextRange wordRange = LSPIJUtils.getWordRangeAt(document, file, completionOffset); - if (wordRange != null) { - return wordRange.getStartOffset(); - } - - // case 2.2: second strategy, we check if the left content of the completion offset - // matches the full insertText left content - // ex : - // insertText= 'foo.bar' - // document= {foo.b|} - // we have to return {| as prefix start offset - - Integer prefixStartOffset = getPrefixStartOffsetWhichMatchesLeftContent(document, completionOffset, insertText); - if (prefixStartOffset != null) { - return prefixStartOffset; - } - - return null; - } - - @Nullable - private static Integer getPrefixStartOffsetWhichMatchesLeftContent(@NotNull Document document, - int completionOffset, - @NotNull String insertText) { - int startOffset = Math.max(0, completionOffset - insertText.length()); - int endOffset = startOffset + Math.min(insertText.length(), completionOffset); - String subDoc = document.getText(new TextRange(startOffset, endOffset)); // "".ch - for (int i = 0; i < insertText.length() && i < completionOffset; i++) { - String tentativeCommonString = subDoc.substring(i); - if (insertText.startsWith(tentativeCommonString)) { - return completionOffset - tentativeCommonString.length(); - } - } - return null; - } - @Override public @Nullable LSPCompletionProposal dereference() { diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/completion/DAPCompletionProcessor.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/completion/DAPCompletionProcessor.java index 8ab7bf3cb..a1a122814 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/completion/DAPCompletionProcessor.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/completion/DAPCompletionProcessor.java @@ -108,6 +108,7 @@ public void fillCompletionVariants(@NotNull CompletionParameters parameters, Arrays.sort(items, new DAPCompletionItemComparator(prefixMatcher, currentWord, caseSensitive)); int size = items.length; + int completionOffset = parameters.getOffset(); // Items now sorted by priority, low index == high priority for (int i = 0; i < size; i++) { var item = items[i]; @@ -115,8 +116,9 @@ public void fillCompletionVariants(@NotNull CompletionParameters parameters, LookupElement lookupElement = createLookupElement(parameters, item); if (lookupElement != null) { + lookupElement.putUserData(CodeCompletionHandlerBase.DIRECT_INSERTION, true); int priority = size - i; - var prioritizedLookupItem = PrioritizedLookupElement.withPriority(new DAPLookupElementDecorator(lookupElement, item), priority); + var prioritizedLookupItem = PrioritizedLookupElement.withPriority(new DAPLookupElementDecorator(lookupElement, item, completionOffset), priority); result.addElement(prioritizedLookupItem); } } @@ -130,6 +132,9 @@ public void fillCompletionVariants(@NotNull CompletionParameters parameters, private LookupElement createLookupElement(@NotNull CompletionParameters parameters, @NotNull CompletionItem item) { String label = item.getLabel(); + if (StringUtils.isBlank(label)) { + return null; + } String insertText = label; if (StringUtils.isNotBlank(item.getText())) { insertText = item.getText(); diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/completion/DAPLookupElementDecorator.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/completion/DAPLookupElementDecorator.java index 397bc02cc..38cced389 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/completion/DAPLookupElementDecorator.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/completion/DAPLookupElementDecorator.java @@ -10,16 +10,24 @@ ******************************************************************************/ package com.redhat.devtools.lsp4ij.dap.completion; +import com.intellij.codeInsight.completion.CompletionInitializationContext; +import com.intellij.codeInsight.completion.InsertionContext; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementDecorator; import com.intellij.codeInsight.lookup.LookupElementPresentation; import com.intellij.icons.AllIcons; +import com.intellij.openapi.application.WriteAction; +import com.intellij.openapi.editor.Document; +import com.redhat.devtools.lsp4ij.internal.StringUtils; import org.eclipse.lsp4j.debug.CompletionItem; import org.eclipse.lsp4j.debug.CompletionItemType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import java.util.Objects; + +import static com.redhat.devtools.lsp4ij.internal.CompletionUtils.computePrefixStartFromInsertText; /** * Debug Adapter Protocol (DAP) lookup element decorator. @@ -27,11 +35,14 @@ public class DAPLookupElementDecorator extends LookupElementDecorator { private final @NotNull CompletionItem item; + private final int completionOffset; protected DAPLookupElementDecorator(@NotNull LookupElement delegate, - @NotNull CompletionItem item) { + @NotNull CompletionItem item, + int completionOffset) { super(delegate); this.item = item; + this.completionOffset = completionOffset; } @Override @@ -43,68 +54,120 @@ public void renderElement(@NotNull LookupElementPresentation presentation) { presentation.setTypeText(this.getTypeText(item)); presentation.setIcon(this.getIcon(item.getType())); presentation.setTypeGrayed(true); -} + } -private boolean isBold(@NotNull CompletionItem item) { - return false; -} + @Override + public void handleInsert(@NotNull InsertionContext context) { + WriteAction.run(() -> handleInsertInWriteAction(context)); + } -private boolean isStrikeout(@NotNull CompletionItem item) { - return false; -} + private void handleInsertInWriteAction(@NotNull InsertionContext context) { + var editor = context.getEditor(); + final int oldCaretOffset = editor.getCaretModel().getOffset(); + var document = context.getDocument(); -private @Nullable String getTailText(@NotNull CompletionItem item) { - return null; -} + int startOffset = getStartOffset(document); + int length = getLength(context); + int endOffset = length + startOffset; + String newText = getNewtText(); -private @Nullable String getTypeText(@NotNull CompletionItem item) { - return item.getDetail(); -} + // Update document with the new completion item text to insert + if (endOffset <= 0) { + document.insertString(startOffset, newText); + } else { + document.replaceString(startOffset, endOffset, newText); + } + + // Update caret offset / selection (if needed) + Integer selectionStart = item.getSelectionStart(); + if (selectionStart != null) { + // Update selection + selectionStart += startOffset; + Integer selectionLength = item.getSelectionLength(); + int selectionEnd = selectionStart + Objects.requireNonNullElse(selectionLength, 0); + editor.getSelectionModel().setSelection(selectionStart, selectionEnd); + + // Update caret offset + if (oldCaretOffset != selectionEnd) { + editor.getCaretModel().moveToOffset(selectionEnd); + } -private static @Nullable Icon getIcon(@Nullable CompletionItemType type) { - if (type == null) { + } else { + // No selection, update caret offset only + int newCaretOffset = editor.getCaretModel().getOffset() + newText.length() - length; + if (oldCaretOffset != newCaretOffset) { + editor.getCaretModel().moveToOffset(newCaretOffset); + } + } + } + + private int getStartOffset(@NotNull Document document) { + Integer start = item.getStart(); + if (start != null) { + return start; + } + Integer prefixStartOffset = computePrefixStartFromInsertText(document, null, completionOffset, getNewtText()); + return Objects.requireNonNullElse(prefixStartOffset, completionOffset); + } + + private int getLength(@NotNull InsertionContext context) { + int selectionEndOffset = context.getOffset(CompletionInitializationContext.SELECTION_END_OFFSET); + int endOffset = selectionEndOffset - completionOffset; + Integer length = item.getLength(); + if (length != null) { + endOffset += length; + } + return endOffset; + } + + private @NotNull String getNewtText() { + String newText = item.getText(); + if (StringUtils.isBlank(newText)) { + return item.getLabel(); + } + return newText; + } + + private boolean isBold(@NotNull CompletionItem item) { + return false; + } + + private boolean isStrikeout(@NotNull CompletionItem item) { + return false; + } + + private @Nullable String getTailText(@NotNull CompletionItem item) { return null; } - switch (type) { - case CLASS: - return AllIcons.Nodes.Class; - case CUSTOMCOLOR: - case COLOR: - return AllIcons.Nodes.EmptyNode; - case CONSTRUCTOR: - return AllIcons.Nodes.ClassInitializer; - case ENUM: - return AllIcons.Nodes.Enum; - case FIELD: - return AllIcons.Nodes.Field; - case FILE: - return AllIcons.FileTypes.Any_type; - case FUNCTION: - return AllIcons.Nodes.Function; - case INTERFACE: - return AllIcons.Nodes.Interface; - case KEYWORD: - return AllIcons.Nodes.Constant; - case METHOD: - return AllIcons.Nodes.Method; - case MODULE: - return AllIcons.Nodes.Module; - case PROPERTY: - return AllIcons.Nodes.Property; - case SNIPPET: - return AllIcons.Nodes.Template; - case TEXT: - return AllIcons.Nodes.Word; - case UNIT: - return AllIcons.Nodes.Test; - case VALUE: - case REFERENCE: - case VARIABLE: - return AllIcons.Nodes.Variable; - default: - return AllIcons.Nodes.EmptyNode; + private @Nullable String getTypeText(@NotNull CompletionItem item) { + return item.getDetail(); + } + + private @Nullable Icon getIcon(@Nullable CompletionItemType type) { + if (type == null) { + return null; + } + + return switch (type) { + case CLASS -> AllIcons.Nodes.Class; + case CUSTOMCOLOR, COLOR -> AllIcons.Nodes.EmptyNode; + case CONSTRUCTOR -> AllIcons.Nodes.ClassInitializer; + case ENUM -> AllIcons.Nodes.Enum; + case FIELD -> AllIcons.Nodes.Field; + case FILE -> AllIcons.FileTypes.Any_type; + case FUNCTION -> AllIcons.Nodes.Function; + case INTERFACE -> AllIcons.Nodes.Interface; + case KEYWORD -> AllIcons.Nodes.Constant; + case METHOD -> AllIcons.Nodes.Method; + case MODULE -> AllIcons.Nodes.Module; + case PROPERTY -> AllIcons.Nodes.Property; + case SNIPPET -> AllIcons.Nodes.Template; + case TEXT -> AllIcons.Nodes.Word; + case UNIT -> AllIcons.Nodes.Test; + case VALUE, REFERENCE, VARIABLE -> AllIcons.Nodes.Variable; + default -> AllIcons.Nodes.EmptyNode; + }; } -} } diff --git a/src/main/java/com/redhat/devtools/lsp4ij/internal/CompletionUtils.java b/src/main/java/com/redhat/devtools/lsp4ij/internal/CompletionUtils.java new file mode 100644 index 000000000..21aca9705 --- /dev/null +++ b/src/main/java/com/redhat/devtools/lsp4ij/internal/CompletionUtils.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2025 Red Hat, Inc. + * Distributed under license by Red Hat, Inc. All rights reserved. + * This program is made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, + * and is available at https://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + *****************************************************************************/ +package com.redhat.devtools.lsp4ij.internal; + +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiFile; +import com.redhat.devtools.lsp4ij.LSPIJUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * LSP/DAP Completion utilities. + */ +public class CompletionUtils { + + @Nullable + public static Integer computePrefixStartFromInsertText(@NotNull Document document, + @Nullable PsiFile file, + int completionOffset, + String insertText) { + + // case 2.1: first strategy, we collect word range at + // ex : + // insertText= '(let [${1:binding} ${2:value}])' + // document= le + // we have to return |le as prefix start offset + + TextRange wordRange = LSPIJUtils.getWordRangeAt(document, file, completionOffset); + if (wordRange != null) { + return wordRange.getStartOffset(); + } + + // case 2.2: second strategy, we check if the left content of the completion offset + // matches the full insertText left content + // ex : + // insertText= 'foo.bar' + // document= {foo.b|} + // we have to return {| as prefix start offset + + return getPrefixStartOffsetWhichMatchesLeftContent(document, completionOffset, insertText); + } + + @Nullable + private static Integer getPrefixStartOffsetWhichMatchesLeftContent(@NotNull Document document, + int completionOffset, + @NotNull String insertText) { + int startOffset = Math.max(0, completionOffset - insertText.length()); + int endOffset = startOffset + Math.min(insertText.length(), completionOffset); + String subDoc = document.getText(new TextRange(startOffset, endOffset)); // "".ch + for (int i = 0; i < insertText.length() && i < completionOffset; i++) { + String tentativeCommonString = subDoc.substring(i); + if (insertText.startsWith(tentativeCommonString)) { + return completionOffset - tentativeCommonString.length(); + } + } + return null; + } + +} From 035c4fd82cc7603ef3a346be0d9585d4e41564b0 Mon Sep 17 00:00:00 2001 From: azerr Date: Fri, 25 Jul 2025 15:32:36 +0200 Subject: [PATCH 003/264] feat: Support runInTerminal (integrated) request for DAP Fixes #1181 Signed-off-by: azerr --- gradle.properties | 2 +- .../devtools/lsp4ij/dap/client/DAPClient.java | 10 +- .../runInterminal/RunInTerminalManager.java | 213 ++++++++++++++++++ .../descriptors/DebugAdapterDescriptor.java | 1 + .../resources/META-INF/plugin-terminal.xml | 4 + src/main/resources/META-INF/plugin.xml | 3 + 6 files changed, 230 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/RunInTerminalManager.java create mode 100644 src/main/resources/META-INF/plugin-terminal.xml diff --git a/gradle.properties b/gradle.properties index 3bb6b7bf5..8b3137b45 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,7 +14,7 @@ pluginSinceBuild=233 # IntelliJ Platform Properties -> https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#configuration-intellij-extension platformType=IC platformVersion=2023.3 -platformBundledPlugins=org.jetbrains.plugins.textmate,com.intellij.properties +platformBundledPlugins=org.jetbrains.plugins.textmate,com.intellij.properties,org.jetbrains.plugins.terminal # Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html platformPlugins=com.redhat.devtools.intellij.telemetry:1.2.1.62 diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/client/DAPClient.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/client/DAPClient.java index fee5b903e..48edea44f 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/client/DAPClient.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/client/DAPClient.java @@ -31,6 +31,7 @@ import com.redhat.devtools.lsp4ij.dap.DebugMode; import com.redhat.devtools.lsp4ij.dap.TransportStreams; import com.redhat.devtools.lsp4ij.dap.breakpoints.DAPBreakpointProperties; +import com.redhat.devtools.lsp4ij.dap.client.runInterminal.RunInTerminalManager; import com.redhat.devtools.lsp4ij.dap.descriptors.DebugAdapterDescriptor; import com.redhat.devtools.lsp4ij.internal.CancellationSupport; import com.redhat.devtools.lsp4ij.internal.StringUtils; @@ -306,6 +307,11 @@ private static ConsoleViewContentType getContentType(String category) { return ConsoleViewContentType.LOG_INFO_OUTPUT; } + @Override + public CompletableFuture runInTerminal(RunInTerminalRequestArguments args) { + return RunInTerminalManager.getInstance(getProject()).runInTerminal(args); + } + @Override public void breakpoint(BreakpointEventArguments args) { if (BreakpointEventArgumentsReason.CHANGED.equals(args.getReason())) { @@ -600,13 +606,13 @@ public CompletableFuture getThreads(boolean re if (debugProtocolServer == null) { return CompletableFuture.completedFuture(EMPTY_THREADS); } - var result= debugProtocolServer + var result = debugProtocolServer .threads() .thenApply(response -> { if (response == null) { return EMPTY_THREADS; } - return response.getThreads(); + return response.getThreads(); }); if (refreshThreads) { result.thenAccept(threads -> { diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/RunInTerminalManager.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/RunInTerminalManager.java new file mode 100644 index 000000000..1f15950f2 --- /dev/null +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/RunInTerminalManager.java @@ -0,0 +1,213 @@ +/******************************************************************************* + * Copyright (c) 2025 Red Hat, Inc. + * Distributed under license by Red Hat, Inc. All rights reserved. + * This program is made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, + * and is available at https://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + ******************************************************************************/ +package com.redhat.devtools.lsp4ij.dap.client.runInterminal; + +import com.intellij.ide.plugins.PluginManagerCore; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.extensions.PluginId; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.util.Alarm; +import org.eclipse.lsp4j.debug.RunInTerminalRequestArguments; +import org.eclipse.lsp4j.debug.RunInTerminalRequestArgumentsKind; +import org.eclipse.lsp4j.debug.RunInTerminalResponse; +import org.eclipse.sisu.Nullable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.terminal.ShellTerminalWidget; +import org.jetbrains.plugins.terminal.TerminalToolWindowManager; + +import java.util.Arrays; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; + +/** + * Manages Debug Adapter Protocol (DAP) {@code RunInTerminal} requests, + * supporting integrated terminal execution within IntelliJ IDEA. + */ +public class RunInTerminalManager { + + private final @NotNull Project project; + + public RunInTerminalManager(@NotNull Project project) { + this.project = project; + } + + public static RunInTerminalManager getInstance(@NotNull Project project) { + return project.getService(RunInTerminalManager.class); + } + + /** + * Executes a command in either an integrated or external terminal based on the request kind. + * + * @param args DAP {@link RunInTerminalRequestArguments} + * @return a {@link CompletableFuture} resolving to the {@link RunInTerminalResponse} + */ + public CompletableFuture runInTerminal(RunInTerminalRequestArguments args) { + if (shouldUseIntegratedTerminal(args.getKind())) { + return runInIntegratedTerminal(args); + } + return runInExternalTerminal(args); + } + + /** + * Runs a command in IntelliJ's integrated terminal. + */ + private CompletableFuture runInIntegratedTerminal(RunInTerminalRequestArguments args) { + CompletableFuture future = new CompletableFuture<>(); + + ApplicationManager.getApplication().invokeLater(() -> { + try { + TerminalToolWindowManager tm = TerminalToolWindowManager.getInstance(project); + + String title = args.getTitle(); + String workingDirectory = args.getCwd(); + ShellTerminalWidget shellWidget = tm.createLocalShellWidget(workingDirectory, title); + + String command = prepareCommandWithEnv(args); + + shellWidget.executeCommand(command); + + Alarm alarm = new Alarm(Alarm.ThreadToUse.POOLED_THREAD, project); + Runnable checkProcess = new Runnable() { + @Override + public void run() { + var tty = shellWidget.getProcessTtyConnector(); + if (tty != null) { + RunInTerminalResponse resp = new RunInTerminalResponse(); + resp.setProcessId((int) tty.getProcess().pid()); + future.complete(resp); + } else if (!future.isDone()) { + alarm.addRequest(this, 100); // recheck in 100ms + } + } + }; + alarm.addRequest(checkProcess, 100); + + } catch (Exception e) { + future.completeExceptionally(e); + } + }); + + return future; + } + + /** + * Prepares a full command line with environment variable injection, + * adapting to the current OS and shell syntax. + *

+ * - PowerShell: ${env:VAR}='value'; command + * - cmd.exe: set VAR=value && set VAR2=value && command + * - Unix shells: VAR='value' VAR2='value' command + */ + private String prepareCommandWithEnv(RunInTerminalRequestArguments args) { + String command = formatCommandArguments(args.getArgs()); + + if (args.getEnv() == null || args.getEnv().isEmpty()) { + return command; + } + + boolean isWindows = SystemInfo.isWindows; + boolean isPowerShell = isWindows && isPowerShellEnvironment(); + StringBuilder envCmd = new StringBuilder(); + + if (isPowerShell) { + args.getEnv().forEach((k, v) -> { + envCmd.append("${env:").append(k).append("}='") + .append(v.replace("'", "''")).append("'; "); + }); + envCmd.append(command); + } else if (isWindows) { + args.getEnv().forEach((k, v) -> { + envCmd.append("set ").append(k).append("=").append(v).append(" && "); + }); + envCmd.append(command); + } else { + args.getEnv().forEach((k, v) -> { + envCmd.append(k).append("='") + .append(v.replace("'", "'\"'\"'")).append("' "); + }); + envCmd.append(command); + } + + return envCmd.toString(); + } + + /** + * Formats a command line by quoting and escaping arguments for the current OS/shell. + *

+ * - PowerShell: adds call operator '&' and quotes paths with spaces + * - cmd.exe: escapes spaces with '^' + * - Unix: wraps arguments with spaces in single quotes + */ + private String formatCommandArguments(String[] args) { + boolean isWindows = SystemInfo.isWindows; + boolean isPowerShell = isWindows && isPowerShellEnvironment(); + + if (args.length == 0) { + return ""; + } + + if (isPowerShell) { + String first = args[0]; + if (first.contains(" ")) { + first = "& \"" + first + "\""; + } else { + first = "& " + first; + } + + String rest = Arrays.stream(args, 1, args.length) + .map(arg -> arg.contains(" ") ? "\"" + arg + "\"" : arg) + .collect(Collectors.joining(" ")); + + return first + (rest.isEmpty() ? "" : " " + rest); + } else if (isWindows) { + return Arrays.stream(args) + .map(arg -> arg.contains(" ") ? arg.replace(" ", "^ ") : arg) + .collect(Collectors.joining(" ")); + } else { + return Arrays.stream(args) + .map(arg -> arg.contains(" ") ? "'" + arg.replace("'", "'\"'\"'") + "'" : arg) + .collect(Collectors.joining(" ")); + } + } + + /** + * Detects whether the current environment is running PowerShell on Windows. + */ + private boolean isPowerShellEnvironment() { + String psModule = System.getenv("PSModulePath"); + return psModule != null && psModule.contains("PowerShell"); + } + + /** + * Placeholder for running in an external terminal. + */ + private CompletableFuture runInExternalTerminal(RunInTerminalRequestArguments args) { + CompletableFuture future = new CompletableFuture<>(); + future.completeExceptionally(new UnsupportedOperationException("runInExternalTerminal not supported")); + return future; + } + + /** + * Checks if the request should use the integrated terminal. + */ + private boolean shouldUseIntegratedTerminal(@Nullable RunInTerminalRequestArgumentsKind kind) { + return kind == RunInTerminalRequestArgumentsKind.INTEGRATED && isTerminalPluginInstalled(); + } + + /** + * Verifies if the IntelliJ terminal plugin is installed. + */ + private static boolean isTerminalPluginInstalled() { + PluginId pluginId = PluginId.getId("org.jetbrains.plugins.terminal"); + return PluginManagerCore.getPlugin(pluginId) != null; + } +} diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/descriptors/DebugAdapterDescriptor.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/descriptors/DebugAdapterDescriptor.java index 794a0f992..b862955d9 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/descriptors/DebugAdapterDescriptor.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/descriptors/DebugAdapterDescriptor.java @@ -163,6 +163,7 @@ public static Integer getServerPort(ProcessHandler processHandler) { args.setLinesStartAt1(true); args.setColumnsStartAt1(true); args.setSupportsStartDebuggingRequest(true); + args.setSupportsRunInTerminalRequest(true); return args; } diff --git a/src/main/resources/META-INF/plugin-terminal.xml b/src/main/resources/META-INF/plugin-terminal.xml new file mode 100644 index 000000000..f88266f08 --- /dev/null +++ b/src/main/resources/META-INF/plugin-terminal.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 0d8ccc4e1..a4591e33e 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -248,6 +248,7 @@ org.jetbrains.plugins.textmate com.redhat.devtools.intellij.telemetry com.intellij.modules.json + org.jetbrains.plugins.terminal @@ -970,6 +971,8 @@ + Date: Tue, 29 Jul 2025 11:33:12 +0200 Subject: [PATCH 004/264] fix: DAP completion apply fix Signed-off-by: azerr --- .../dap/completion/DAPLookupElementDecorator.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/completion/DAPLookupElementDecorator.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/completion/DAPLookupElementDecorator.java index 38cced389..d08304715 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/completion/DAPLookupElementDecorator.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/completion/DAPLookupElementDecorator.java @@ -67,8 +67,7 @@ private void handleInsertInWriteAction(@NotNull InsertionContext context) { var document = context.getDocument(); int startOffset = getStartOffset(document); - int length = getLength(context); - int endOffset = length + startOffset; + int endOffset = getEndOffset(startOffset, context); String newText = getNewtText(); // Update document with the new completion item text to insert @@ -94,7 +93,7 @@ private void handleInsertInWriteAction(@NotNull InsertionContext context) { } else { // No selection, update caret offset only - int newCaretOffset = editor.getCaretModel().getOffset() + newText.length() - length; + int newCaretOffset = editor.getCaretModel().getOffset() + newText.length() - (endOffset - startOffset); if (oldCaretOffset != newCaretOffset) { editor.getCaretModel().moveToOffset(newCaretOffset); } @@ -110,14 +109,13 @@ private int getStartOffset(@NotNull Document document) { return Objects.requireNonNullElse(prefixStartOffset, completionOffset); } - private int getLength(@NotNull InsertionContext context) { + private int getEndOffset(int startOffset, @NotNull InsertionContext context) { int selectionEndOffset = context.getOffset(CompletionInitializationContext.SELECTION_END_OFFSET); - int endOffset = selectionEndOffset - completionOffset; Integer length = item.getLength(); - if (length != null) { - endOffset += length; + if (length == null) { + return selectionEndOffset; } - return endOffset; + return startOffset + (selectionEndOffset - completionOffset + length); } private @NotNull String getNewtText() { From ead6e294cf6fb7ba277de2d4810db1b7663416f2 Mon Sep 17 00:00:00 2001 From: azerr Date: Mon, 28 Jul 2025 16:39:25 +0200 Subject: [PATCH 005/264] feat: Support runInTerminal (external only for Windows OS) request for DAP Signed-off-by: azerr --- docs/dap/DAPSupport.md | 2 +- .../runInterminal/RunInTerminalManager.java | 181 ++------------ .../runInterminal/RunInTerminalService.java | 75 ++++++ .../external/ExternalTerminalService.java | 79 ++++++ .../LinuxExternalTerminalService.java | 141 +++++++++++ .../external/MacExternalTerminalService.java | 93 +++++++ .../WindowsExternalTerminalService.java | 131 ++++++++++ .../RunInIntegratedTerminalService.java | 228 ++++++++++++++++++ 8 files changed, 773 insertions(+), 157 deletions(-) create mode 100644 src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/RunInTerminalService.java create mode 100644 src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/external/ExternalTerminalService.java create mode 100644 src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/external/LinuxExternalTerminalService.java create mode 100644 src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/external/MacExternalTerminalService.java create mode 100644 src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/external/WindowsExternalTerminalService.java create mode 100644 src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/integrated/RunInIntegratedTerminalService.java diff --git a/docs/dap/DAPSupport.md b/docs/dap/DAPSupport.md index dd0749333..b093ae384 100644 --- a/docs/dap/DAPSupport.md +++ b/docs/dap/DAPSupport.md @@ -76,5 +76,5 @@ Current state of [Requests](https://microsoft.github.io/debug-adapter-protocol// Current state of [Reverse Requests](https://microsoft.github.io/debug-adapter-protocol//specification.html#Reverse_Requests) support: -* ❌ [RunInTerminal](https://microsoft.github.io/debug-adapter-protocol//specification.html#Reverse_Requests_RunInTerminal). +* ✅ [RunInTerminal](https://microsoft.github.io/debug-adapter-protocol//specification.html#Reverse_Requests_RunInTerminal). * ✅ [StartDebugging](https://microsoft.github.io/debug-adapter-protocol//specification.html#Reverse_Requests_StartDebugging). \ No newline at end of file diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/RunInTerminalManager.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/RunInTerminalManager.java index 1f15950f2..295c4ae60 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/RunInTerminalManager.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/RunInTerminalManager.java @@ -16,6 +16,10 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.SystemInfo; import com.intellij.util.Alarm; +import com.redhat.devtools.lsp4ij.dap.client.runInterminal.external.LinuxExternalTerminalService; +import com.redhat.devtools.lsp4ij.dap.client.runInterminal.external.MacExternalTerminalService; +import com.redhat.devtools.lsp4ij.dap.client.runInterminal.external.WindowsExternalTerminalService; +import com.redhat.devtools.lsp4ij.dap.client.runInterminal.integrated.RunInIntegratedTerminalService; import org.eclipse.lsp4j.debug.RunInTerminalRequestArguments; import org.eclipse.lsp4j.debug.RunInTerminalRequestArgumentsKind; import org.eclipse.lsp4j.debug.RunInTerminalResponse; @@ -24,7 +28,9 @@ import org.jetbrains.plugins.terminal.ShellTerminalWidget; import org.jetbrains.plugins.terminal.TerminalToolWindowManager; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; @@ -35,9 +41,23 @@ public class RunInTerminalManager { private final @NotNull Project project; + private final @NotNull RunInTerminalService runInIntegratedTerminalService; + private final @NotNull RunInTerminalService runInExternalTerminalService; public RunInTerminalManager(@NotNull Project project) { this.project = project; + this.runInIntegratedTerminalService = new RunInIntegratedTerminalService(); + this.runInExternalTerminalService = createExternalTerminalService(); + } + + private @NotNull RunInTerminalService createExternalTerminalService() { + if (SystemInfo.isWindows) { + return new WindowsExternalTerminalService(); + } + if (SystemInfo.isMac) { + return new MacExternalTerminalService(); + } + return new LinuxExternalTerminalService(); } public static RunInTerminalManager getInstance(@NotNull Project project) { @@ -50,164 +70,13 @@ public static RunInTerminalManager getInstance(@NotNull Project project) { * @param args DAP {@link RunInTerminalRequestArguments} * @return a {@link CompletableFuture} resolving to the {@link RunInTerminalResponse} */ - public CompletableFuture runInTerminal(RunInTerminalRequestArguments args) { - if (shouldUseIntegratedTerminal(args.getKind())) { - return runInIntegratedTerminal(args); - } - return runInExternalTerminal(args); - } - - /** - * Runs a command in IntelliJ's integrated terminal. - */ - private CompletableFuture runInIntegratedTerminal(RunInTerminalRequestArguments args) { - CompletableFuture future = new CompletableFuture<>(); - - ApplicationManager.getApplication().invokeLater(() -> { - try { - TerminalToolWindowManager tm = TerminalToolWindowManager.getInstance(project); - - String title = args.getTitle(); - String workingDirectory = args.getCwd(); - ShellTerminalWidget shellWidget = tm.createLocalShellWidget(workingDirectory, title); - - String command = prepareCommandWithEnv(args); - - shellWidget.executeCommand(command); - - Alarm alarm = new Alarm(Alarm.ThreadToUse.POOLED_THREAD, project); - Runnable checkProcess = new Runnable() { - @Override - public void run() { - var tty = shellWidget.getProcessTtyConnector(); - if (tty != null) { - RunInTerminalResponse resp = new RunInTerminalResponse(); - resp.setProcessId((int) tty.getProcess().pid()); - future.complete(resp); - } else if (!future.isDone()) { - alarm.addRequest(this, 100); // recheck in 100ms - } - } - }; - alarm.addRequest(checkProcess, 100); - - } catch (Exception e) { - future.completeExceptionally(e); + public CompletableFuture runInTerminal(@NotNull RunInTerminalRequestArguments args) { + if (args.getKind() == RunInTerminalRequestArgumentsKind.INTEGRATED) { + if (runInIntegratedTerminalService.isApplicable()) { + return runInIntegratedTerminalService.runInTerminal(args, project); } - }); - - return future; - } - - /** - * Prepares a full command line with environment variable injection, - * adapting to the current OS and shell syntax. - *

- * - PowerShell: ${env:VAR}='value'; command - * - cmd.exe: set VAR=value && set VAR2=value && command - * - Unix shells: VAR='value' VAR2='value' command - */ - private String prepareCommandWithEnv(RunInTerminalRequestArguments args) { - String command = formatCommandArguments(args.getArgs()); - - if (args.getEnv() == null || args.getEnv().isEmpty()) { - return command; - } - - boolean isWindows = SystemInfo.isWindows; - boolean isPowerShell = isWindows && isPowerShellEnvironment(); - StringBuilder envCmd = new StringBuilder(); - - if (isPowerShell) { - args.getEnv().forEach((k, v) -> { - envCmd.append("${env:").append(k).append("}='") - .append(v.replace("'", "''")).append("'; "); - }); - envCmd.append(command); - } else if (isWindows) { - args.getEnv().forEach((k, v) -> { - envCmd.append("set ").append(k).append("=").append(v).append(" && "); - }); - envCmd.append(command); - } else { - args.getEnv().forEach((k, v) -> { - envCmd.append(k).append("='") - .append(v.replace("'", "'\"'\"'")).append("' "); - }); - envCmd.append(command); } - - return envCmd.toString(); + return runInExternalTerminalService.runInTerminal(args, project); } - /** - * Formats a command line by quoting and escaping arguments for the current OS/shell. - *

- * - PowerShell: adds call operator '&' and quotes paths with spaces - * - cmd.exe: escapes spaces with '^' - * - Unix: wraps arguments with spaces in single quotes - */ - private String formatCommandArguments(String[] args) { - boolean isWindows = SystemInfo.isWindows; - boolean isPowerShell = isWindows && isPowerShellEnvironment(); - - if (args.length == 0) { - return ""; - } - - if (isPowerShell) { - String first = args[0]; - if (first.contains(" ")) { - first = "& \"" + first + "\""; - } else { - first = "& " + first; - } - - String rest = Arrays.stream(args, 1, args.length) - .map(arg -> arg.contains(" ") ? "\"" + arg + "\"" : arg) - .collect(Collectors.joining(" ")); - - return first + (rest.isEmpty() ? "" : " " + rest); - } else if (isWindows) { - return Arrays.stream(args) - .map(arg -> arg.contains(" ") ? arg.replace(" ", "^ ") : arg) - .collect(Collectors.joining(" ")); - } else { - return Arrays.stream(args) - .map(arg -> arg.contains(" ") ? "'" + arg.replace("'", "'\"'\"'") + "'" : arg) - .collect(Collectors.joining(" ")); - } - } - - /** - * Detects whether the current environment is running PowerShell on Windows. - */ - private boolean isPowerShellEnvironment() { - String psModule = System.getenv("PSModulePath"); - return psModule != null && psModule.contains("PowerShell"); - } - - /** - * Placeholder for running in an external terminal. - */ - private CompletableFuture runInExternalTerminal(RunInTerminalRequestArguments args) { - CompletableFuture future = new CompletableFuture<>(); - future.completeExceptionally(new UnsupportedOperationException("runInExternalTerminal not supported")); - return future; - } - - /** - * Checks if the request should use the integrated terminal. - */ - private boolean shouldUseIntegratedTerminal(@Nullable RunInTerminalRequestArgumentsKind kind) { - return kind == RunInTerminalRequestArgumentsKind.INTEGRATED && isTerminalPluginInstalled(); - } - - /** - * Verifies if the IntelliJ terminal plugin is installed. - */ - private static boolean isTerminalPluginInstalled() { - PluginId pluginId = PluginId.getId("org.jetbrains.plugins.terminal"); - return PluginManagerCore.getPlugin(pluginId) != null; - } } diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/RunInTerminalService.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/RunInTerminalService.java new file mode 100644 index 000000000..bae9a7f43 --- /dev/null +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/RunInTerminalService.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2025 Red Hat, Inc. + * Distributed under license by Red Hat, Inc. All rights reserved. + * This program is made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, + * and is available at https://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + ******************************************************************************/ +package com.redhat.devtools.lsp4ij.dap.client.runInterminal; + +import com.intellij.openapi.project.Project; +import org.eclipse.lsp4j.debug.RunInTerminalRequestArguments; +import org.eclipse.lsp4j.debug.RunInTerminalResponse; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.CompletableFuture; + +/** + * Service API for handling Debug Adapter Protocol {@code runInTerminal} requests. + *

+ * Implementations of this service are responsible for spawning a new terminal instance + * (either external or integrated) and executing the command specified in the + * {@link RunInTerminalRequestArguments}. Implementations are typically platform-specific + * (e.g., Windows, Linux, macOS). + *

+ * + *

This service is used to support the DAP {@code runInTerminal} feature, allowing + * debug adapters to request that a program be launched in a user-visible terminal.

+ * + *

Implementation notes:

+ *
    + *
  • Implementations should check {@link #isApplicable()} to determine whether the service + * can run on the current OS/environment.
  • + *
  • The {@link #runInTerminal(RunInTerminalRequestArguments, Project)} method should + * execute the command asynchronously and return a {@link CompletableFuture} that + * completes with the {@link RunInTerminalResponse} when the terminal is launched.
  • + *
+ */ +public interface RunInTerminalService { + + /** + * Determines whether this implementation is applicable in the current environment. + *

+ * This is typically used to filter OS-specific services (e.g., Windows, Linux, macOS) + * so that only the correct one is used at runtime. + *

+ * + * @return {@code true} if this service can handle {@code runInTerminal} requests + * on the current platform, {@code false} otherwise. + */ + boolean isApplicable(); + + /** + * Launches a new terminal and executes the command specified in the given + * {@link RunInTerminalRequestArguments}. + * + *

+ * The implementation should spawn a terminal process (external or integrated), + * set the working directory and environment variables as specified, + * and start the target program. This method must return immediately + * with a {@link CompletableFuture} that completes when the terminal is successfully + * launched or completes exceptionally if an error occurs. + *

+ * + * @param args the {@link RunInTerminalRequestArguments} containing the command, + * working directory, environment variables, and terminal type + * @param project the IntelliJ {@link Project} in which this terminal is being launched + * @return a {@link CompletableFuture} resolving to a {@link RunInTerminalResponse} + * containing the process ID or {@code null} if not supported. + */ + CompletableFuture runInTerminal(@NotNull RunInTerminalRequestArguments args, + @NotNull Project project); +} diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/external/ExternalTerminalService.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/external/ExternalTerminalService.java new file mode 100644 index 000000000..83902d11d --- /dev/null +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/external/ExternalTerminalService.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2025 Red Hat, Inc. + * Distributed under license by Red Hat, Inc. All rights reserved. + * This program is made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, + * and is available at https://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + ******************************************************************************/ +package com.redhat.devtools.lsp4ij.dap.client.runInterminal.external; + +import com.intellij.openapi.project.Project; +import com.redhat.devtools.lsp4ij.dap.client.runInterminal.RunInTerminalService; +import org.eclipse.lsp4j.debug.RunInTerminalRequestArguments; +import org.eclipse.lsp4j.debug.RunInTerminalResponse; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.CompletableFuture; + +/** + * Base class for external terminal services that handle Debug Adapter Protocol + * {@code runInTerminal} requests. + *

+ * This abstract class implements the {@link RunInTerminalService} API and provides + * a standard mechanism to wrap the process ID into a {@link RunInTerminalResponse}. + * Subclasses are responsible for providing the OS-specific logic to actually + * spawn the terminal and execute the command via {@link #doRunInTerminal(RunInTerminalRequestArguments, Project)}. + *

+ * + *

+ * Implementations typically include: + *

    + *
  • {@code WindowsExternalTerminalService}
  • + *
  • {@code LinuxExternalTerminalService}
  • + *
  • {@code MacExternalTerminalService}
  • + *
+ *

+ */ +public abstract class ExternalTerminalService implements RunInTerminalService { + + /** + * Executes a DAP {@code runInTerminal} request by delegating to the + * platform-specific {@link #doRunInTerminal(RunInTerminalRequestArguments, Project)} + * implementation and wrapping the resulting process ID into a + * {@link RunInTerminalResponse}. + * + * @param args the {@link RunInTerminalRequestArguments} containing the command, + * working directory, environment variables, and terminal kind + * @param project the IntelliJ {@link Project} in which this terminal is being launched + * @return a {@link CompletableFuture} that resolves to a {@link RunInTerminalResponse} + * containing the process ID of the spawned terminal process. + */ + @Override + public CompletableFuture runInTerminal(@NotNull RunInTerminalRequestArguments args, + @NotNull Project project) { + return doRunInTerminal(args, project) + .thenApply(pid -> { + RunInTerminalResponse response = new RunInTerminalResponse(); + response.setProcessId(pid); + return response; + }); + } + + /** + * Spawns an external terminal process and executes the command specified in + * the given {@link RunInTerminalRequestArguments}. + *

+ * Subclasses must implement this method to handle the platform-specific logic + * (Windows, Linux, macOS). + *

+ * + * @param args the {@link RunInTerminalRequestArguments} with the command and environment settings + * @param project the IntelliJ {@link Project} context + * @return a {@link CompletableFuture} resolving to the process ID of the spawned terminal + */ + protected abstract CompletableFuture doRunInTerminal(@NotNull RunInTerminalRequestArguments args, + @NotNull Project project); +} diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/external/LinuxExternalTerminalService.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/external/LinuxExternalTerminalService.java new file mode 100644 index 000000000..c07edfe78 --- /dev/null +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/external/LinuxExternalTerminalService.java @@ -0,0 +1,141 @@ +/******************************************************************************* + * Copyright (c) 2025 Red Hat, Inc. + * Distributed under license by Red Hat, Inc. All rights reserved. + * This program is made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, + * and is available at https://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + ******************************************************************************/ +package com.redhat.devtools.lsp4ij.dap.client.runInterminal.external; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.SystemInfo; +import org.eclipse.lsp4j.debug.RunInTerminalRequestArguments; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; +import java.util.*; +import java.util.concurrent.CompletableFuture; + +/** + * This class code is the vscode TypeScript translate from + * LinuxExternalTerminalService + */ +public class LinuxExternalTerminalService extends ExternalTerminalService { + + // List of common Linux terminals in the same order VS Code tries them + private static final String[] LINUX_TERMINALS = new String[]{ + "gnome-terminal", + "konsole", + "xfce4-terminal", + "xterm", + "lxterminal", + "mate-terminal", + "terminator", + "tilix", + "deepin-terminal", + "kitty", + "alacritty", + "x-terminal-emulator" + }; + + @Override + public boolean isApplicable() { + return SystemInfo.isLinux; + } + + @Override + protected CompletableFuture doRunInTerminal(@NotNull RunInTerminalRequestArguments args, + @NotNull Project project) { + + // TODO : reimplement this class!!! + + String terminal = findAvailableTerminal(); + if (terminal == null) { + CompletableFuture failed = new CompletableFuture<>(); + failed.completeExceptionally(new RuntimeException("No supported Linux terminal found in PATH")); + return failed; + } + + // Build the shell command like VS Code: + // bash -c "cd /cwd && ; exec bash" + String joinedArgs = String.join(" ", escapeArgs(args.getArgs())); + String fullCommand = "cd " + escapeArg(args.getCwd()) + " && " + joinedArgs + " ; exec bash"; + + List cmd = new ArrayList<>(); + cmd.add(terminal); + cmd.add("-e"); + cmd.add("bash"); + cmd.add("-c"); + cmd.add(fullCommand); + + ProcessBuilder pb = new ProcessBuilder(cmd); + pb.directory(new File(args.getCwd())); + + // Filter out null values in the environment variables + Map env = args.getEnv() != null ? args.getEnv() : new HashMap<>(); + env.entrySet().removeIf(e -> e.getValue() == null); + pb.environment().putAll(env); + + return runProcessAsyncWithExitCode(pb); + } + + /** + * Run the process asynchronously and complete the future with the exit code. + */ + private CompletableFuture runProcessAsyncWithExitCode(ProcessBuilder pb) { + CompletableFuture future = new CompletableFuture<>(); + try { + Process p = pb.start(); + p.onExit().thenAccept(pr -> future.complete(pr.exitValue())); + } catch (IOException e) { + future.completeExceptionally(e); + } + return future; + } + + /** + * Finds the first available terminal from the list in the PATH. + */ + private String findAvailableTerminal() { + for (String term : LINUX_TERMINALS) { + if (isExecutableInPath(term)) { + return term; + } + } + return null; + } + + /** + * Checks if the given executable is available in the PATH using 'which'. + */ + private boolean isExecutableInPath(String exec) { + try { + Process p = new ProcessBuilder("which", exec).start(); + return p.waitFor() == 0; + } catch (Exception e) { + return false; + } + } + + /** + * Escape arguments for safe usage inside bash -c. + */ + private List escapeArgs(String[] args) { + List escaped = new ArrayList<>(); + for (String arg : args) { + escaped.add(escapeArg(arg)); + } + return escaped; + } + + /** + * Escape a single argument by wrapping it in single quotes and handling embedded quotes. + */ + private String escapeArg(String arg) { + return "'" + arg.replace("'", "'\"'\"'") + "'"; + } +} diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/external/MacExternalTerminalService.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/external/MacExternalTerminalService.java new file mode 100644 index 000000000..e5e474390 --- /dev/null +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/external/MacExternalTerminalService.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * Copyright (c) 2025 Red Hat, Inc. + * Distributed under license by Red Hat, Inc. All rights reserved. + * This program is made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, + * and is available at https://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + ******************************************************************************/ +package com.redhat.devtools.lsp4ij.dap.client.runInterminal.external; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.SystemInfo; +import org.eclipse.lsp4j.debug.RunInTerminalRequestArguments; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; +import java.util.*; +import java.util.concurrent.CompletableFuture; + +/** + * This class code is the vscode TypeScript translate from + * MacExternalTerminalService + */ +public class MacExternalTerminalService extends ExternalTerminalService { + + @Override + public boolean isApplicable() { + return SystemInfo.isMac; + } + + @Override + protected CompletableFuture doRunInTerminal(@NotNull RunInTerminalRequestArguments args, + @NotNull Project project) { + + // TODO : reimplement this class!!! + + // Build AppleScript command like VS Code does + String joinedArgs = String.join(" ", escapeArgs(args.getArgs())); + String fullCommand = "cd " + escapeArg(args.getCwd()) + " && " + joinedArgs; + + // AppleScript to tell Terminal to open a new window and run the command + String appleScript = "tell application \"Terminal\"\n" + + "do script \"" + fullCommand + "\"\n" + + "activate\n" + + "end tell"; + + List cmd = Arrays.asList("osascript", "-e", appleScript); + + ProcessBuilder pb = new ProcessBuilder(cmd); + pb.directory(new File(args.getCwd())); + + Map env = args.getEnv() != null ? args.getEnv() : new HashMap<>(); + env.entrySet().removeIf(e -> e.getValue() == null); + pb.environment().putAll(env); + + return runProcessAsyncWithExitCode(pb); + } + + /** + * Run the process asynchronously and complete the future with the exit code. + */ + private CompletableFuture runProcessAsyncWithExitCode(ProcessBuilder pb) { + CompletableFuture future = new CompletableFuture<>(); + try { + Process p = pb.start(); + p.onExit().thenAccept(pr -> future.complete(pr.exitValue())); + } catch (IOException e) { + future.completeExceptionally(e); + } + return future; + } + + /** + * Escape arguments for safe usage inside AppleScript/Terminal. + */ + private List escapeArgs(String[] args) { + List escaped = new ArrayList<>(); + for (String arg : args) { + escaped.add(escapeArg(arg)); + } + return escaped; + } + + /** + * Escape a single argument for safe bash usage. + */ + private String escapeArg(String arg) { + return "'" + arg.replace("'", "'\"'\"'") + "'"; + } +} diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/external/WindowsExternalTerminalService.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/external/WindowsExternalTerminalService.java new file mode 100644 index 000000000..d6e1983c6 --- /dev/null +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/external/WindowsExternalTerminalService.java @@ -0,0 +1,131 @@ +/******************************************************************************* + * Copyright (c) 2025 Red Hat, Inc. + * Distributed under license by Red Hat, Inc. All rights reserved. + * This program is made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, + * and is available at https://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + ******************************************************************************/ +package com.redhat.devtools.lsp4ij.dap.client.runInterminal.external; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.SystemInfo; +import org.eclipse.lsp4j.debug.RunInTerminalRequestArguments; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; +import java.util.*; +import java.util.concurrent.CompletableFuture; + +/** + * Windows-specific implementation of {@link ExternalTerminalService} used to spawn external + * terminals when handling the Debug Adapter Protocol (DAP) {@code runInTerminal} request. + *

+ * This class is based on the VS Code implementation + * + * WindowsExternalTerminalService, translated from TypeScript to Java. + *

+ * The service detects whether the Windows Terminal (`wt.exe`) or the classic `cmd.exe` should be used, + * constructs the appropriate command-line arguments, injects environment variables, and runs the + * process asynchronously, returning its exit code once completed. + */ +public class WindowsExternalTerminalService extends ExternalTerminalService { + + /** Default Windows command-line interpreter. */ + private static final String CMD = "cmd.exe"; + + /** Cached default terminal path to avoid recomputing. */ + private static String DEFAULT_TERMINAL_WINDOWS; + + /** + * Indicates if this service is applicable on the current platform. + * + * @return {@code true} if running on Windows, {@code false} otherwise. + */ + @Override + public boolean isApplicable() { + return SystemInfo.isWindows; + } + + /** + * Executes the {@code runInTerminal} request in an external Windows terminal. + * + * @param args the DAP {@link RunInTerminalRequestArguments} containing command, environment and working directory. + * @param project the current IntelliJ project context. + * @return a {@link CompletableFuture} that completes with the exit code of the spawned process. + */ + @Override + protected CompletableFuture doRunInTerminal(@NotNull RunInTerminalRequestArguments args, + @NotNull Project project) { + // Resolve the terminal executable. Fallback to default Windows terminal if not configured. + String exec = /* settings.getWindowsExec() != null ? + settings.getWindowsExec() : */ getDefaultTerminalWindows(); + + // Prepare the title and the command to be executed. + String fullTitle = "\"" + args.getTitle() + "\""; + String command = "\"" + String.join("\" \"", args.getArgs()) + "\" & pause"; + + // Prepare environment variables, removing null entries. + Map env = args.getEnv() != null ? args.getEnv() : new HashMap<>(); + env.entrySet().removeIf(e -> e.getValue() == null); + + List cmdArgs = new ArrayList<>(); + String spawnExec; + + // Detect if the configured executable is Windows Terminal (wt.exe) or a classic cmd.exe session. + if (new File(exec).getName().equalsIgnoreCase("wt.exe")) { + spawnExec = exec; + // Use Windows Terminal with cmd.exe as shell. + cmdArgs.addAll(Arrays.asList("-d", ".", CMD, "/c", command)); + } else { + spawnExec = CMD; + // Use classic cmd.exe and spawn the configured terminal as a subprocess. + cmdArgs.addAll(Arrays.asList("/c", "start", fullTitle, "/wait", exec, "/c", "\"" + command + "\"")); + } + + // Configure the process builder with working directory and environment variables. + ProcessBuilder pb = new ProcessBuilder(spawnExec); + pb.command().addAll(cmdArgs); + pb.directory(new File(args.getCwd())); + pb.environment().putAll(env); + + return runProcessAsyncWithExitCode(pb); + } + + /** + * Starts the process asynchronously and completes with its exit code when finished. + * + * @param pb the configured {@link ProcessBuilder} to launch. + * @return a {@link CompletableFuture} of the process exit code. + */ + private CompletableFuture runProcessAsyncWithExitCode(ProcessBuilder pb) { + CompletableFuture future = new CompletableFuture<>(); + try { + Process p = pb.start(); + p.onExit() + .thenAccept(pr -> future.complete(pr.exitValue())); + } catch (IOException e) { + future.completeExceptionally(e); + } + return future; + } + + /** + * Determines the default Windows terminal executable path depending on the architecture (Sysnative/System32). + *

+ * This method caches the computed path to avoid recomputing it for every invocation. + * + * @return the absolute path of the default terminal executable (cmd.exe). + */ + public static String getDefaultTerminalWindows() { + if (DEFAULT_TERMINAL_WINDOWS == null) { + boolean isWoW64 = System.getenv().containsKey("PROCESSOR_ARCHITEW6432"); + String winDir = System.getenv().getOrDefault("windir", "C:\\Windows"); + DEFAULT_TERMINAL_WINDOWS = winDir + "\\" + (isWoW64 ? "Sysnative" : "System32") + "\\cmd.exe"; + } + return DEFAULT_TERMINAL_WINDOWS; + } +} diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/integrated/RunInIntegratedTerminalService.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/integrated/RunInIntegratedTerminalService.java new file mode 100644 index 000000000..392fb93bb --- /dev/null +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/integrated/RunInIntegratedTerminalService.java @@ -0,0 +1,228 @@ +/******************************************************************************* + * Copyright (c) 2025 Red Hat, Inc. + * Distributed under license by Red Hat, Inc. All rights reserved. + * This program is made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, + * and is available at https://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + ******************************************************************************/ +package com.redhat.devtools.lsp4ij.dap.client.runInterminal.integrated; + +import com.intellij.ide.plugins.PluginManagerCore; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.extensions.PluginId; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.util.Alarm; +import com.redhat.devtools.lsp4ij.dap.client.runInterminal.RunInTerminalService; +import org.eclipse.lsp4j.debug.RunInTerminalRequestArguments; +import org.eclipse.lsp4j.debug.RunInTerminalResponse; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.terminal.ShellTerminalWidget; +import org.jetbrains.plugins.terminal.TerminalToolWindowManager; + +import java.util.Arrays; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; + +/** + * Integrated terminal implementation of {@link RunInTerminalService} for Debug Adapter Protocol (DAP). + *

+ * This service opens a new IntelliJ integrated terminal tab and executes the command specified + * by a {@link RunInTerminalRequestArguments} request. It supports injecting environment variables + * and formatting commands based on the underlying OS and shell. + *

+ * + *

Features:

+ *
    + *
  • Creates a local shell widget in the integrated terminal window.
  • + *
  • Supports PowerShell, cmd.exe, and Unix-style shells.
  • + *
  • Injects environment variables with syntax adapted to the active shell.
  • + *
  • Returns the process ID of the spawned shell through {@link RunInTerminalResponse}.
  • + *
+ * + *

+ * This service requires the IntelliJ Terminal plugin to be installed. If the plugin is missing, + * {@link #isApplicable()} returns {@code false}. + *

+ */ +public class RunInIntegratedTerminalService implements RunInTerminalService { + + /** + * Checks if the IntelliJ terminal plugin is installed and available. + * + * @return {@code true} if the terminal plugin is installed, {@code false} otherwise + */ + @Override + public boolean isApplicable() { + return isTerminalPluginInstalled(); + } + + /** + * Executes the given DAP {@code runInTerminal} request in an integrated terminal tab. + * + *

The method:

+ *
    + *
  1. Creates a new {@link ShellTerminalWidget} for the project.
  2. + *
  3. Prepares the command line with proper argument quoting and environment variable injection.
  4. + *
  5. Executes the command inside the terminal.
  6. + *
  7. Polls the terminal widget until a process ID is available, then completes the future.
  8. + *
+ * + * @param args the {@link RunInTerminalRequestArguments} containing command, working directory, + * environment variables, and title + * @param project the IntelliJ {@link Project} in which to open the integrated terminal + * @return a {@link CompletableFuture} resolving to a {@link RunInTerminalResponse} + * containing the process ID of the spawned terminal process + */ + @Override + public CompletableFuture runInTerminal(@NotNull RunInTerminalRequestArguments args, + @NotNull Project project) { + CompletableFuture future = new CompletableFuture<>(); + + ApplicationManager.getApplication().invokeLater(() -> { + try { + TerminalToolWindowManager tm = TerminalToolWindowManager.getInstance(project); + + String title = args.getTitle(); + String workingDirectory = args.getCwd(); + ShellTerminalWidget shellWidget = tm.createLocalShellWidget(workingDirectory, title); + + String command = prepareCommandWithEnv(args); + shellWidget.executeCommand(command); + + // Poll until the process PID becomes available + Alarm alarm = new Alarm(Alarm.ThreadToUse.POOLED_THREAD, project); + Runnable checkProcess = new Runnable() { + @Override + public void run() { + var tty = shellWidget.getProcessTtyConnector(); + if (tty != null) { + RunInTerminalResponse resp = new RunInTerminalResponse(); + resp.setProcessId((int) tty.getProcess().pid()); + future.complete(resp); + } else if (!future.isDone()) { + alarm.addRequest(this, 100); + } + } + }; + alarm.addRequest(checkProcess, 100); + + } catch (Exception e) { + future.completeExceptionally(e); + } + }); + + return future; + } + + /** + * Builds a full command line with environment variable injection adapted + * to the current OS and shell syntax. + *

+ * - PowerShell: {@code ${env:VAR}='value'; command}
+ * - cmd.exe: {@code set VAR=value && set VAR2=value && command}
+ * - Unix shells: {@code VAR='value' VAR2='value' command} + *

+ * + * @param args the {@link RunInTerminalRequestArguments} containing the command and environment + * @return the formatted command string + */ + private String prepareCommandWithEnv(@NotNull RunInTerminalRequestArguments args) { + String command = formatCommandArguments(args.getArgs()); + + if (args.getEnv() == null || args.getEnv().isEmpty()) { + return command; + } + + boolean isWindows = SystemInfo.isWindows; + boolean isPowerShell = isWindows && isPowerShellEnvironment(); + StringBuilder envCmd = new StringBuilder(); + + if (isPowerShell) { + args.getEnv().forEach((k, v) -> { + envCmd.append("${env:").append(k).append("}='") + .append(v.replace("'", "''")).append("'; "); + }); + envCmd.append(command); + } else if (isWindows) { + args.getEnv().forEach((k, v) -> { + envCmd.append("set ").append(k).append("=").append(v).append(" && "); + }); + envCmd.append(command); + } else { + args.getEnv().forEach((k, v) -> { + envCmd.append(k).append("='") + .append(v.replace("'", "'\"'\"'")).append("' "); + }); + envCmd.append(command); + } + + return envCmd.toString(); + } + + /** + * Formats command-line arguments for the active OS and shell. + *

+ * - PowerShell: adds call operator {@code &} and quotes paths with spaces
+ * - cmd.exe: escapes spaces with {@code ^ }
+ * - Unix: wraps arguments with spaces in single quotes + *

+ * + * @param args the array of command arguments + * @return a properly quoted and escaped command string + */ + private String formatCommandArguments(String[] args) { + boolean isWindows = SystemInfo.isWindows; + boolean isPowerShell = isWindows && isPowerShellEnvironment(); + + if (args.length == 0) { + return ""; + } + + if (isPowerShell) { + String first = args[0]; + if (first.contains(" ")) { + first = "& \"" + first + "\""; + } else { + first = "& " + first; + } + + String rest = Arrays.stream(args, 1, args.length) + .map(arg -> arg.contains(" ") ? "\"" + arg + "\"" : arg) + .collect(Collectors.joining(" ")); + + return first + (rest.isEmpty() ? "" : " " + rest); + } else if (isWindows) { + return Arrays.stream(args) + .map(arg -> arg.contains(" ") ? arg.replace(" ", "^ ") : arg) + .collect(Collectors.joining(" ")); + } else { + return Arrays.stream(args) + .map(arg -> arg.contains(" ") ? "'" + arg.replace("'", "'\"'\"'") + "'" : arg) + .collect(Collectors.joining(" ")); + } + } + + /** + * Detects whether the current environment is running under PowerShell on Windows. + * + * @return {@code true} if the environment suggests PowerShell, {@code false} otherwise + */ + private boolean isPowerShellEnvironment() { + String psModule = System.getenv("PSModulePath"); + return psModule != null && psModule.contains("PowerShell"); + } + + /** + * Checks if the IntelliJ terminal plugin is installed and available. + * + * @return {@code true} if the terminal plugin is present, {@code false} otherwise + */ + private static boolean isTerminalPluginInstalled() { + PluginId pluginId = PluginId.getId("org.jetbrains.plugins.terminal"); + return PluginManagerCore.getPlugin(pluginId) != null; + } +} From ae9fa1fb60a0243d93992aeed1822ae7b1ef2b37 Mon Sep 17 00:00:00 2001 From: azerr Date: Wed, 30 Jul 2025 15:28:08 +0200 Subject: [PATCH 006/264] fix: don't use processId for external RunInTerminal. Signed-off-by: azerr --- .../devtools/lsp4ij/dap/client/DAPClient.java | 2 +- .../LinuxExternalTerminalService.java | 141 ----------------- .../external/MacExternalTerminalService.java | 93 ----------- .../RunInTerminalManager.java | 21 +-- .../RunInTerminalService.java | 6 +- .../external/ExternalTerminalService.java | 50 ++++-- .../LinuxExternalTerminalService.java | 144 ++++++++++++++++++ .../external/MacExternalTerminalService.java | 35 +++++ .../WindowsExternalTerminalService.java | 64 +++----- .../RunInIntegratedTerminalService.java | 6 +- src/main/resources/META-INF/plugin.xml | 2 +- 11 files changed, 256 insertions(+), 308 deletions(-) delete mode 100644 src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/external/LinuxExternalTerminalService.java delete mode 100644 src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/external/MacExternalTerminalService.java rename src/main/java/com/redhat/devtools/lsp4ij/dap/{client/runInterminal => runInTerminal}/RunInTerminalManager.java (74%) rename src/main/java/com/redhat/devtools/lsp4ij/dap/{client/runInterminal => runInTerminal}/RunInTerminalService.java (94%) rename src/main/java/com/redhat/devtools/lsp4ij/dap/{client/runInterminal => runInTerminal}/external/ExternalTerminalService.java (64%) create mode 100644 src/main/java/com/redhat/devtools/lsp4ij/dap/runInTerminal/external/LinuxExternalTerminalService.java create mode 100644 src/main/java/com/redhat/devtools/lsp4ij/dap/runInTerminal/external/MacExternalTerminalService.java rename src/main/java/com/redhat/devtools/lsp4ij/dap/{client/runInterminal => runInTerminal}/external/WindowsExternalTerminalService.java (70%) rename src/main/java/com/redhat/devtools/lsp4ij/dap/{client/runInterminal => runInTerminal}/integrated/RunInIntegratedTerminalService.java (97%) diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/client/DAPClient.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/client/DAPClient.java index 48edea44f..3a336b224 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/client/DAPClient.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/client/DAPClient.java @@ -31,7 +31,7 @@ import com.redhat.devtools.lsp4ij.dap.DebugMode; import com.redhat.devtools.lsp4ij.dap.TransportStreams; import com.redhat.devtools.lsp4ij.dap.breakpoints.DAPBreakpointProperties; -import com.redhat.devtools.lsp4ij.dap.client.runInterminal.RunInTerminalManager; +import com.redhat.devtools.lsp4ij.dap.runInTerminal.RunInTerminalManager; import com.redhat.devtools.lsp4ij.dap.descriptors.DebugAdapterDescriptor; import com.redhat.devtools.lsp4ij.internal.CancellationSupport; import com.redhat.devtools.lsp4ij.internal.StringUtils; diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/external/LinuxExternalTerminalService.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/external/LinuxExternalTerminalService.java deleted file mode 100644 index c07edfe78..000000000 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/external/LinuxExternalTerminalService.java +++ /dev/null @@ -1,141 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2025 Red Hat, Inc. - * Distributed under license by Red Hat, Inc. All rights reserved. - * This program is made available under the terms of the - * Eclipse Public License v2.0 which accompanies this distribution, - * and is available at https://www.eclipse.org/legal/epl-v20.html - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - ******************************************************************************/ -package com.redhat.devtools.lsp4ij.dap.client.runInterminal.external; - -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.SystemInfo; -import org.eclipse.lsp4j.debug.RunInTerminalRequestArguments; -import org.jetbrains.annotations.NotNull; - -import java.io.File; -import java.io.IOException; -import java.util.*; -import java.util.concurrent.CompletableFuture; - -/** - * This class code is the vscode TypeScript translate from - * LinuxExternalTerminalService - */ -public class LinuxExternalTerminalService extends ExternalTerminalService { - - // List of common Linux terminals in the same order VS Code tries them - private static final String[] LINUX_TERMINALS = new String[]{ - "gnome-terminal", - "konsole", - "xfce4-terminal", - "xterm", - "lxterminal", - "mate-terminal", - "terminator", - "tilix", - "deepin-terminal", - "kitty", - "alacritty", - "x-terminal-emulator" - }; - - @Override - public boolean isApplicable() { - return SystemInfo.isLinux; - } - - @Override - protected CompletableFuture doRunInTerminal(@NotNull RunInTerminalRequestArguments args, - @NotNull Project project) { - - // TODO : reimplement this class!!! - - String terminal = findAvailableTerminal(); - if (terminal == null) { - CompletableFuture failed = new CompletableFuture<>(); - failed.completeExceptionally(new RuntimeException("No supported Linux terminal found in PATH")); - return failed; - } - - // Build the shell command like VS Code: - // bash -c "cd /cwd && ; exec bash" - String joinedArgs = String.join(" ", escapeArgs(args.getArgs())); - String fullCommand = "cd " + escapeArg(args.getCwd()) + " && " + joinedArgs + " ; exec bash"; - - List cmd = new ArrayList<>(); - cmd.add(terminal); - cmd.add("-e"); - cmd.add("bash"); - cmd.add("-c"); - cmd.add(fullCommand); - - ProcessBuilder pb = new ProcessBuilder(cmd); - pb.directory(new File(args.getCwd())); - - // Filter out null values in the environment variables - Map env = args.getEnv() != null ? args.getEnv() : new HashMap<>(); - env.entrySet().removeIf(e -> e.getValue() == null); - pb.environment().putAll(env); - - return runProcessAsyncWithExitCode(pb); - } - - /** - * Run the process asynchronously and complete the future with the exit code. - */ - private CompletableFuture runProcessAsyncWithExitCode(ProcessBuilder pb) { - CompletableFuture future = new CompletableFuture<>(); - try { - Process p = pb.start(); - p.onExit().thenAccept(pr -> future.complete(pr.exitValue())); - } catch (IOException e) { - future.completeExceptionally(e); - } - return future; - } - - /** - * Finds the first available terminal from the list in the PATH. - */ - private String findAvailableTerminal() { - for (String term : LINUX_TERMINALS) { - if (isExecutableInPath(term)) { - return term; - } - } - return null; - } - - /** - * Checks if the given executable is available in the PATH using 'which'. - */ - private boolean isExecutableInPath(String exec) { - try { - Process p = new ProcessBuilder("which", exec).start(); - return p.waitFor() == 0; - } catch (Exception e) { - return false; - } - } - - /** - * Escape arguments for safe usage inside bash -c. - */ - private List escapeArgs(String[] args) { - List escaped = new ArrayList<>(); - for (String arg : args) { - escaped.add(escapeArg(arg)); - } - return escaped; - } - - /** - * Escape a single argument by wrapping it in single quotes and handling embedded quotes. - */ - private String escapeArg(String arg) { - return "'" + arg.replace("'", "'\"'\"'") + "'"; - } -} diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/external/MacExternalTerminalService.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/external/MacExternalTerminalService.java deleted file mode 100644 index e5e474390..000000000 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/external/MacExternalTerminalService.java +++ /dev/null @@ -1,93 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2025 Red Hat, Inc. - * Distributed under license by Red Hat, Inc. All rights reserved. - * This program is made available under the terms of the - * Eclipse Public License v2.0 which accompanies this distribution, - * and is available at https://www.eclipse.org/legal/epl-v20.html - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - ******************************************************************************/ -package com.redhat.devtools.lsp4ij.dap.client.runInterminal.external; - -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.SystemInfo; -import org.eclipse.lsp4j.debug.RunInTerminalRequestArguments; -import org.jetbrains.annotations.NotNull; - -import java.io.File; -import java.io.IOException; -import java.util.*; -import java.util.concurrent.CompletableFuture; - -/** - * This class code is the vscode TypeScript translate from - * MacExternalTerminalService - */ -public class MacExternalTerminalService extends ExternalTerminalService { - - @Override - public boolean isApplicable() { - return SystemInfo.isMac; - } - - @Override - protected CompletableFuture doRunInTerminal(@NotNull RunInTerminalRequestArguments args, - @NotNull Project project) { - - // TODO : reimplement this class!!! - - // Build AppleScript command like VS Code does - String joinedArgs = String.join(" ", escapeArgs(args.getArgs())); - String fullCommand = "cd " + escapeArg(args.getCwd()) + " && " + joinedArgs; - - // AppleScript to tell Terminal to open a new window and run the command - String appleScript = "tell application \"Terminal\"\n" + - "do script \"" + fullCommand + "\"\n" + - "activate\n" + - "end tell"; - - List cmd = Arrays.asList("osascript", "-e", appleScript); - - ProcessBuilder pb = new ProcessBuilder(cmd); - pb.directory(new File(args.getCwd())); - - Map env = args.getEnv() != null ? args.getEnv() : new HashMap<>(); - env.entrySet().removeIf(e -> e.getValue() == null); - pb.environment().putAll(env); - - return runProcessAsyncWithExitCode(pb); - } - - /** - * Run the process asynchronously and complete the future with the exit code. - */ - private CompletableFuture runProcessAsyncWithExitCode(ProcessBuilder pb) { - CompletableFuture future = new CompletableFuture<>(); - try { - Process p = pb.start(); - p.onExit().thenAccept(pr -> future.complete(pr.exitValue())); - } catch (IOException e) { - future.completeExceptionally(e); - } - return future; - } - - /** - * Escape arguments for safe usage inside AppleScript/Terminal. - */ - private List escapeArgs(String[] args) { - List escaped = new ArrayList<>(); - for (String arg : args) { - escaped.add(escapeArg(arg)); - } - return escaped; - } - - /** - * Escape a single argument for safe bash usage. - */ - private String escapeArg(String arg) { - return "'" + arg.replace("'", "'\"'\"'") + "'"; - } -} diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/RunInTerminalManager.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/runInTerminal/RunInTerminalManager.java similarity index 74% rename from src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/RunInTerminalManager.java rename to src/main/java/com/redhat/devtools/lsp4ij/dap/runInTerminal/RunInTerminalManager.java index 295c4ae60..e80099329 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/RunInTerminalManager.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/runInTerminal/RunInTerminalManager.java @@ -8,31 +8,20 @@ * Contributors: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ -package com.redhat.devtools.lsp4ij.dap.client.runInterminal; +package com.redhat.devtools.lsp4ij.dap.runInTerminal; -import com.intellij.ide.plugins.PluginManagerCore; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.extensions.PluginId; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.SystemInfo; -import com.intellij.util.Alarm; -import com.redhat.devtools.lsp4ij.dap.client.runInterminal.external.LinuxExternalTerminalService; -import com.redhat.devtools.lsp4ij.dap.client.runInterminal.external.MacExternalTerminalService; -import com.redhat.devtools.lsp4ij.dap.client.runInterminal.external.WindowsExternalTerminalService; -import com.redhat.devtools.lsp4ij.dap.client.runInterminal.integrated.RunInIntegratedTerminalService; +import com.redhat.devtools.lsp4ij.dap.runInTerminal.external.LinuxExternalTerminalService; +import com.redhat.devtools.lsp4ij.dap.runInTerminal.external.MacExternalTerminalService; +import com.redhat.devtools.lsp4ij.dap.runInTerminal.external.WindowsExternalTerminalService; +import com.redhat.devtools.lsp4ij.dap.runInTerminal.integrated.RunInIntegratedTerminalService; import org.eclipse.lsp4j.debug.RunInTerminalRequestArguments; import org.eclipse.lsp4j.debug.RunInTerminalRequestArgumentsKind; import org.eclipse.lsp4j.debug.RunInTerminalResponse; -import org.eclipse.sisu.Nullable; import org.jetbrains.annotations.NotNull; -import org.jetbrains.plugins.terminal.ShellTerminalWidget; -import org.jetbrains.plugins.terminal.TerminalToolWindowManager; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; import java.util.concurrent.CompletableFuture; -import java.util.stream.Collectors; /** * Manages Debug Adapter Protocol (DAP) {@code RunInTerminal} requests, diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/RunInTerminalService.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/runInTerminal/RunInTerminalService.java similarity index 94% rename from src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/RunInTerminalService.java rename to src/main/java/com/redhat/devtools/lsp4ij/dap/runInTerminal/RunInTerminalService.java index bae9a7f43..00f699afa 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/RunInTerminalService.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/runInTerminal/RunInTerminalService.java @@ -8,7 +8,7 @@ * Contributors: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ -package com.redhat.devtools.lsp4ij.dap.client.runInterminal; +package com.redhat.devtools.lsp4ij.dap.runInTerminal; import com.intellij.openapi.project.Project; import org.eclipse.lsp4j.debug.RunInTerminalRequestArguments; @@ -48,7 +48,7 @@ public interface RunInTerminalService { *

* * @return {@code true} if this service can handle {@code runInTerminal} requests - * on the current platform, {@code false} otherwise. + * on the current platform, {@code false} otherwise. */ boolean isApplicable(); @@ -68,7 +68,7 @@ public interface RunInTerminalService { * working directory, environment variables, and terminal type * @param project the IntelliJ {@link Project} in which this terminal is being launched * @return a {@link CompletableFuture} resolving to a {@link RunInTerminalResponse} - * containing the process ID or {@code null} if not supported. + * containing the process ID or {@code null} if not supported. */ CompletableFuture runInTerminal(@NotNull RunInTerminalRequestArguments args, @NotNull Project project); diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/external/ExternalTerminalService.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/runInTerminal/external/ExternalTerminalService.java similarity index 64% rename from src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/external/ExternalTerminalService.java rename to src/main/java/com/redhat/devtools/lsp4ij/dap/runInTerminal/external/ExternalTerminalService.java index 83902d11d..5299e362f 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/external/ExternalTerminalService.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/runInTerminal/external/ExternalTerminalService.java @@ -8,15 +8,19 @@ * Contributors: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ -package com.redhat.devtools.lsp4ij.dap.client.runInterminal.external; +package com.redhat.devtools.lsp4ij.dap.runInTerminal.external; import com.intellij.openapi.project.Project; -import com.redhat.devtools.lsp4ij.dap.client.runInterminal.RunInTerminalService; +import com.redhat.devtools.lsp4ij.dap.runInTerminal.RunInTerminalService; import org.eclipse.lsp4j.debug.RunInTerminalRequestArguments; import org.eclipse.lsp4j.debug.RunInTerminalResponse; import org.jetbrains.annotations.NotNull; +import java.io.File; +import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; /** * Base class for external terminal services that handle Debug Adapter Protocol @@ -49,17 +53,14 @@ public abstract class ExternalTerminalService implements RunInTerminalService { * working directory, environment variables, and terminal kind * @param project the IntelliJ {@link Project} in which this terminal is being launched * @return a {@link CompletableFuture} that resolves to a {@link RunInTerminalResponse} - * containing the process ID of the spawned terminal process. + * containing the process ID of the spawned terminal process. */ @Override public CompletableFuture runInTerminal(@NotNull RunInTerminalRequestArguments args, @NotNull Project project) { + return doRunInTerminal(args, project) - .thenApply(pid -> { - RunInTerminalResponse response = new RunInTerminalResponse(); - response.setProcessId(pid); - return response; - }); + .thenApply(unused -> new RunInTerminalResponse()); } /** @@ -72,8 +73,35 @@ public CompletableFuture runInTerminal(@NotNull RunInTerm * * @param args the {@link RunInTerminalRequestArguments} with the command and environment settings * @param project the IntelliJ {@link Project} context - * @return a {@link CompletableFuture} resolving to the process ID of the spawned terminal + * @return a {@link CompletableFuture} resolving the spawned terminal */ - protected abstract CompletableFuture doRunInTerminal(@NotNull RunInTerminalRequestArguments args, - @NotNull Project project); + protected abstract CompletableFuture doRunInTerminal(@NotNull RunInTerminalRequestArguments args, + @NotNull Project project); + + protected @NotNull ProcessBuilder createProcessBuilder(@NotNull RunInTerminalRequestArguments args, + @NotNull Function<@NotNull RunInTerminalRequestArguments, @NotNull List> commandBuilder) { + + // Configure the process builder with working directory and environment variables. + ProcessBuilder pb = new ProcessBuilder(commandBuilder.apply(args)); + if (args.getCwd() != null) { + pb.directory(new File(args.getCwd())); + } + if (args.getEnv() != null) { + pb.environment().putAll(args.getEnv()); + } + return pb; + } + + protected static Process startProcess(ProcessBuilder pb, long timeout) { + try { + var p = pb.start(); + if (timeout > 0) { + p.waitFor(timeout, TimeUnit.MILLISECONDS); + } + return p; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/runInTerminal/external/LinuxExternalTerminalService.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/runInTerminal/external/LinuxExternalTerminalService.java new file mode 100644 index 000000000..ddcd145f9 --- /dev/null +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/runInTerminal/external/LinuxExternalTerminalService.java @@ -0,0 +1,144 @@ +/******************************************************************************* + * Copyright (c) 2025 Red Hat, Inc. + * Distributed under license by Red Hat, Inc. All rights reserved. + * This program is made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, + * and is available at https://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + ******************************************************************************/ +package com.redhat.devtools.lsp4ij.dap.runInTerminal.external; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.SystemInfo; +import org.eclipse.lsp4j.debug.RunInTerminalRequestArguments; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +/** + * This class code is the vscode TypeScript translate from + * LinuxExternalTerminalService + */ +public class LinuxExternalTerminalService extends ExternalTerminalService { + + // List of common Linux terminals in the same order VS Code tries them + private static final String[] LINUX_TERMINALS = new String[]{ + "gnome-terminal", + "konsole", + "xfce4-terminal", + "xterm", + "lxterminal", + "mate-terminal", + "terminator", + "tilix", + "deepin-terminal", + "kitty", + "alacritty", + "x-terminal-emulator" + }; + + @Override + public boolean isApplicable() { + return SystemInfo.isLinux; + } + + /** + * Executes the {@code runInTerminal} request in an external Windows terminal. + * + * @param args the DAP {@link RunInTerminalRequestArguments} containing command, environment and working directory. + * @param project the current IntelliJ project context. + * @return a {@link CompletableFuture} that completes with the spawned process. + */ + @Override + protected CompletableFuture doRunInTerminal(@NotNull RunInTerminalRequestArguments args, + @NotNull Project project) { + CompletableFuture result = new CompletableFuture<>(); + CompletableFuture.supplyAsync(() -> { + // Configure the process builder with working directory and environment variables. + ProcessBuilder pb = createProcessBuilder(args, LinuxExternalTerminalService::createCommands); + return startProcess(pb, 0); + }).handle((process, error) -> { + if (process == null || error != null) { + result.completeExceptionally(error); + } else { + process.onExit().thenRun(() -> { + if (process.exitValue() == 0) { + result.complete(null); + } else { + result.completeExceptionally(new RuntimeException("Linux terminal failed with exit code " + process.exitValue())); + } + }); + } + return null; + }); + return result; + } + + private static @NotNull List createCommands(@NotNull RunInTerminalRequestArguments args) { + String terminal = findAvailableTerminal(); + if (terminal == null) { + throw new RuntimeException("No supported Linux terminal found in PATH"); + } + + List termArgs = new ArrayList<>(); + if (terminal.contains("gnome-terminal")) { + termArgs.add("-x"); + } else { + termArgs.add("-e"); + } + + termArgs.add("bash"); + termArgs.add("-c"); + + String bashCommand = quote(args.getArgs()) + "; echo; read -p \"" + + "Press any key to continue..." + "\" -n1;"; + // wrapping argument in two sets of ' because node is so "friendly" that it removes one set... + termArgs.add("''" + bashCommand + "''"); + return termArgs; + } + + /** + * Finds the first available terminal from the list in the PATH. + */ + private static String findAvailableTerminal() { + for (String term : LINUX_TERMINALS) { + if (isExecutableInPath(term)) { + return term; + } + } + return null; + } + + /** + * Checks if the given executable is available in the PATH using 'which'. + */ + private static boolean isExecutableInPath(String exec) { + try { + Process p = new ProcessBuilder("which", exec).start(); + return p.waitFor() == 0; + } catch (Exception e) { + return false; + } + } + + /** + * Quote args if necessary and combine into a space separated string. + */ + private static String quote(String[] args) { + StringBuilder r = new StringBuilder(); + for (String a : args) { + if (a.contains(" ")) { + r.append('"').append(a).append('"'); + } else { + r.append(a); + } + r.append(' '); + } + return r.toString().trim(); + } + +} diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/runInTerminal/external/MacExternalTerminalService.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/runInTerminal/external/MacExternalTerminalService.java new file mode 100644 index 000000000..e70a1c94a --- /dev/null +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/runInTerminal/external/MacExternalTerminalService.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2025 Red Hat, Inc. + * Distributed under license by Red Hat, Inc. All rights reserved. + * This program is made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, + * and is available at https://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + ******************************************************************************/ +package com.redhat.devtools.lsp4ij.dap.runInTerminal.external; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.SystemInfo; +import org.eclipse.lsp4j.debug.RunInTerminalRequestArguments; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.CompletableFuture; + +/** + * This class code is the vscode TypeScript translate from + * MacExternalTerminalService + */ +public class MacExternalTerminalService extends ExternalTerminalService { + + @Override + public boolean isApplicable() { + return SystemInfo.isMac; + } + + @Override + protected CompletableFuture doRunInTerminal(@NotNull RunInTerminalRequestArguments args, @NotNull Project project) { + return CompletableFuture.failedFuture(new UnsupportedOperationException("MacExternalTerminalService not implemented")); + } +} diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/external/WindowsExternalTerminalService.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/runInTerminal/external/WindowsExternalTerminalService.java similarity index 70% rename from src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/external/WindowsExternalTerminalService.java rename to src/main/java/com/redhat/devtools/lsp4ij/dap/runInTerminal/external/WindowsExternalTerminalService.java index d6e1983c6..cba573c9f 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/external/WindowsExternalTerminalService.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/runInTerminal/external/WindowsExternalTerminalService.java @@ -8,7 +8,7 @@ * Contributors: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ -package com.redhat.devtools.lsp4ij.dap.client.runInterminal.external; +package com.redhat.devtools.lsp4ij.dap.runInTerminal.external; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.SystemInfo; @@ -16,8 +16,9 @@ import org.jetbrains.annotations.NotNull; import java.io.File; -import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.concurrent.CompletableFuture; /** @@ -34,10 +35,14 @@ */ public class WindowsExternalTerminalService extends ExternalTerminalService { - /** Default Windows command-line interpreter. */ + /** + * Default Windows command-line interpreter. + */ private static final String CMD = "cmd.exe"; - /** Cached default terminal path to avoid recomputing. */ + /** + * Cached default terminal path to avoid recomputing. + */ private static String DEFAULT_TERMINAL_WINDOWS; /** @@ -55,23 +60,28 @@ public boolean isApplicable() { * * @param args the DAP {@link RunInTerminalRequestArguments} containing command, environment and working directory. * @param project the current IntelliJ project context. - * @return a {@link CompletableFuture} that completes with the exit code of the spawned process. + * @return a {@link CompletableFuture} that completes with the spawned process. */ @Override - protected CompletableFuture doRunInTerminal(@NotNull RunInTerminalRequestArguments args, - @NotNull Project project) { + protected CompletableFuture doRunInTerminal(@NotNull RunInTerminalRequestArguments args, + @NotNull Project project) { + return CompletableFuture.supplyAsync(() -> { + // Configure the process builder with working directory and environment variables. + ProcessBuilder pb = createProcessBuilder(args, WindowsExternalTerminalService::createCommands); + startProcess(pb, 1000); + return null; + }); + } + + private static @NotNull List createCommands(@NotNull RunInTerminalRequestArguments args) { // Resolve the terminal executable. Fallback to default Windows terminal if not configured. String exec = /* settings.getWindowsExec() != null ? - settings.getWindowsExec() : */ getDefaultTerminalWindows(); + settings.getWindowsExec() : */ getDefaultTerminalWindows(); // Prepare the title and the command to be executed. String fullTitle = "\"" + args.getTitle() + "\""; String command = "\"" + String.join("\" \"", args.getArgs()) + "\" & pause"; - // Prepare environment variables, removing null entries. - Map env = args.getEnv() != null ? args.getEnv() : new HashMap<>(); - env.entrySet().removeIf(e -> e.getValue() == null); - List cmdArgs = new ArrayList<>(); String spawnExec; @@ -85,32 +95,8 @@ protected CompletableFuture doRunInTerminal(@NotNull RunInTerminalReque // Use classic cmd.exe and spawn the configured terminal as a subprocess. cmdArgs.addAll(Arrays.asList("/c", "start", fullTitle, "/wait", exec, "/c", "\"" + command + "\"")); } - - // Configure the process builder with working directory and environment variables. - ProcessBuilder pb = new ProcessBuilder(spawnExec); - pb.command().addAll(cmdArgs); - pb.directory(new File(args.getCwd())); - pb.environment().putAll(env); - - return runProcessAsyncWithExitCode(pb); - } - - /** - * Starts the process asynchronously and completes with its exit code when finished. - * - * @param pb the configured {@link ProcessBuilder} to launch. - * @return a {@link CompletableFuture} of the process exit code. - */ - private CompletableFuture runProcessAsyncWithExitCode(ProcessBuilder pb) { - CompletableFuture future = new CompletableFuture<>(); - try { - Process p = pb.start(); - p.onExit() - .thenAccept(pr -> future.complete(pr.exitValue())); - } catch (IOException e) { - future.completeExceptionally(e); - } - return future; + cmdArgs.add(0, spawnExec); + return cmdArgs; } /** diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/integrated/RunInIntegratedTerminalService.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/runInTerminal/integrated/RunInIntegratedTerminalService.java similarity index 97% rename from src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/integrated/RunInIntegratedTerminalService.java rename to src/main/java/com/redhat/devtools/lsp4ij/dap/runInTerminal/integrated/RunInIntegratedTerminalService.java index 392fb93bb..e40bc0ad9 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/client/runInterminal/integrated/RunInIntegratedTerminalService.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/runInTerminal/integrated/RunInIntegratedTerminalService.java @@ -8,7 +8,7 @@ * Contributors: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ -package com.redhat.devtools.lsp4ij.dap.client.runInterminal.integrated; +package com.redhat.devtools.lsp4ij.dap.runInTerminal.integrated; import com.intellij.ide.plugins.PluginManagerCore; import com.intellij.openapi.application.ApplicationManager; @@ -16,7 +16,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.SystemInfo; import com.intellij.util.Alarm; -import com.redhat.devtools.lsp4ij.dap.client.runInterminal.RunInTerminalService; +import com.redhat.devtools.lsp4ij.dap.runInTerminal.RunInTerminalService; import org.eclipse.lsp4j.debug.RunInTerminalRequestArguments; import org.eclipse.lsp4j.debug.RunInTerminalResponse; import org.jetbrains.annotations.NotNull; @@ -75,7 +75,7 @@ public boolean isApplicable() { * environment variables, and title * @param project the IntelliJ {@link Project} in which to open the integrated terminal * @return a {@link CompletableFuture} resolving to a {@link RunInTerminalResponse} - * containing the process ID of the spawned terminal process + * containing the process ID of the spawned terminal process */ @Override public CompletableFuture runInTerminal(@NotNull RunInTerminalRequestArguments args, diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index a4591e33e..fe2b4c483 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -972,7 +972,7 @@ + serviceImplementation="com.redhat.devtools.lsp4ij.dap.runInTerminal.RunInTerminalManager"/> Date: Wed, 30 Jul 2025 22:57:38 +0200 Subject: [PATCH 007/264] feat: show external runInTerminal error Signed-off-by: azerr --- .../external/ExternalTerminalService.java | 3 ++- .../LinuxExternalTerminalService.java | 13 ++++++++--- .../ResponseErrorExceptionWrapper.java | 23 ++++++++++++------- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/runInTerminal/external/ExternalTerminalService.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/runInTerminal/external/ExternalTerminalService.java index 5299e362f..63ffeed93 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/runInTerminal/external/ExternalTerminalService.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/runInTerminal/external/ExternalTerminalService.java @@ -12,6 +12,7 @@ import com.intellij.openapi.project.Project; import com.redhat.devtools.lsp4ij.dap.runInTerminal.RunInTerminalService; +import com.redhat.devtools.lsp4ij.internal.ResponseErrorExceptionWrapper; import org.eclipse.lsp4j.debug.RunInTerminalRequestArguments; import org.eclipse.lsp4j.debug.RunInTerminalResponse; import org.jetbrains.annotations.NotNull; @@ -100,7 +101,7 @@ protected static Process startProcess(ProcessBuilder pb, long timeout) { } return p; } catch (Exception e) { - throw new RuntimeException(e); + throw new ResponseErrorExceptionWrapper(e); } } diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/runInTerminal/external/LinuxExternalTerminalService.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/runInTerminal/external/LinuxExternalTerminalService.java index ddcd145f9..11086461c 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/runInTerminal/external/LinuxExternalTerminalService.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/runInTerminal/external/LinuxExternalTerminalService.java @@ -12,7 +12,9 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.SystemInfo; +import com.redhat.devtools.lsp4ij.internal.ResponseErrorExceptionWrapper; import org.eclipse.lsp4j.debug.RunInTerminalRequestArguments; +import org.eclipse.lsp4j.jsonrpc.ResponseErrorException; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -63,13 +65,17 @@ protected CompletableFuture doRunInTerminal(@NotNull RunInTerminalRequestA return startProcess(pb, 0); }).handle((process, error) -> { if (process == null || error != null) { - result.completeExceptionally(error); + if (error instanceof ResponseErrorException) { + result.completeExceptionally(error); + } else { + result.completeExceptionally(new ResponseErrorExceptionWrapper(error)); + } } else { process.onExit().thenRun(() -> { if (process.exitValue() == 0) { result.complete(null); } else { - result.completeExceptionally(new RuntimeException("Linux terminal failed with exit code " + process.exitValue())); + result.completeExceptionally(new ResponseErrorExceptionWrapper("Linux terminal failed with exit code " + process.exitValue())); } }); } @@ -81,7 +87,7 @@ protected CompletableFuture doRunInTerminal(@NotNull RunInTerminalRequestA private static @NotNull List createCommands(@NotNull RunInTerminalRequestArguments args) { String terminal = findAvailableTerminal(); if (terminal == null) { - throw new RuntimeException("No supported Linux terminal found in PATH"); + throw new ResponseErrorExceptionWrapper("No supported Linux terminal found in PATH"); } List termArgs = new ArrayList<>(); @@ -98,6 +104,7 @@ protected CompletableFuture doRunInTerminal(@NotNull RunInTerminalRequestA + "Press any key to continue..." + "\" -n1;"; // wrapping argument in two sets of ' because node is so "friendly" that it removes one set... termArgs.add("''" + bashCommand + "''"); + termArgs.add(0, terminal); return termArgs; } diff --git a/src/main/java/com/redhat/devtools/lsp4ij/internal/ResponseErrorExceptionWrapper.java b/src/main/java/com/redhat/devtools/lsp4ij/internal/ResponseErrorExceptionWrapper.java index 7a54f5018..4d6055009 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/internal/ResponseErrorExceptionWrapper.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/internal/ResponseErrorExceptionWrapper.java @@ -14,6 +14,7 @@ import org.eclipse.lsp4j.jsonrpc.messages.ResponseError; import org.eclipse.lsp4j.jsonrpc.messages.ResponseErrorCode; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.ByteArrayOutputStream; import java.io.PrintWriter; @@ -21,28 +22,34 @@ /** * LSP4J Response error wrapper. */ -public class ResponseErrorExceptionWrapper extends ResponseErrorException { +public class ResponseErrorExceptionWrapper extends ResponseErrorException { public ResponseErrorExceptionWrapper(@NotNull Throwable throwable) { super(toResponseError(throwable.getMessage(), throwable)); } + public ResponseErrorExceptionWrapper(@NotNull String message) { + this(message, null); + } + public ResponseErrorExceptionWrapper(@NotNull String message, - @NotNull Throwable throwable) { + @Nullable Throwable throwable) { super(toResponseError(message, throwable)); } @NotNull private static ResponseError toResponseError(@NotNull String message, - @NotNull Throwable throwable) { + @Nullable Throwable throwable) { ResponseError error = new ResponseError(); error.setMessage(message); error.setCode(ResponseErrorCode.InternalError); - ByteArrayOutputStream stackTrace = new ByteArrayOutputStream(); - PrintWriter stackTraceWriter = new PrintWriter(stackTrace); - throwable.printStackTrace(stackTraceWriter); - stackTraceWriter.flush(); - error.setData(stackTrace.toString()); + if (throwable != null) { + ByteArrayOutputStream stackTrace = new ByteArrayOutputStream(); + PrintWriter stackTraceWriter = new PrintWriter(stackTrace); + throwable.printStackTrace(stackTraceWriter); + stackTraceWriter.flush(); + error.setData(stackTrace.toString()); + } return error; } } From 2fde386a8ebf416bf7bae53c0c21eb19920a02fc Mon Sep 17 00:00:00 2001 From: azerr Date: Thu, 31 Jul 2025 10:24:15 +0200 Subject: [PATCH 008/264] feat: Provide extension point to declare a DAP server See #838 Signed-off-by: azerr --- .../devtools/lsp4ij/dap/DAPDebugProcess.java | 11 +- .../devtools/lsp4ij/dap/DAPDebugRunner.java | 3 +- .../lsp4ij/dap/DebugAdapterManager.java | 30 +- .../dap/breakpoints/DAPBreakpointHandler.java | 387 +--------------- .../breakpoints/DAPBreakpointHandlerBase.java | 424 ++++++++++++++++++ .../dap/breakpoints/DAPBreakpointType.java | 32 +- .../breakpoints/DAPBreakpointTypeBase.java | 67 +++ .../DAPExceptionBreakpointsPanel.java | 4 +- .../devtools/lsp4ij/dap/client/DAPClient.java | 2 +- ...ionType.java => DAPConfigurationType.java} | 74 +-- .../configurations/DAPRunConfiguration.java | 54 +-- .../DAPRunConfigurationBase.java | 73 +++ .../DAPRunConfigurationOptions.java | 15 +- .../DAPRunConfigurationProvider.java | 2 +- .../attach/DAPAttachRunConfiguration.java | 73 +++ .../DAPAttachRunConfigurationOptions.java | 49 ++ .../attach/DAPAttachSettingsEditor.java | 86 ++++ .../options/AttachConfigurable.java | 28 ++ .../descriptors/DebugAdapterDescriptor.java | 32 +- .../DebugAdapterDescriptorFactory.java | 20 +- .../DefaultDebugAdapterDescriptor.java | 34 +- src/main/resources/META-INF/plugin.xml | 2 +- 22 files changed, 964 insertions(+), 538 deletions(-) create mode 100644 src/main/java/com/redhat/devtools/lsp4ij/dap/breakpoints/DAPBreakpointHandlerBase.java create mode 100644 src/main/java/com/redhat/devtools/lsp4ij/dap/breakpoints/DAPBreakpointTypeBase.java rename src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/{DAPRunConfigurationType.java => DAPConfigurationType.java} (78%) create mode 100644 src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfigurationBase.java create mode 100644 src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/attach/DAPAttachRunConfiguration.java create mode 100644 src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/attach/DAPAttachRunConfigurationOptions.java create mode 100644 src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/attach/DAPAttachSettingsEditor.java create mode 100644 src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/options/AttachConfigurable.java diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/DAPDebugProcess.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/DAPDebugProcess.java index ce8f37a62..842dc4c1f 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/DAPDebugProcess.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/DAPDebugProcess.java @@ -31,11 +31,14 @@ import com.intellij.xdebugger.XDebugSession; import com.intellij.xdebugger.XSourcePosition; import com.intellij.xdebugger.breakpoints.XBreakpointHandler; +import com.intellij.xdebugger.breakpoints.XBreakpointProperties; +import com.intellij.xdebugger.breakpoints.XLineBreakpoint; import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider; import com.intellij.xdebugger.frame.XStackFrame; import com.intellij.xdebugger.frame.XSuspendContext; import com.intellij.xdebugger.ui.XDebugTabLayouter; -import com.redhat.devtools.lsp4ij.dap.breakpoints.DAPBreakpointHandler; +import com.redhat.devtools.lsp4ij.dap.breakpoints.DAPBreakpointHandlerBase; +import com.redhat.devtools.lsp4ij.dap.breakpoints.DAPBreakpointProperties; import com.redhat.devtools.lsp4ij.dap.breakpoints.DAPExceptionBreakpointsPanel; import com.redhat.devtools.lsp4ij.dap.client.DAPClient; import com.redhat.devtools.lsp4ij.dap.client.DAPStackFrame; @@ -78,7 +81,7 @@ private enum Status { private final @NotNull DAPCommandLineState dapState; private final @NotNull ExecutionResult executionResult; private final @NotNull XDebuggerEditorsProvider editorsProvider; - private final @NotNull DAPBreakpointHandler breakpointHandler; + private final @NotNull DAPBreakpointHandlerBase breakpointHandler; private final @NotNull DebugAdapterDescriptor serverDescriptor; private final @NotNull DAPServerReadyTracker serverReadyFuture; private @Nullable CompletableFuture connectToServerFuture; @@ -100,7 +103,7 @@ public DAPDebugProcess(@NotNull DAPCommandLineState dapState, this.executionResult = executionResult; this.editorsProvider = new DAPDebuggerEditorsProvider(dapState.getFileType(), this); this.serverDescriptor = dapState.getServerDescriptor(); - this.breakpointHandler = new DAPBreakpointHandler(session, serverDescriptor, project); + this.breakpointHandler = serverDescriptor.createBreakpointHandler(session, project); this.threadsPanel = new ThreadsPanel(this); this.status = Status.NONE; @@ -367,7 +370,7 @@ public void print(@Nullable String message, @NotNull ConsoleViewContentType type return new XBreakpointHandler[]{breakpointHandler}; } - public @NotNull DAPBreakpointHandler getBreakpointHandler() { + public @NotNull DAPBreakpointHandlerBase getBreakpointHandler() { return breakpointHandler; } diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/DAPDebugRunner.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/DAPDebugRunner.java index cf91339ba..1a09719d9 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/DAPDebugRunner.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/DAPDebugRunner.java @@ -30,6 +30,7 @@ import com.intellij.xdebugger.XDebuggerManager; import com.redhat.devtools.lsp4ij.dap.configurations.DAPCommandLineState; import com.redhat.devtools.lsp4ij.dap.configurations.DAPRunConfiguration; +import com.redhat.devtools.lsp4ij.dap.configurations.DAPRunConfigurationBase; import com.redhat.devtools.lsp4ij.installation.CommandLineUpdater; import com.redhat.devtools.lsp4ij.installation.ConsoleProvider; import com.redhat.devtools.lsp4ij.installation.ServerInstallationStatus; @@ -62,7 +63,7 @@ public class DAPDebugRunner extends AsyncProgramRunner { */ @Override public boolean canRun(@NotNull String executorId, @NotNull RunProfile profile) { - return profile instanceof DAPRunConfiguration dap && dap.canRun(executorId); + return profile instanceof DAPRunConfigurationBase dap && dap.canRun(executorId); } /** diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/DebugAdapterManager.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/DebugAdapterManager.java index 4359dea7f..3589b9597 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/DebugAdapterManager.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/DebugAdapterManager.java @@ -18,6 +18,7 @@ import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.xdebugger.breakpoints.XBreakpointType; import com.redhat.devtools.lsp4ij.dap.configurations.DAPRunConfiguration; import com.redhat.devtools.lsp4ij.dap.configurations.DebuggableFile; import com.redhat.devtools.lsp4ij.dap.definitions.DebugAdapterServerDefinition; @@ -285,8 +286,14 @@ public void handleChangeEvent(DebugAdapterServerListener.ChangedEvent event) { @Override public boolean isDebuggableFile(@NotNull VirtualFile file, @NotNull Project project) { + return isDebuggableFile(file, null, project); + } + + public boolean isDebuggableFile(@NotNull VirtualFile file, + @Nullable XBreakpointType breakpointType, + @NotNull Project project) { // Search canDebug inside the factories - if (findDebugAdapterServerFor(file, project) != null) { + if (findDebugAdapterServerFor(file, breakpointType, project) != null) { return true; } @@ -294,6 +301,27 @@ public boolean isDebuggableFile(@NotNull VirtualFile file, return findExistingConfigurationFor(file, project, false) != null; } + /** + * Returns the DAP descriptor factory for the given file and null otherwise. + * + * @param file the file. + * @param breakpointType the breakpoint toe and null otherwise. + * @param project the project. + * @return the DAP descriptor factory for the given file and null otherwise. + */ + @Nullable + private DebugAdapterServerDefinition findDebugAdapterServerFor(@NotNull VirtualFile file, + @Nullable XBreakpointType breakpointType, + @NotNull Project project) { + for (var serverDefinition : serverDefinitions.values()) { + var factory = serverDefinition.getFactory(); + if (factory.isDebuggableFile(file, project) && (breakpointType == null || factory.supportsBreakpointType(breakpointType))) { + return serverDefinition; + } + } + return null; + } + /** * Returns the existing run configuration for the given file and null otherwise. * diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/breakpoints/DAPBreakpointHandler.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/breakpoints/DAPBreakpointHandler.java index 5b61d1627..ec499041d 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/breakpoints/DAPBreakpointHandler.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/breakpoints/DAPBreakpointHandler.java @@ -20,6 +20,7 @@ import com.intellij.xdebugger.XSourcePosition; import com.intellij.xdebugger.breakpoints.XBreakpoint; import com.intellij.xdebugger.breakpoints.XBreakpointHandler; +import com.intellij.xdebugger.breakpoints.XBreakpointType; import com.intellij.xdebugger.breakpoints.XLineBreakpoint; import com.redhat.devtools.lsp4ij.dap.descriptors.DebugAdapterDescriptor; import org.eclipse.lsp4j.debug.*; @@ -35,389 +36,11 @@ import static com.redhat.devtools.lsp4ij.dap.DAPIJUtils.*; /** - * Debug Adapter Protocol (DAP) breakpoint handler. + * Debug Adapter Protocol (DAP) breakpoint handler which is working with {@link DAPBreakpointType}. */ -public class DAPBreakpointHandler extends XBreakpointHandler> implements Disposable { +public class DAPBreakpointHandler extends DAPBreakpointHandlerBase> { - private static final @NotNull Key DAP_BREAKPOINT_ID = Key.create("dap.breakpoint.id"); - private static final SourceBreakpoint[] EMPTY_SOURCE_BREAKPOINTS = new SourceBreakpoint[0]; - public static final CompletableFuture[] EMPTY_COMPLETABLE_FUTURES = new CompletableFuture[0]; - - private final @NotNull XDebugSession debugSession; - private final @NotNull DebugAdapterDescriptor debugAdapterDescriptor; - private final @NotNull Project project; - private final List debugProtocolServers = ContainerUtil.createConcurrentList(); - private @Nullable Capabilities capabilities; - private final List> breakpoints = ContainerUtil.createConcurrentList(); - private final @NotNull DAPExceptionBreakpointsPanel exceptionBreakpointsPanel; - - private record TemporaryBreakpoint(@NotNull XSourcePosition sourcePosition, boolean add) { - } - - public DAPBreakpointHandler(@NotNull XDebugSession debugSession, - @NotNull DebugAdapterDescriptor debugAdapterDescriptor, - @NotNull Project project) { - super(DAPBreakpointType.class); - this.debugSession = debugSession; - this.debugAdapterDescriptor = debugAdapterDescriptor; - this.project = project; - this.exceptionBreakpointsPanel = new DAPExceptionBreakpointsPanel(this); - } - - @Override - public void registerBreakpoint(@NotNull XLineBreakpoint breakpoint) { - if (!(breakpoint.isEnabled() && - supportsBreakpoint(breakpoint))) { - return; - } - - breakpoints.add(breakpoint); - sendBreakpoints(null, null); - } - - @Override - public void unregisterBreakpoint(@NotNull XLineBreakpoint breakpoint, - boolean temporary) { - var sourcePosition = breakpoint.getSourcePosition(); - if (!supportsBreakpoint(breakpoint) || sourcePosition == null) { - return; - } - breakpoints.remove(breakpoint); - sendBreakpoints(null, - new TemporaryBreakpoint(sourcePosition, false)); - } - - public CompletableFuture<@Nullable Void> initialize(@NotNull IDebugProtocolServer debugProtocolServer, - @Nullable Capabilities capabilities) { - this.debugProtocolServers.add(debugProtocolServer); - this.capabilities = capabilities; - return sendBreakpoints(debugProtocolServer, null); - } - - private CompletableFuture<@Nullable Void> sendBreakpoints(@Nullable IDebugProtocolServer debugProtocolServer, - @Nullable TemporaryBreakpoint temporaryBreakpoint) { - if (debugProtocolServers.isEmpty()) { - return CompletableFuture.completedFuture(null); - } - - // Convert list of IJ XBreakpoint -> LSP SourceBreakpoint - Map> targetBreakpoints = new HashMap<>(); - for (XBreakpoint breakpoint : breakpoints) { - var sourcePosition = breakpoint.getSourcePosition(); - if (sourcePosition != null) { - addSourceBreakpoint(sourcePosition, breakpoint.getConditionExpression(), targetBreakpoints); - } - } - - if (temporaryBreakpoint != null) { - if (temporaryBreakpoint.add()) { - addSourceBreakpoint(temporaryBreakpoint.sourcePosition(), null, targetBreakpoints); - } else { - // Removed IntelliJ breakpoint - // Create a Source with empty source breakpoints if it doesn't exist, - // in order to disable removed breakpoint - // if the source contained only this breakpoint. - Source source = toDAPSource(temporaryBreakpoint.sourcePosition()); - targetBreakpoints - .computeIfAbsent(source, s -> new ArrayList<>()); - } - } - - final var setBreakpointsFutures = new ArrayList>(); - for (Iterator>> iterator = targetBreakpoints.entrySet() - .iterator(); iterator.hasNext(); ) { - Map.Entry> entry = iterator.next(); - - Source source = entry.getKey(); - List sourceBreakpoints = entry.getValue(); - - // Call 'setBreakpoints' DAP request for each Source keys. - final var arguments = getSetBreakpointsArguments(source, sourceBreakpoints); - if (debugProtocolServer != null) { - // Call 'setBreakpoints' DAP request for each Source keys - // and the given debug protocol server - setBreakpointsFutures.add(setBreakpoints(debugProtocolServer, arguments)); - } else { - // Call 'setBreakpoints' DAP request for each Source keys - // for each registered debug protocol server - for (var server : debugProtocolServers) { - setBreakpointsFutures.add(setBreakpoints(server, arguments)); - } - } - - // Once we told adapter there are no breakpoints for a source file, we can stop - // tracking that file - if (sourceBreakpoints.isEmpty()) { - iterator.remove(); - } - } - return CompletableFuture.allOf(setBreakpointsFutures.toArray(EMPTY_COMPLETABLE_FUTURES)); - } - - private static @NotNull SetBreakpointsArguments getSetBreakpointsArguments(@NotNull Source source, - @NotNull List sourceBreakpoints) { - int[] lines = sourceBreakpoints - .stream() - .mapToInt(SourceBreakpoint::getLine) - .toArray(); - - final var arguments = new SetBreakpointsArguments(); - arguments.setSource(source); - arguments.setLines(lines); - arguments.setBreakpoints(sourceBreakpoints.toArray(EMPTY_SOURCE_BREAKPOINTS)); - arguments.setSourceModified(false); - return arguments; - } - - private CompletableFuture setBreakpoints(@NotNull IDebugProtocolServer debugProtocolServer, - @NotNull SetBreakpointsArguments arguments) { - CompletableFuture future = debugProtocolServer.setBreakpoints(arguments); - return future - .thenAccept(response -> { - var breakpoints = response.getBreakpoints(); - if (breakpoints == null) { - return; - } - for (int i = 0; i < breakpoints.length; i++) { - Breakpoint breakpointResponse = breakpoints[i]; - Source source = breakpointResponse.getSource(); - if (source == null) { - source = arguments.getSource(); - } - Integer line = breakpointResponse.getLine(); - if (line == null && arguments.getBreakpoints().length > i) { - var sourceBreakpoint = arguments.getBreakpoints()[i]; - line = sourceBreakpoint.getLine(); - } - if (source != null && line != null) { - var ijBreakpoint = findBreakpoint(source, line); - if (ijBreakpoint != null) { - ijBreakpoint.putUserData(DAP_BREAKPOINT_ID, breakpointResponse.getId()); - updateBreakpoint(breakpointResponse, ijBreakpoint); - } - } - } - }); - } - - private static void addSourceBreakpoint(@NotNull XSourcePosition sourcePosition, - @Nullable XExpression conditionExpression, - @NotNull Map> targetBreakpoints) { - Source source = toDAPSource(sourcePosition); - int lineNumber = getLineNumber(sourcePosition); - SourceBreakpoint sourceBreakpoint = new SourceBreakpoint(); - sourceBreakpoint.setLine(lineNumber); - if (conditionExpression != null) { - // Breakpoint with condition - sourceBreakpoint.setCondition(conditionExpression.getExpression()); - } - List sourceBreakpoints = targetBreakpoints - .computeIfAbsent(source, s -> new ArrayList<>()); - sourceBreakpoints.add(sourceBreakpoint); - } - - private static @NotNull Source toDAPSource(@NotNull XSourcePosition sourcePosition) { - Source source = new Source(); - source.setPath(getFilePath(sourcePosition.getFile())); - source.setName(getFileName(sourcePosition.getFile())); - return source; - } - - /** - * Register the given source position as temporary breakpoint. - * - * @param sourcePosition the temporary breakpoint. - * @return the completable future. - */ - public CompletableFuture<@Nullable Void> registerTemporaryBreakpoint(@NotNull XSourcePosition sourcePosition) { - return sendBreakpoints(null, new TemporaryBreakpoint(sourcePosition, true)); - } - - /** - * Un-register the given source position as temporary breakpoint. - * - * @param sourcePosition the temporary breakpoint. - * @return the completable future. - */ - public CompletableFuture<@Nullable Void> unregisterTemporaryBreakpoint(@NotNull XSourcePosition sourcePosition) { - return sendBreakpoints(null, new TemporaryBreakpoint(sourcePosition, false)); - } - - /** - * Returns whether this target can install the given breakpoint. - * - * @param breakpoint breakpoint to consider - * @return whether this target can install the given breakpoint - */ - public boolean supportsBreakpoint(XBreakpoint breakpoint) { - if (!(breakpoint.getType() instanceof DAPBreakpointType)) { - return false; - } - - XSourcePosition sourcePosition = breakpoint.getSourcePosition(); - if (sourcePosition == null) { - return false; - } - return debugAdapterDescriptor.isDebuggableFile(sourcePosition.getFile(), project); - } - - private static int getLineNumber(@NotNull XSourcePosition sourcePosition) { - return sourcePosition.getLine() + 1; - } - - /** - * Returns the IntelliJ breakpoint from the DAP breakpoint id and null otherwise. - * - * @param id the DAP breakpoint id. - * @return the IntelliJ breakpoint from the DAP breakpoint id and null otherwise. - */ - @Nullable - public XBreakpoint findBreakpointById(@Nullable Integer id) { - if (id == null) { - return null; - } - for (var breakpoint : breakpoints) { - Integer breakpointId = breakpoint.getUserData(DAP_BREAKPOINT_ID); - if (id.equals(breakpointId)) { - return breakpoint; - } - } - return null; - } - - /** - * Returns the IntelliJ breakpoint from the DAP stack frame and null otherwise. - * - * @param stackFrame the DAP stack frame. - * @return the IntelliJ breakpoint from the DAP stack frame and null otherwise. - */ - @Nullable - public XBreakpoint findBreakpoint(@NotNull StackFrame stackFrame) { - return findBreakpoint(stackFrame.getSource(), stackFrame.getLine()); - } - - /** - * Returns the IntelliJ breakpoint from the DAP source and given line and null otherwise. - * - * @param source the DAP source. - * @param lineNumber the line number. - * @return the IntelliJ breakpoint from the DAP source and given line and null otherwise. - */ - @Nullable - private XBreakpoint findBreakpoint(@Nullable Source source, - int lineNumber) { - if (source == null) { - return null; - } - Path filePath = getValidFilePath(source); - if (filePath == null) { - return null; - } - for (XBreakpoint breakpoint : breakpoints) { - XSourcePosition breakpointPosition = breakpoint.getSourcePosition(); - if (breakpointPosition == null) { - continue; - } - VirtualFile fileInBreakpoint = breakpointPosition.getFile(); - int line = breakpointPosition.getLine() + 1; - if (fileInBreakpoint.toNioPath().equals(filePath) && line == lineNumber) { - return breakpoint; - } - } - return null; - } - - /** - * Update IntelliJ breakpoint with the given DAP breakpoint information. - * - * @param breakpoint the DAP breakpoint information. - * @param ijBreakpoint the IJ Breakpoint and null otherwise. - */ - public void updateBreakpoint(@NotNull Breakpoint breakpoint, - @Nullable XBreakpoint ijBreakpoint) { - if (ijBreakpoint == null) { - // Retrieve the IntelliJ breakpoint by the id. - ijBreakpoint = findBreakpointById(breakpoint.getId()); - } - if (ijBreakpoint instanceof XLineBreakpoint lineBreakpoint) { - // Update the IntelliJ breakpoint according the DAP breakpoint 'verified' flag. - if (breakpoint.isVerified()) { - debugSession.setBreakpointVerified(lineBreakpoint); - } else { - debugSession.setBreakpointInvalid(lineBreakpoint, breakpoint.getMessage()); - } - } - } - - /** - * Returns the exception breakpoints panel which host exception breakpoint filter - * get during the initialization of the DAP server. - * - * @return the exception breakpoints panel which host exception breakpoint filter - * * get during the initialization of the DAP server. - */ - public @NotNull DAPExceptionBreakpointsPanel getExceptionBreakpointsPanel() { - return exceptionBreakpointsPanel; - } - - /** - * Returns the DAP server descriptor. - * - * @return the DAP server descriptor. - */ - public @NotNull DebugAdapterDescriptor getDebugAdapterDescriptor() { - return debugAdapterDescriptor; - } - - /** - * Send exception breakpoint filters to the all initialized DAP servers. - */ - public void sendExceptionBreakpointFilters() { - var applicableFilters = getExceptionBreakpointsPanel().getApplicableFilters(); - for (var server : debugProtocolServers) { - sendExceptionBreakpointFilters(applicableFilters, server); - } - } - - /** - * Send exception breakpoint filters to the given server. - * - * @param filters all filters (enabled/disabled) coming from the DAP server. - * @param debugProtocolServer the DAP server. - * @return the future. - */ - public CompletableFuture sendExceptionBreakpointFilters(ExceptionBreakpointsFilter[] filters, - IDebugProtocolServer debugProtocolServer) { - var applicableFilters = getExceptionBreakpointsPanel() - .refresh(filters); - return sendExceptionBreakpointFilters( - applicableFilters, debugProtocolServer); - } - - /** - * Send exception breakpoint filters to the given server. - * - * @param applicableFilters the applicable exception breakpoint filters. - * @param debugProtocolServer the DAP server. - * @return the future. - */ - private CompletableFuture sendExceptionBreakpointFilters(Collection applicableFilters, - IDebugProtocolServer debugProtocolServer) { - SetExceptionBreakpointsArguments args = new SetExceptionBreakpointsArguments(); - args.setFilters( - applicableFilters - .stream() - .map(ExceptionBreakpointsFilter::getFilter) - .toArray(String[]::new)); - return debugProtocolServer - .setExceptionBreakpoints(args) - .thenAccept(r -> { - }); - } - - - @Override - public void dispose() { - debugProtocolServers.clear(); + public DAPBreakpointHandler(@NotNull XDebugSession debugSession, @NotNull DebugAdapterDescriptor debugAdapterDescriptor, @NotNull Project project) { + super(DAPBreakpointType.class, debugSession, debugAdapterDescriptor, project); } } diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/breakpoints/DAPBreakpointHandlerBase.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/breakpoints/DAPBreakpointHandlerBase.java new file mode 100644 index 000000000..bf46c305a --- /dev/null +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/breakpoints/DAPBreakpointHandlerBase.java @@ -0,0 +1,424 @@ +/******************************************************************************* + * Copyright (c) 2025 Red Hat, Inc. + * Distributed under license by Red Hat, Inc. All rights reserved. + * This program is made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, + * and is available at https://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + ******************************************************************************/ +package com.redhat.devtools.lsp4ij.dap.breakpoints; + +import com.intellij.openapi.Disposable; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.xdebugger.XDebugSession; +import com.intellij.xdebugger.XExpression; +import com.intellij.xdebugger.XSourcePosition; +import com.intellij.xdebugger.breakpoints.XBreakpoint; +import com.intellij.xdebugger.breakpoints.XBreakpointHandler; +import com.intellij.xdebugger.breakpoints.XBreakpointType; +import com.intellij.xdebugger.breakpoints.XLineBreakpoint; +import com.redhat.devtools.lsp4ij.dap.descriptors.DebugAdapterDescriptor; +import org.eclipse.lsp4j.debug.*; +import org.eclipse.lsp4j.debug.services.IDebugProtocolServer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Path; +import java.util.*; +import java.util.concurrent.CompletableFuture; + +import static com.redhat.devtools.lsp4ij.dap.DAPIJUtils.*; + +/** + * Abstract Debug Adapter Protocol (DAP) breakpoint handler. + */ +public abstract class DAPBreakpointHandlerBase> extends XBreakpointHandler implements Disposable { + + private static final @NotNull Key DAP_BREAKPOINT_ID = Key.create("dap.breakpoint.id"); + private static final SourceBreakpoint[] EMPTY_SOURCE_BREAKPOINTS = new SourceBreakpoint[0]; + public static final CompletableFuture[] EMPTY_COMPLETABLE_FUTURES = new CompletableFuture[0]; + + private final @NotNull XDebugSession debugSession; + private final @NotNull DebugAdapterDescriptor debugAdapterDescriptor; + private final @NotNull Project project; + private final List debugProtocolServers = ContainerUtil.createConcurrentList(); + private @Nullable Capabilities capabilities; + private final List breakpoints = ContainerUtil.createConcurrentList(); + private final @NotNull DAPExceptionBreakpointsPanel exceptionBreakpointsPanel; + + private record TemporaryBreakpoint(@NotNull XSourcePosition sourcePosition, boolean add) { + } + + public DAPBreakpointHandlerBase(@NotNull Class> breakpointTypeClass, + @NotNull XDebugSession debugSession, + @NotNull DebugAdapterDescriptor debugAdapterDescriptor, + @NotNull Project project) { + super(breakpointTypeClass); + this.debugSession = debugSession; + this.debugAdapterDescriptor = debugAdapterDescriptor; + this.project = project; + this.exceptionBreakpointsPanel = new DAPExceptionBreakpointsPanel(this); + } + + @Override + public void registerBreakpoint(@NotNull B breakpoint) { + if (!(breakpoint.isEnabled() && + supportsBreakpoint(breakpoint))) { + return; + } + + breakpoints.add(breakpoint); + sendBreakpoints(null, null); + } + + @Override + public void unregisterBreakpoint(@NotNull B breakpoint, + boolean temporary) { + var sourcePosition = breakpoint.getSourcePosition(); + if (!supportsBreakpoint(breakpoint) || sourcePosition == null) { + return; + } + breakpoints.remove(breakpoint); + sendBreakpoints(null, + new TemporaryBreakpoint(sourcePosition, false)); + } + + public CompletableFuture<@Nullable Void> initialize(@NotNull IDebugProtocolServer debugProtocolServer, + @Nullable Capabilities capabilities) { + this.debugProtocolServers.add(debugProtocolServer); + this.capabilities = capabilities; + return sendBreakpoints(debugProtocolServer, null); + } + + private CompletableFuture<@Nullable Void> sendBreakpoints(@Nullable IDebugProtocolServer debugProtocolServer, + @Nullable TemporaryBreakpoint temporaryBreakpoint) { + if (debugProtocolServers.isEmpty()) { + return CompletableFuture.completedFuture(null); + } + + // Convert list of IJ XBreakpoint -> LSP SourceBreakpoint + Map> targetBreakpoints = new HashMap<>(); + for (B breakpoint : breakpoints) { + var sourcePosition = breakpoint.getSourcePosition(); + if (sourcePosition != null) { + addSourceBreakpoint(sourcePosition, breakpoint.getConditionExpression(), targetBreakpoints); + } + } + + if (temporaryBreakpoint != null) { + if (temporaryBreakpoint.add()) { + addSourceBreakpoint(temporaryBreakpoint.sourcePosition(), null, targetBreakpoints); + } else { + // Removed IntelliJ breakpoint + // Create a Source with empty source breakpoints if it doesn't exist, + // in order to disable removed breakpoint + // if the source contained only this breakpoint. + Source source = toDAPSource(temporaryBreakpoint.sourcePosition()); + targetBreakpoints + .computeIfAbsent(source, s -> new ArrayList<>()); + } + } + + final var setBreakpointsFutures = new ArrayList>(); + for (Iterator>> iterator = targetBreakpoints.entrySet() + .iterator(); iterator.hasNext(); ) { + Map.Entry> entry = iterator.next(); + + Source source = entry.getKey(); + List sourceBreakpoints = entry.getValue(); + + // Call 'setBreakpoints' DAP request for each Source keys. + final var arguments = getSetBreakpointsArguments(source, sourceBreakpoints); + if (debugProtocolServer != null) { + // Call 'setBreakpoints' DAP request for each Source keys + // and the given debug protocol server + setBreakpointsFutures.add(setBreakpoints(debugProtocolServer, arguments)); + } else { + // Call 'setBreakpoints' DAP request for each Source keys + // for each registered debug protocol server + for (var server : debugProtocolServers) { + setBreakpointsFutures.add(setBreakpoints(server, arguments)); + } + } + + // Once we told adapter there are no breakpoints for a source file, we can stop + // tracking that file + if (sourceBreakpoints.isEmpty()) { + iterator.remove(); + } + } + return CompletableFuture.allOf(setBreakpointsFutures.toArray(EMPTY_COMPLETABLE_FUTURES)); + } + + private static @NotNull SetBreakpointsArguments getSetBreakpointsArguments(@NotNull Source source, + @NotNull List sourceBreakpoints) { + int[] lines = sourceBreakpoints + .stream() + .mapToInt(SourceBreakpoint::getLine) + .toArray(); + + final var arguments = new SetBreakpointsArguments(); + arguments.setSource(source); + arguments.setLines(lines); + arguments.setBreakpoints(sourceBreakpoints.toArray(EMPTY_SOURCE_BREAKPOINTS)); + arguments.setSourceModified(false); + return arguments; + } + + private CompletableFuture setBreakpoints(@NotNull IDebugProtocolServer debugProtocolServer, + @NotNull SetBreakpointsArguments arguments) { + CompletableFuture future = debugProtocolServer.setBreakpoints(arguments); + return future + .thenAccept(response -> { + var breakpoints = response.getBreakpoints(); + if (breakpoints == null) { + return; + } + for (int i = 0; i < breakpoints.length; i++) { + Breakpoint breakpointResponse = breakpoints[i]; + Source source = breakpointResponse.getSource(); + if (source == null) { + source = arguments.getSource(); + } + Integer line = breakpointResponse.getLine(); + if (line == null && arguments.getBreakpoints().length > i) { + var sourceBreakpoint = arguments.getBreakpoints()[i]; + line = sourceBreakpoint.getLine(); + } + if (source != null && line != null) { + var ijBreakpoint = findBreakpoint(source, line); + if (ijBreakpoint != null) { + ijBreakpoint.putUserData(DAP_BREAKPOINT_ID, breakpointResponse.getId()); + updateBreakpoint(breakpointResponse, ijBreakpoint); + } + } + } + }); + } + + private static void addSourceBreakpoint(@NotNull XSourcePosition sourcePosition, + @Nullable XExpression conditionExpression, + @NotNull Map> targetBreakpoints) { + Source source = toDAPSource(sourcePosition); + int lineNumber = getLineNumber(sourcePosition); + SourceBreakpoint sourceBreakpoint = new SourceBreakpoint(); + sourceBreakpoint.setLine(lineNumber); + if (conditionExpression != null) { + // Breakpoint with condition + sourceBreakpoint.setCondition(conditionExpression.getExpression()); + } + List sourceBreakpoints = targetBreakpoints + .computeIfAbsent(source, s -> new ArrayList<>()); + sourceBreakpoints.add(sourceBreakpoint); + } + + private static @NotNull Source toDAPSource(@NotNull XSourcePosition sourcePosition) { + Source source = new Source(); + source.setPath(getFilePath(sourcePosition.getFile())); + source.setName(getFileName(sourcePosition.getFile())); + return source; + } + + /** + * Register the given source position as temporary breakpoint. + * + * @param sourcePosition the temporary breakpoint. + * @return the completable future. + */ + public CompletableFuture<@Nullable Void> registerTemporaryBreakpoint(@NotNull XSourcePosition sourcePosition) { + return sendBreakpoints(null, new TemporaryBreakpoint(sourcePosition, true)); + } + + /** + * Un-register the given source position as temporary breakpoint. + * + * @param sourcePosition the temporary breakpoint. + * @return the completable future. + */ + public CompletableFuture<@Nullable Void> unregisterTemporaryBreakpoint(@NotNull XSourcePosition sourcePosition) { + return sendBreakpoints(null, new TemporaryBreakpoint(sourcePosition, false)); + } + + /** + * Returns whether this target can install the given breakpoint. + * + * @param breakpoint breakpoint to consider + * @return whether this target can install the given breakpoint + */ + public boolean supportsBreakpoint(B breakpoint) { + if (!(breakpoint.getType() instanceof DAPBreakpointTypeBase)) { + return false; + } + + XSourcePosition sourcePosition = breakpoint.getSourcePosition(); + if (sourcePosition == null) { + return false; + } + return debugAdapterDescriptor.isDebuggableFile(sourcePosition.getFile(), project); + } + + private static int getLineNumber(@NotNull XSourcePosition sourcePosition) { + return sourcePosition.getLine() + 1; + } + + /** + * Returns the IntelliJ breakpoint from the DAP breakpoint id and null otherwise. + * + * @param id the DAP breakpoint id. + * @return the IntelliJ breakpoint from the DAP breakpoint id and null otherwise. + */ + @Nullable + public B findBreakpointById(@Nullable Integer id) { + if (id == null) { + return null; + } + for (var breakpoint : breakpoints) { + Integer breakpointId = breakpoint.getUserData(DAP_BREAKPOINT_ID); + if (id.equals(breakpointId)) { + return breakpoint; + } + } + return null; + } + + /** + * Returns the IntelliJ breakpoint from the DAP stack frame and null otherwise. + * + * @param stackFrame the DAP stack frame. + * @return the IntelliJ breakpoint from the DAP stack frame and null otherwise. + */ + @Nullable + public B findBreakpoint(@NotNull StackFrame stackFrame) { + return findBreakpoint(stackFrame.getSource(), stackFrame.getLine()); + } + + /** + * Returns the IntelliJ breakpoint from the DAP source and given line and null otherwise. + * + * @param source the DAP source. + * @param lineNumber the line number. + * @return the IntelliJ breakpoint from the DAP source and given line and null otherwise. + */ + @Nullable + private B findBreakpoint(@Nullable Source source, + int lineNumber) { + if (source == null) { + return null; + } + Path filePath = getValidFilePath(source); + if (filePath == null) { + return null; + } + for (B breakpoint : breakpoints) { + XSourcePosition breakpointPosition = breakpoint.getSourcePosition(); + if (breakpointPosition == null) { + continue; + } + VirtualFile fileInBreakpoint = breakpointPosition.getFile(); + int line = breakpointPosition.getLine() + 1; + if (fileInBreakpoint.toNioPath().equals(filePath) && line == lineNumber) { + return breakpoint; + } + } + return null; + } + + /** + * Update IntelliJ breakpoint with the given DAP breakpoint information. + * + * @param breakpoint the DAP breakpoint information. + * @param ijBreakpoint the IJ Breakpoint and null otherwise. + */ + public void updateBreakpoint(@NotNull Breakpoint breakpoint, + @Nullable B ijBreakpoint) { + if (ijBreakpoint == null) { + // Retrieve the IntelliJ breakpoint by the id. + ijBreakpoint = findBreakpointById(breakpoint.getId()); + } + if (ijBreakpoint instanceof XLineBreakpoint lineBreakpoint) { + // Update the IntelliJ breakpoint according the DAP breakpoint 'verified' flag. + if (breakpoint.isVerified()) { + debugSession.setBreakpointVerified(lineBreakpoint); + } else { + debugSession.setBreakpointInvalid(lineBreakpoint, breakpoint.getMessage()); + } + } + } + + /** + * Returns the exception breakpoints panel which host exception breakpoint filter + * get during the initialization of the DAP server. + * + * @return the exception breakpoints panel which host exception breakpoint filter + * * get during the initialization of the DAP server. + */ + public @NotNull DAPExceptionBreakpointsPanel getExceptionBreakpointsPanel() { + return exceptionBreakpointsPanel; + } + + /** + * Returns the DAP server descriptor. + * + * @return the DAP server descriptor. + */ + public @NotNull DebugAdapterDescriptor getDebugAdapterDescriptor() { + return debugAdapterDescriptor; + } + + /** + * Send exception breakpoint filters to the all initialized DAP servers. + */ + public void sendExceptionBreakpointFilters() { + var applicableFilters = getExceptionBreakpointsPanel().getApplicableFilters(); + for (var server : debugProtocolServers) { + sendExceptionBreakpointFilters(applicableFilters, server); + } + } + + /** + * Send exception breakpoint filters to the given server. + * + * @param filters all filters (enabled/disabled) coming from the DAP server. + * @param debugProtocolServer the DAP server. + * @return the future. + */ + public CompletableFuture sendExceptionBreakpointFilters(ExceptionBreakpointsFilter[] filters, + IDebugProtocolServer debugProtocolServer) { + var applicableFilters = getExceptionBreakpointsPanel() + .refresh(filters); + return sendExceptionBreakpointFilters( + applicableFilters, debugProtocolServer); + } + + /** + * Send exception breakpoint filters to the given server. + * + * @param applicableFilters the applicable exception breakpoint filters. + * @param debugProtocolServer the DAP server. + * @return the future. + */ + private CompletableFuture sendExceptionBreakpointFilters(Collection applicableFilters, + IDebugProtocolServer debugProtocolServer) { + SetExceptionBreakpointsArguments args = new SetExceptionBreakpointsArguments(); + args.setFilters( + applicableFilters + .stream() + .map(ExceptionBreakpointsFilter::getFilter) + .toArray(String[]::new)); + return debugProtocolServer + .setExceptionBreakpoints(args) + .thenAccept(r -> { + }); + } + + + @Override + public void dispose() { + debugProtocolServers.clear(); + } +} diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/breakpoints/DAPBreakpointType.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/breakpoints/DAPBreakpointType.java index 9037797db..0db863fb7 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/breakpoints/DAPBreakpointType.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/breakpoints/DAPBreakpointType.java @@ -24,9 +24,9 @@ import org.jetbrains.annotations.Nullable; /** - * Debug Adapter Protocol (DAP) breakpoint type. + * Default Debug Adapter Protocol (DAP) breakpoint type. */ -public class DAPBreakpointType extends XLineBreakpointType { +public class DAPBreakpointType extends DAPBreakpointTypeBase { private static final String BREAKPOINT_ID = "dap-breakpoint"; @@ -40,32 +40,4 @@ public DAPBreakpointProperties createBreakpointProperties(@NotNull final Virtual return new DAPBreakpointProperties(); } - @Override - public boolean canPutAt(@NotNull VirtualFile file, - int line, - @NotNull Project project) { - return DebugAdapterManager.getInstance().isDebuggableFile(file, project); - } - - @Override - public @Nullable XDebuggerEditorsProvider getEditorsProvider(@NotNull XLineBreakpoint breakpoint, - @NotNull Project project) { - // Returns a non-null XDebuggerEditorsProvider to support Condition in the breakpoint type. - FileType fileType = null; - var file = LSPIJUtils.findResourceFor(breakpoint.getFileUrl()); - if (file != null) { - if (!canSupportConditionBreakpoint(file, project)) { - return null; - } - fileType = file.getFileType(); - } - return new DAPDebuggerEditorsProvider(fileType, null); - } - - private boolean canSupportConditionBreakpoint(VirtualFile file, @NotNull Project project) { - // TODO: manage a settings to know if the given file which is associated to a DAP server - // can support condition breakpoint point - // At this step, the DAP server cannot be started, so we need to manage a DAP server settings for that. - return true; - } } diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/breakpoints/DAPBreakpointTypeBase.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/breakpoints/DAPBreakpointTypeBase.java new file mode 100644 index 000000000..97c0d0708 --- /dev/null +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/breakpoints/DAPBreakpointTypeBase.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2025 Red Hat, Inc. + * Distributed under license by Red Hat, Inc. All rights reserved. + * This program is made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + ******************************************************************************/ +package com.redhat.devtools.lsp4ij.dap.breakpoints; + +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.xdebugger.breakpoints.XBreakpointProperties; +import com.intellij.xdebugger.breakpoints.XLineBreakpoint; +import com.intellij.xdebugger.breakpoints.XLineBreakpointType; +import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider; +import com.redhat.devtools.lsp4ij.LSPIJUtils; +import com.redhat.devtools.lsp4ij.dap.DAPDebuggerEditorsProvider; +import com.redhat.devtools.lsp4ij.dap.DebugAdapterManager; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Base class for Debug Adapter Protocol (DAP) breakpoint type. + * + * @param

the breakpoint point properties. + */ +public abstract class DAPBreakpointTypeBase

> extends XLineBreakpointType

{ + + protected DAPBreakpointTypeBase(@NonNls @NotNull String id, @Nls @NotNull String title) { + super(id, title); + } + + @Override + public @Nullable XDebuggerEditorsProvider getEditorsProvider(@NotNull XLineBreakpoint

breakpoint, + @NotNull Project project) { + // Returns a non-null XDebuggerEditorsProvider to support Condition in the breakpoint type. + FileType fileType = null; + var file = LSPIJUtils.findResourceFor(breakpoint.getFileUrl()); + if (file != null) { + if (!supportsConditionBreakpoint(file, project)) { + return null; + } + fileType = file.getFileType(); + } + return new DAPDebuggerEditorsProvider(fileType, null); + } + + @Override + public boolean canPutAt(@NotNull VirtualFile file, + int line, + @NotNull Project project) { + return DebugAdapterManager.getInstance().isDebuggableFile(file, this, project); + } + + protected boolean supportsConditionBreakpoint(VirtualFile file, @NotNull Project project) { + // TODO: manage a settings to know if the given file which is associated to a DAP server + // can support condition breakpoint point + // At this step, the DAP server cannot be started, so we need to manage a DAP server settings for that. + return true; + } +} diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/breakpoints/DAPExceptionBreakpointsPanel.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/breakpoints/DAPExceptionBreakpointsPanel.java index 933f50b98..d203ec213 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/breakpoints/DAPExceptionBreakpointsPanel.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/breakpoints/DAPExceptionBreakpointsPanel.java @@ -41,11 +41,11 @@ public class DAPExceptionBreakpointsPanel extends BorderLayoutPanel implements D static final EnabledColumnInfo ENABLED_COLUMN = new EnabledColumnInfo(); static final NameColumnInfo NAME_COLUMN = new NameColumnInfo(); - private final @NotNull DAPBreakpointHandler breakpointHandler; + private final @NotNull DAPBreakpointHandlerBase breakpointHandler; private final @NotNull ListTableModel myModel; private final @NotNull TableView myTable; - public DAPExceptionBreakpointsPanel(@NotNull DAPBreakpointHandler breakpointHandler) { + public DAPExceptionBreakpointsPanel(@NotNull DAPBreakpointHandlerBase breakpointHandler) { this.breakpointHandler = breakpointHandler; // Create Table view diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/client/DAPClient.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/client/DAPClient.java index 3a336b224..d3eecf4bf 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/client/DAPClient.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/client/DAPClient.java @@ -354,7 +354,7 @@ public void stopped(StoppedEventArguments args) { StackFrame[] stackFrames = stackTraceResponse.getStackFrames(); if (stackFrames != null && stackFrames.length > 0) { var stackFrame = stackFrames[0]; - XBreakpoint breakpoint = debugProcess.getBreakpointHandler().findBreakpoint(stackFrame); + XBreakpoint breakpoint = debugProcess.getBreakpointHandler().findBreakpoint(stackFrame); XSuspendContext context = getSession().getSuspendContext(); if (context == null) { context = new DAPSuspendContext(this); diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfigurationType.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPConfigurationType.java similarity index 78% rename from src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfigurationType.java rename to src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPConfigurationType.java index c69439505..3416b31ff 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfigurationType.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPConfigurationType.java @@ -1,38 +1,38 @@ -/******************************************************************************* - * Copyright (c) 2025 Red Hat, Inc. - * Distributed under license by Red Hat, Inc. All rights reserved. - * This program is made available under the terms of the - * Eclipse Public License v2.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v20.html - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - ******************************************************************************/ -package com.redhat.devtools.lsp4ij.dap.configurations; - -import com.intellij.execution.configurations.ConfigurationTypeBase; -import com.intellij.execution.configurations.ConfigurationTypeUtil; -import com.intellij.icons.AllIcons; -import com.intellij.openapi.util.NotNullLazyValue; -import com.redhat.devtools.lsp4ij.dap.DAPBundle; - -/** - * Default Debug Adapter Protocol (DAP) configuration type. - */ -final class DAPRunConfigurationType extends ConfigurationTypeBase { - - public static final String ID = "DAPRunConfiguration"; - - public static DAPRunConfigurationType getInstance() { - return ConfigurationTypeUtil.findConfigurationType(DAPRunConfigurationType.class); - } - - DAPRunConfigurationType() { - super(ID, - DAPBundle.message("DAPRunConfigurationType.displayName"), - DAPBundle.message("DAPRunConfigurationType.description"), - NotNullLazyValue.createValue(() -> AllIcons.Debugger.Console)); - addFactory(new DAPConfigurationFactory(this)); - } - +/******************************************************************************* + * Copyright (c) 2025 Red Hat, Inc. + * Distributed under license by Red Hat, Inc. All rights reserved. + * This program is made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + ******************************************************************************/ +package com.redhat.devtools.lsp4ij.dap.configurations; + +import com.intellij.execution.configurations.ConfigurationTypeBase; +import com.intellij.execution.configurations.ConfigurationTypeUtil; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.util.NotNullLazyValue; +import com.redhat.devtools.lsp4ij.dap.DAPBundle; + +/** + * Default Debug Adapter Protocol (DAP) configuration type. + */ +final class DAPConfigurationType extends ConfigurationTypeBase { + + public static final String ID = "DAPConfiguration"; + + public static DAPConfigurationType getInstance() { + return ConfigurationTypeUtil.findConfigurationType(DAPConfigurationType.class); + } + + DAPConfigurationType() { + super(ID, + DAPBundle.message("DAPRunConfigurationType.displayName"), + DAPBundle.message("DAPRunConfigurationType.description"), + NotNullLazyValue.createValue(() -> AllIcons.Debugger.Console)); + addFactory(new DAPConfigurationFactory(this)); + } + } \ No newline at end of file diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfiguration.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfiguration.java index 443d3b004..77c4d57b5 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfiguration.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfiguration.java @@ -20,6 +20,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.redhat.devtools.lsp4ij.dap.DebugMode; import com.redhat.devtools.lsp4ij.dap.DebugServerWaitStrategy; +import com.redhat.devtools.lsp4ij.dap.configurations.options.AttachConfigurable; import com.redhat.devtools.lsp4ij.dap.configurations.options.FileOptionConfigurable; import com.redhat.devtools.lsp4ij.dap.configurations.options.WorkingDirectoryConfigurable; import com.redhat.devtools.lsp4ij.dap.definitions.DebugAdapterServerDefinition; @@ -36,9 +37,9 @@ import java.util.List; /** - * Debug Adapter Protocol (DAP) run configuration. + * Default Debug Adapter Protocol (DAP) run configuration. */ -public class DAPRunConfiguration extends RunConfigurationBase implements FileOptionConfigurable, WorkingDirectoryConfigurable, DebuggableFile { +public class DAPRunConfiguration extends DAPRunConfigurationBase implements FileOptionConfigurable, WorkingDirectoryConfigurable, AttachConfigurable, DebuggableFile { public static final String DEBUG_ADAPTER_CONFIGURATION = "Debug Adapter Configuration"; @@ -143,19 +144,23 @@ public void setDebugServerReadyPattern(String debugServerReadyPattern) { getOptions().setDebugServerReadyPattern(debugServerReadyPattern); } - public String getAttachAddress() { + @Override + public @Nullable String getAttachAddress() { return getOptions().getAttachAddress(); } - public void setAttachAddress(String attachAddress) { + @Override + public void setAttachAddress(@Nullable String attachAddress) { getOptions().setAttachAddress(attachAddress); } - public String getAttachPort() { + @Override + public @Nullable String getAttachPort() { return getOptions().getAttachPort(); } - public void setAttachPort(String attachPort) { + @Override + public void setAttachPort(@Nullable String attachPort) { getOptions().setAttachPort(attachPort); } @@ -257,33 +262,11 @@ public SettingsEditor getConfigurationEditor() { new DAPSettingsEditor(getProject()); } - @Nullable - @Override - public RunProfileState getState(@NotNull Executor executor, - @NotNull ExecutionEnvironment environment) { - var debugAdapterServer = getDebugAdapterServer(); - DebugAdapterDescriptor serverDescriptor = debugAdapterServer != null ? - debugAdapterServer.getFactory().createDebugAdapterDescriptor(getOptions(), environment) : - new DefaultDebugAdapterDescriptor(getOptions(), environment, getName()); - return new DAPCommandLineState(serverDescriptor, getOptions(), environment); - } - @Override public boolean isDebuggableFile(@NotNull VirtualFile file, @NotNull Project project) { return getOptions().isDebuggableFile(file, project); } - /** - * Returns true if the given executor id (ex: 'Debug') can be executed and false otherwise. - * - * @param executorId the executor id (ex: 'Debug'). - * @return true if the given executor id (ex: 'Debug') can be executed and false otherwise. - */ - public boolean canRun(@NotNull String executorId) { - var serverFactory = getServerFactory(); - return serverFactory == null || serverFactory.canRun(executorId); - } - @Override public void checkConfiguration() throws RuntimeConfigurationException { if (StringUtils.isBlank(getCommand()) && StringUtils.isBlank(getServerId())) { @@ -291,19 +274,8 @@ public void checkConfiguration() throws RuntimeConfigurationException { } } - /** - * Returns the server DAP factory descriptor and null otherwise. - * - * @return the server DAP factory descriptor and null otherwise. - */ - @Nullable - private DebugAdapterDescriptorFactory getServerFactory() { - var server = getDebugAdapterServer(); - return server != null ? server.getFactory() : null; - } - - @Nullable - private DebugAdapterServerDefinition getDebugAdapterServer() { + @Override + protected @Nullable DebugAdapterServerDefinition getDebugAdapterServer() { return getOptions().getDebugAdapterServer(); } diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfigurationBase.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfigurationBase.java new file mode 100644 index 000000000..a1ecdf818 --- /dev/null +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfigurationBase.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2025 Red Hat, Inc. + * Distributed under license by Red Hat, Inc. All rights reserved. + * This program is made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, + * and is available at https://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + ******************************************************************************/ +package com.redhat.devtools.lsp4ij.dap.configurations; + +import com.intellij.execution.Executor; +import com.intellij.execution.configurations.ConfigurationFactory; +import com.intellij.execution.configurations.RunConfigurationBase; +import com.intellij.execution.configurations.RunProfileState; +import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.openapi.project.Project; +import com.redhat.devtools.lsp4ij.dap.definitions.DebugAdapterServerDefinition; +import com.redhat.devtools.lsp4ij.dap.descriptors.DebugAdapterDescriptor; +import com.redhat.devtools.lsp4ij.dap.descriptors.DebugAdapterDescriptorFactory; +import com.redhat.devtools.lsp4ij.dap.descriptors.DefaultDebugAdapterDescriptor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Debug Adapter Protocol (DAP) run configuration base. + * + * @param the run configuration options. + */ +public abstract class DAPRunConfigurationBase extends RunConfigurationBase { + + protected DAPRunConfigurationBase(@NotNull Project project, + @Nullable ConfigurationFactory factory, + @Nullable String name) { + super(project, factory, name); + } + + @Nullable + @Override + public RunProfileState getState(@NotNull Executor executor, + @NotNull ExecutionEnvironment environment) { + var debugAdapterServer = getDebugAdapterServer(); + DebugAdapterDescriptor serverDescriptor = debugAdapterServer != null ? + debugAdapterServer.getFactory().createDebugAdapterDescriptor(getOptions(), environment) : + new DefaultDebugAdapterDescriptor(getOptions(), environment, getName()); + return new DAPCommandLineState(serverDescriptor, getOptions(), environment); + } + + /** + * Returns the server DAP factory descriptor and null otherwise. + * + * @return the server DAP factory descriptor and null otherwise. + */ + @Nullable + protected DebugAdapterDescriptorFactory getServerFactory() { + var server = getDebugAdapterServer(); + return server != null ? server.getFactory() : null; + } + + /** + * Returns true if the given executor id (ex: 'Debug') can be executed and false otherwise. + * + * @param executorId the executor id (ex: 'Debug'). + * @return true if the given executor id (ex: 'Debug') can be executed and false otherwise. + */ + public boolean canRun(@NotNull String executorId) { + var serverFactory = getServerFactory(); + return serverFactory == null || serverFactory.canRun(executorId); + } + + protected abstract @Nullable DebugAdapterServerDefinition getDebugAdapterServer(); +} diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfigurationOptions.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfigurationOptions.java index 0307cc389..3338e2f2c 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfigurationOptions.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfigurationOptions.java @@ -20,6 +20,7 @@ import com.redhat.devtools.lsp4ij.dap.DebugMode; import com.redhat.devtools.lsp4ij.dap.DebugServerWaitStrategy; import com.redhat.devtools.lsp4ij.dap.configurations.extractors.NetworkAddressExtractor; +import com.redhat.devtools.lsp4ij.dap.configurations.options.AttachConfigurable; import com.redhat.devtools.lsp4ij.dap.configurations.options.FileOptionConfigurable; import com.redhat.devtools.lsp4ij.dap.configurations.options.WorkingDirectoryConfigurable; import com.redhat.devtools.lsp4ij.dap.definitions.DebugAdapterServerDefinition; @@ -36,7 +37,7 @@ /** * Debug Adapter Protocol (DAP) run configuration options. */ -public class DAPRunConfigurationOptions extends RunConfigurationOptions implements FileOptionConfigurable, WorkingDirectoryConfigurable, DebuggableFile, CommandLineUpdater { +public class DAPRunConfigurationOptions extends RunConfigurationOptions implements FileOptionConfigurable, WorkingDirectoryConfigurable, AttachConfigurable, DebuggableFile, CommandLineUpdater { @Nullable private NetworkAddressExtractor networkAddressExtractor; @@ -290,19 +291,23 @@ public void setDebugServerReadyPattern(String debugServerReadyPattern) { this.networkAddressExtractor = null; } - public String getAttachAddress() { + @Override + public @Nullable String getAttachAddress() { return attachAddress.getValue(this); } - public void setAttachAddress(String attachAddress) { + @Override + public void setAttachAddress(@Nullable String attachAddress) { this.attachAddress.setValue(this, attachAddress); } - public String getAttachPort() { + @Override + public @Nullable String getAttachPort() { return attachPort.getValue(this); } - public void setAttachPort(String attachPort) { + @Override + public void setAttachPort(@Nullable String attachPort) { this.attachPort.setValue(this, attachPort); } diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfigurationProvider.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfigurationProvider.java index 94f8ef5bb..08d511ed1 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfigurationProvider.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfigurationProvider.java @@ -25,7 +25,7 @@ public class DAPRunConfigurationProvider extends LazyRunConfigurationProducer extends DAPRunConfigurationBase implements AttachConfigurable { + + private final @NotNull String serverId; + + protected DAPAttachRunConfiguration(@NotNull Project project, + @Nullable ConfigurationFactory factory, + @Nullable String name, + @NotNull String serverId) { + super(project, factory, name); + this.serverId = serverId; + } + + @Override + public @NotNull SettingsEditor getConfigurationEditor() { + return new DAPAttachSettingsEditor<>(getProject()); + } + + @Override + protected @Nullable DebugAdapterServerDefinition getDebugAdapterServer() { + return DebugAdapterManager.getInstance().getDebugAdapterServerById(serverId); + } + + @Override + public @Nullable String getAttachAddress() { + return getOptions().getAttachAddress(); + } + + @Override + public void setAttachAddress(@Nullable String attachAddress) { + getOptions().setAttachAddress(attachAddress); + } + + @Override + public @Nullable String getAttachPort() { + return getOptions().getAttachPort(); + } + + @Override + public void setAttachPort(@Nullable String attachPort) { + getOptions().setAttachPort(attachPort); + } + + @Override + protected @NotNull T getOptions() { + return (T) super.getOptions(); + } +} diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/attach/DAPAttachRunConfigurationOptions.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/attach/DAPAttachRunConfigurationOptions.java new file mode 100644 index 000000000..7a9cdab71 --- /dev/null +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/attach/DAPAttachRunConfigurationOptions.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2025 Red Hat, Inc. + * Distributed under license by Red Hat, Inc. All rights reserved. + * This program is made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, + * and is available at https://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + ******************************************************************************/ +package com.redhat.devtools.lsp4ij.dap.configurations.attach; + +import com.intellij.execution.configurations.RunConfigurationOptions; +import com.intellij.openapi.components.StoredProperty; +import com.redhat.devtools.lsp4ij.dap.configurations.options.AttachConfigurable; +import org.jetbrains.annotations.Nullable; + +/** + * DAP run configuration options for "attach" mode. + */ +public class DAPAttachRunConfigurationOptions extends RunConfigurationOptions implements AttachConfigurable { + + private final StoredProperty attachAddress = string("") + .provideDelegate(this, "attachAddress"); + + private final StoredProperty attachPort = string("") + .provideDelegate(this, "attachPort"); + + @Override + public @Nullable String getAttachAddress() { + return attachAddress.getValue(this); + } + + @Override + public void setAttachAddress(@Nullable String attachAddress) { + this.attachAddress.setValue(this, attachAddress); + } + + @Override + public @Nullable String getAttachPort() { + return attachPort.getValue(this); + } + + @Override + public void setAttachPort(@Nullable String attachPort) { + this.attachPort.setValue(this, attachPort); + } + +} diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/attach/DAPAttachSettingsEditor.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/attach/DAPAttachSettingsEditor.java new file mode 100644 index 000000000..c44d02f6f --- /dev/null +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/attach/DAPAttachSettingsEditor.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright (c) 2025 Red Hat, Inc. + * Distributed under license by Red Hat, Inc. All rights reserved. + * This program is made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, + * and is available at https://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + ******************************************************************************/ +package com.redhat.devtools.lsp4ij.dap.configurations.attach; + +import com.intellij.execution.ExecutionBundle; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.options.SettingsEditor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.ComponentValidator; +import com.intellij.openapi.ui.ValidationInfo; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.ui.DocumentAdapter; +import com.intellij.util.ui.FormBuilder; +import com.redhat.devtools.lsp4ij.dap.configurations.options.AttachConfigurable; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import java.awt.*; + +/** + * Settings editor to configure DAP client with "attach". + * + * @param the "attach" configurable. + */ +public class DAPAttachSettingsEditor extends SettingsEditor { + + private final JPanel root; + private final JTextField myAddress = new JTextField(); + private final JTextField myPort = new JTextField(Integer.toString(65535)); + + public DAPAttachSettingsEditor(@NotNull Project project) { + this.myPort.setMinimumSize(this.myPort.getPreferredSize()); + (new ComponentValidator(project)).withValidator(() -> { + String pt = this.myPort.getText(); + if (StringUtil.isNotEmpty(pt)) { + try { + int portValue = Integer.parseInt(pt); + return portValue >= 0 && portValue <= 65535 ? null : new ValidationInfo(ExecutionBundle.message("incorrect.port.range.set.value.between"), this.myPort); + } catch (NumberFormatException var3) { + return new ValidationInfo(ExecutionBundle.message("port.value.should.be.a.number.between"), this.myPort); + } + } else { + return null; + } + }).installOn(this.myPort); + this.myPort.getDocument().addDocumentListener(new DocumentAdapter() { + protected void textChanged(@NotNull DocumentEvent e) { + ComponentValidator.getInstance(DAPAttachSettingsEditor.this.myPort).ifPresent((v) -> v.revalidate()); + } + }); + + FormBuilder builder = FormBuilder + .createFormBuilder(); + + builder.addLabeledComponent("Port:", myPort); + + JPanel panel = new JPanel(new BorderLayout()); + panel.add(builder.getPanel(), BorderLayout.CENTER); + root = panel; + + } + + @Override + protected void resetEditorFrom(@NotNull Settings settings) { + myPort.setText(settings.getAttachPort()); + } + + @Override + protected void applyEditorTo(@NotNull Settings settings) throws ConfigurationException { + settings.setAttachPort(myPort.getText()); + } + + @Override + protected @NotNull JComponent createEditor() { + return root; + } +} diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/options/AttachConfigurable.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/options/AttachConfigurable.java new file mode 100644 index 000000000..0143d0c8a --- /dev/null +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/options/AttachConfigurable.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2025 Red Hat, Inc. + * Distributed under license by Red Hat, Inc. All rights reserved. + * This program is made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, + * and is available at https://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + ******************************************************************************/ +package com.redhat.devtools.lsp4ij.dap.configurations.options; + +import org.jetbrains.annotations.Nullable; + +/** + * Attach configurable. + */ +public interface AttachConfigurable { + + @Nullable String getAttachAddress(); + + void setAttachAddress(@Nullable String attachAddress); + + @Nullable String getAttachPort(); + + void setAttachPort(@Nullable String attachPort); + +} diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/descriptors/DebugAdapterDescriptor.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/descriptors/DebugAdapterDescriptor.java index b862955d9..0e99969c6 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/descriptors/DebugAdapterDescriptor.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/descriptors/DebugAdapterDescriptor.java @@ -23,10 +23,19 @@ import com.intellij.openapi.util.Key; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.net.NetUtils; +import com.intellij.xdebugger.XDebugSession; +import com.intellij.xdebugger.breakpoints.XBreakpointProperties; +import com.intellij.xdebugger.breakpoints.XLineBreakpoint; import com.redhat.devtools.lsp4ij.dap.DAPDebugProcess; import com.redhat.devtools.lsp4ij.dap.DebugMode; +import com.redhat.devtools.lsp4ij.dap.breakpoints.DAPBreakpointHandler; +import com.redhat.devtools.lsp4ij.dap.breakpoints.DAPBreakpointHandlerBase; +import com.redhat.devtools.lsp4ij.dap.breakpoints.DAPBreakpointProperties; import com.redhat.devtools.lsp4ij.dap.client.DAPClient; +import com.redhat.devtools.lsp4ij.dap.client.LaunchUtils; +import com.redhat.devtools.lsp4ij.dap.configurations.DAPRunConfigurationOptions; import com.redhat.devtools.lsp4ij.dap.configurations.DebuggableFile; +import com.redhat.devtools.lsp4ij.dap.configurations.options.AttachConfigurable; import com.redhat.devtools.lsp4ij.dap.definitions.DebugAdapterServerDefinition; import com.redhat.devtools.lsp4ij.internal.IntelliJPlatformUtils; import com.redhat.devtools.lsp4ij.internal.StringUtils; @@ -223,7 +232,24 @@ public ServerTrace getServerTrace() { * @return the strategy to use to know when DAP server is started and DAP client can connect to it. */ @NotNull - public abstract ServerReadyConfig getServerReadyConfig(@NotNull DebugMode debugMode); + public ServerReadyConfig getServerReadyConfig(@NotNull DebugMode debugMode) { + if (options instanceof AttachConfigurable dapOptions) { + if (debugMode == DebugMode.ATTACH) { + String address = LaunchUtils.resolveAttachAddress(dapOptions.getAttachAddress(), getDapParameters()); + int port = LaunchUtils.resolveAttachPort(dapOptions.getAttachPort(), getDapParameters()); + return new ServerReadyConfig(address, port); + } + } + if (options instanceof DAPRunConfigurationOptions dapOptions) { + var strategy = dapOptions.getDebugServerWaitStrategy(); + return switch (strategy) { + case TIMEOUT -> new ServerReadyConfig(dapOptions.getConnectTimeout()); + case TRACE -> new ServerReadyConfig(dapOptions.getNetworkAddressExtractor()); + default -> new ServerReadyConfig(0); + }; + } + return new ServerReadyConfig(500); + } public abstract @Nullable FileType getFileType(); @@ -245,4 +271,8 @@ public String getServerName() { public boolean isDebuggableFile(@NotNull VirtualFile file, @NotNull Project project) { return serverDefinition != null && serverDefinition.isDebuggableFile(file, project); } + + public @NotNull DAPBreakpointHandlerBase createBreakpointHandler(@NotNull XDebugSession session, Project project) { + return new DAPBreakpointHandler(session, this, project); + } } diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/descriptors/DebugAdapterDescriptorFactory.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/descriptors/DebugAdapterDescriptorFactory.java index 792b6251e..cdbdc3687 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/descriptors/DebugAdapterDescriptorFactory.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/descriptors/DebugAdapterDescriptorFactory.java @@ -11,6 +11,7 @@ package com.redhat.devtools.lsp4ij.dap.descriptors; import com.intellij.execution.configurations.RunConfiguration; +import com.intellij.execution.configurations.RunConfigurationOptions; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.ide.plugins.IdeaPluginDescriptor; import com.intellij.ide.plugins.PluginManagerCore; @@ -18,11 +19,12 @@ import com.intellij.openapi.options.SettingsEditor; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.xdebugger.breakpoints.XBreakpointType; import com.redhat.devtools.lsp4ij.client.features.LSPClientFeatures; import com.redhat.devtools.lsp4ij.dap.DebugMode; import com.redhat.devtools.lsp4ij.dap.LaunchConfiguration; +import com.redhat.devtools.lsp4ij.dap.breakpoints.DAPBreakpointType; import com.redhat.devtools.lsp4ij.dap.configurations.DAPRunConfiguration; -import com.redhat.devtools.lsp4ij.dap.configurations.DAPRunConfigurationOptions; import com.redhat.devtools.lsp4ij.dap.configurations.DAPSettingsEditor; import com.redhat.devtools.lsp4ij.dap.configurations.DebuggableFile; import com.redhat.devtools.lsp4ij.dap.configurations.options.FileOptionConfigurable; @@ -81,7 +83,7 @@ public abstract class DebugAdapterDescriptorFactory implements DebuggableFile { private ServerTrace serverTrace; - public DebugAdapterDescriptor createDebugAdapterDescriptor(@NotNull DAPRunConfigurationOptions options, + public DebugAdapterDescriptor createDebugAdapterDescriptor(@NotNull RunConfigurationOptions options, @NotNull ExecutionEnvironment environment) { return new DefaultDebugAdapterDescriptor(options, environment, getServerDefinition()); } @@ -182,4 +184,18 @@ public static Path getDebugAdapterServerPath(@NotNull String pluginId, public ServerInstaller createServerInstaller() { return null; } + + /** + * Determines whether the given breakpoint type is supported by this debugger. + *

+ * The default implementation returns {@code true} if the given {@code breakpointType} + * is exactly of type {@link DAPBreakpointType} (i.e., {@code breakpointType.getClass() == DAPBreakpointType.class}). + *

+ * + * @param breakpointType the breakpoint type to check + * @return {@code true} if the breakpoint type is supported, {@code false} otherwise + */ + public boolean supportsBreakpointType(@NotNull XBreakpointType breakpointType) { + return breakpointType.getClass() == DAPBreakpointType.class; + } } diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/descriptors/DefaultDebugAdapterDescriptor.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/descriptors/DefaultDebugAdapterDescriptor.java index 181bc6bf5..d0bc27751 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/descriptors/DefaultDebugAdapterDescriptor.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/descriptors/DefaultDebugAdapterDescriptor.java @@ -22,6 +22,8 @@ import com.redhat.devtools.lsp4ij.dap.DebugMode; import com.redhat.devtools.lsp4ij.dap.client.LaunchUtils; import com.redhat.devtools.lsp4ij.dap.configurations.DAPRunConfigurationOptions; +import com.redhat.devtools.lsp4ij.dap.configurations.options.AttachConfigurable; +import com.redhat.devtools.lsp4ij.dap.configurations.options.FileOptionConfigurable; import com.redhat.devtools.lsp4ij.dap.definitions.DebugAdapterServerDefinition; import com.redhat.devtools.lsp4ij.dap.definitions.userdefined.UserDefinedDebugAdapterServerDefinition; import com.redhat.devtools.lsp4ij.installation.CommandLineUpdater; @@ -52,7 +54,7 @@ public DefaultDebugAdapterDescriptor(@NotNull RunConfigurationOptions options, this.id = serverDefinition.getId(); } - public DefaultDebugAdapterDescriptor(@NotNull DAPRunConfigurationOptions options, + public DefaultDebugAdapterDescriptor(@NotNull RunConfigurationOptions options, @NotNull ExecutionEnvironment environment, @NotNull String runConfigurationName) { super(options, environment, null); @@ -94,38 +96,12 @@ protected GeneralCommandLine createStartServerCommandLine(@NotNull RunConfigurat return null; } - /** - * Returns the strategy to use to know when DAP server is started and DAP client can connect to it. - * - * @return the strategy to use to know when DAP server is started and DAP client can connect to it. - */ - @NotNull - public ServerReadyConfig getServerReadyConfig(@NotNull DebugMode debugMode) { - if (options instanceof DAPRunConfigurationOptions dapOptions) { - if (debugMode == DebugMode.ATTACH) { - String address = LaunchUtils.resolveAttachAddress(dapOptions.getAttachAddress(), getDapParameters()); - int port = LaunchUtils.resolveAttachPort(dapOptions.getAttachPort(), getDapParameters()); - return new ServerReadyConfig(address, port); - } - var strategy = dapOptions.getDebugServerWaitStrategy(); - switch (strategy) { - case TIMEOUT: - return new ServerReadyConfig(dapOptions.getConnectTimeout()); - case TRACE: - return new ServerReadyConfig(dapOptions.getNetworkAddressExtractor()); - default: - return new ServerReadyConfig(0); - } - } - return new ServerReadyConfig(500); - } - public @Nullable FileType getFileType() { - if (options instanceof DAPRunConfigurationOptions dapOptions) { + if (options instanceof FileOptionConfigurable dapOptions) { String file = dapOptions.getFile(); int index = file != null ? file.lastIndexOf('.') : -1; if (index != -1) { - String fileExtension = file.substring(index + 1, file.length()); + String fileExtension = file.substring(index + 1); return FileTypeManager.getInstance().getFileTypeByExtension(fileExtension); } } diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index fe2b4c483..e1865c9da 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -976,7 +976,7 @@ + implementation="com.redhat.devtools.lsp4ij.dap.configurations.DAPConfigurationType"/> Date: Fri, 8 Aug 2025 11:11:48 -0700 Subject: [PATCH 009/264] docs(readme): add baml to the plugin list --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 76984ee8d..7d9a3bf7f 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,7 @@ Here are some projects that use LSP4IJ: * [SDLB LSP](https://github.com/smart-data-lake/sdl-lsp) * [Bloc Linter Support for IntelliJ](https://github.com/felangel/bloc) * [Vala JetBrains Plugin](https://github.com/Tbusk/vala-jetbrains-plugin) + * [BAML JetBrains Plugin](http://github.com/BoundaryML/baml/tree/canary/jetbrains) ## Requirements From e7b512620762c6347029fcb1b5b1617be3afcbde Mon Sep 17 00:00:00 2001 From: azerr Date: Sun, 10 Aug 2025 08:54:19 +0200 Subject: [PATCH 010/264] fix: nil crashes on textDocument/didSave notification Fixes #1202 Signed-off-by: azerr --- .../redhat/devtools/lsp4ij/DocumentContentSynchronizer.java | 2 +- .../com/redhat/devtools/lsp4ij/LanguageServerWrapper.java | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/redhat/devtools/lsp4ij/DocumentContentSynchronizer.java b/src/main/java/com/redhat/devtools/lsp4ij/DocumentContentSynchronizer.java index 1b33e009e..18f9417bc 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/DocumentContentSynchronizer.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/DocumentContentSynchronizer.java @@ -226,7 +226,7 @@ private TextDocumentContentChangeEvent createChangeEvent(DocumentEvent event) { public void documentSaved() { var saveOptions = syncOptions.getSave(); - if ((saveOptions.isLeft() && !saveOptions.getLeft()) || (saveOptions.isRight() && saveOptions.getRight() == null)) { + if (saveOptions == null || (saveOptions.isLeft() && !saveOptions.getLeft()) || (saveOptions.isRight() && saveOptions.getRight() == null)) { // Don't send textDocument/didSave return; } diff --git a/src/main/java/com/redhat/devtools/lsp4ij/LanguageServerWrapper.java b/src/main/java/com/redhat/devtools/lsp4ij/LanguageServerWrapper.java index 6efa8f26b..4695dd532 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/LanguageServerWrapper.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/LanguageServerWrapper.java @@ -865,11 +865,7 @@ private DocumentContentSynchronizer createDocumentContentSynchronizer(@NotNull S newSyncOptions.setSave(true); return newSyncOptions; } else if (syncOptions.isRight()) { - TextDocumentSyncOptions newSyncOptions = syncOptions.getRight(); - if (newSyncOptions.getSave() == null) { - newSyncOptions.setSave(true); - } - return newSyncOptions; + return syncOptions.getRight(); } } return DEFAULT_SYNC_OPTIONS; From 74db778cc729ae18af4842387667f27a5d29d6dd Mon Sep 17 00:00:00 2001 From: azerr Date: Mon, 11 Aug 2025 13:11:21 +0200 Subject: [PATCH 011/264] feat: add server trace in attach settings editor Signed-off-by: azerr --- .../devtools/lsp4ij/dap/client/DAPClient.java | 3 +- .../configurations/DAPCommandLineState.java | 8 +++++ .../DAPRunConfigurationBase.java | 30 +++++++++++++++- .../DAPRunConfigurationOptions.java | 13 +------ .../DAPRunConfigurationOptionsBase.java | 36 +++++++++++++++++++ .../DAPAttachRunConfigurationOptions.java | 4 ++- .../attach/DAPAttachSettingsEditor.java | 15 +++++++- .../options/ServerTraceConfigurable.java | 25 +++++++++++++ .../descriptors/DebugAdapterDescriptor.java | 9 +++-- .../DefaultDebugAdapterDescriptor.java | 15 ++------ 10 files changed, 125 insertions(+), 33 deletions(-) create mode 100644 src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfigurationOptionsBase.java create mode 100644 src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/options/ServerTraceConfigurable.java diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/client/DAPClient.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/client/DAPClient.java index d3eecf4bf..c5b400a53 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/client/DAPClient.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/client/DAPClient.java @@ -30,9 +30,8 @@ import com.redhat.devtools.lsp4ij.dap.DAPDebugProcess; import com.redhat.devtools.lsp4ij.dap.DebugMode; import com.redhat.devtools.lsp4ij.dap.TransportStreams; -import com.redhat.devtools.lsp4ij.dap.breakpoints.DAPBreakpointProperties; -import com.redhat.devtools.lsp4ij.dap.runInTerminal.RunInTerminalManager; import com.redhat.devtools.lsp4ij.dap.descriptors.DebugAdapterDescriptor; +import com.redhat.devtools.lsp4ij.dap.runInTerminal.RunInTerminalManager; import com.redhat.devtools.lsp4ij.internal.CancellationSupport; import com.redhat.devtools.lsp4ij.internal.StringUtils; import com.redhat.devtools.lsp4ij.settings.ServerTrace; diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPCommandLineState.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPCommandLineState.java index 5ef7f412a..a188fdf26 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPCommandLineState.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPCommandLineState.java @@ -20,6 +20,7 @@ import com.redhat.devtools.lsp4ij.dap.DAPServerReadyTracker; import com.redhat.devtools.lsp4ij.dap.DebugMode; import com.redhat.devtools.lsp4ij.dap.configurations.options.FileOptionConfigurable; +import com.redhat.devtools.lsp4ij.dap.configurations.options.ServerTraceConfigurable; import com.redhat.devtools.lsp4ij.dap.console.DAPTextConsoleBuilderImpl; import com.redhat.devtools.lsp4ij.dap.descriptors.DebugAdapterDescriptor; import com.redhat.devtools.lsp4ij.dap.descriptors.ServerReadyConfig; @@ -86,6 +87,12 @@ public DebugMode getDebugMode() { } public ServerTrace getServerTrace() { + if (options instanceof ServerTraceConfigurable serverTraceConfigurable) { + ServerTrace serverTrace = serverTraceConfigurable.getServerTrace(); + if (serverTrace != null) { + return serverTrace; + } + } return serverDescriptor.getServerTrace(); } @@ -115,6 +122,7 @@ public void setCommandLine(String commandLine) { commandLineUpdater.setCommandLine(commandLine); } } + public @Nullable String getInstallerConfiguration() { if (options instanceof DAPRunConfigurationOptions dapOptions) { return dapOptions.getInstallerConfiguration(); diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfigurationBase.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfigurationBase.java index a1ecdf818..3232bb725 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfigurationBase.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfigurationBase.java @@ -12,14 +12,18 @@ import com.intellij.execution.Executor; import com.intellij.execution.configurations.ConfigurationFactory; +import com.intellij.execution.configurations.RunConfiguration; import com.intellij.execution.configurations.RunConfigurationBase; import com.intellij.execution.configurations.RunProfileState; import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.openapi.options.SettingsEditor; import com.intellij.openapi.project.Project; +import com.redhat.devtools.lsp4ij.dap.configurations.options.ServerTraceConfigurable; import com.redhat.devtools.lsp4ij.dap.definitions.DebugAdapterServerDefinition; import com.redhat.devtools.lsp4ij.dap.descriptors.DebugAdapterDescriptor; import com.redhat.devtools.lsp4ij.dap.descriptors.DebugAdapterDescriptorFactory; import com.redhat.devtools.lsp4ij.dap.descriptors.DefaultDebugAdapterDescriptor; +import com.redhat.devtools.lsp4ij.settings.ServerTrace; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -28,7 +32,7 @@ * * @param the run configuration options. */ -public abstract class DAPRunConfigurationBase extends RunConfigurationBase { +public abstract class DAPRunConfigurationBase extends RunConfigurationBase implements ServerTraceConfigurable { protected DAPRunConfigurationBase(@NotNull Project project, @Nullable ConfigurationFactory factory, @@ -70,4 +74,28 @@ public boolean canRun(@NotNull String executorId) { } protected abstract @Nullable DebugAdapterServerDefinition getDebugAdapterServer(); + + @NotNull + @Override + public SettingsEditor getConfigurationEditor() { + var serverFactory = getServerFactory(); + return serverFactory != null ? + serverFactory.getConfigurationEditor(getProject()) : + new DAPSettingsEditor(getProject()); + } + + @Override + public void setServerTrace(ServerTrace serverTrace) { + if (getOptions() instanceof ServerTraceConfigurable serverTraceConfigurable) { + serverTraceConfigurable.setServerTrace(serverTrace); + } + } + + @Override + public ServerTrace getServerTrace() { + if (getOptions() instanceof ServerTraceConfigurable serverTraceConfigurable) { + return serverTraceConfigurable.getServerTrace(); + } + return null; + } } diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfigurationOptions.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfigurationOptions.java index 3338e2f2c..6d6ff7604 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfigurationOptions.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfigurationOptions.java @@ -37,7 +37,7 @@ /** * Debug Adapter Protocol (DAP) run configuration options. */ -public class DAPRunConfigurationOptions extends RunConfigurationOptions implements FileOptionConfigurable, WorkingDirectoryConfigurable, AttachConfigurable, DebuggableFile, CommandLineUpdater { +public class DAPRunConfigurationOptions extends DAPRunConfigurationOptionsBase implements FileOptionConfigurable, WorkingDirectoryConfigurable, AttachConfigurable, DebuggableFile, CommandLineUpdater { @Nullable private NetworkAddressExtractor networkAddressExtractor; @@ -96,9 +96,6 @@ public class DAPRunConfigurationOptions extends RunConfigurationOptions implemen private final StoredProperty attachPort = string("") .provideDelegate(this, "attachPort"); - private final StoredProperty serverTrace = string(ServerTrace.getDefaultValue().name()) - .provideDelegate(this, "serverTrace"); - // Installer settings private final StoredProperty installerConfiguration = string("") .provideDelegate(this, "installerConfiguration"); @@ -311,14 +308,6 @@ public void setAttachPort(@Nullable String attachPort) { this.attachPort.setValue(this, attachPort); } - public ServerTrace getServerTrace() { - return ServerTrace.get(serverTrace.getValue(this)); - } - - public void setServerTrace(ServerTrace serverTrace) { - this.serverTrace.setValue(this, serverTrace.name()); - } - // Installer settings public String getInstallerConfiguration() { diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfigurationOptionsBase.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfigurationOptionsBase.java new file mode 100644 index 000000000..14359810b --- /dev/null +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/DAPRunConfigurationOptionsBase.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2025 Red Hat, Inc. + * Distributed under license by Red Hat, Inc. All rights reserved. + * This program is made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, + * and is available at https://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + ******************************************************************************/ +package com.redhat.devtools.lsp4ij.dap.configurations; + +import com.intellij.execution.configurations.RunConfigurationOptions; +import com.intellij.openapi.components.StoredProperty; +import com.redhat.devtools.lsp4ij.dap.configurations.options.ServerTraceConfigurable; +import com.redhat.devtools.lsp4ij.settings.ServerTrace; + +/** + * Debug Adapter Protocol (DAP) run configuration options base. + */ +public class DAPRunConfigurationOptionsBase extends RunConfigurationOptions implements ServerTraceConfigurable { + + private final StoredProperty serverTrace = string(ServerTrace.getDefaultValue().name()) + .provideDelegate(this, "serverTrace"); + + @Override + public ServerTrace getServerTrace() { + return ServerTrace.get(serverTrace.getValue(this)); + } + + @Override + public void setServerTrace(ServerTrace serverTrace) { + this.serverTrace.setValue(this, serverTrace.name()); + } + +} diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/attach/DAPAttachRunConfigurationOptions.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/attach/DAPAttachRunConfigurationOptions.java index 7a9cdab71..5a4c5bd65 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/attach/DAPAttachRunConfigurationOptions.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/attach/DAPAttachRunConfigurationOptions.java @@ -12,13 +12,15 @@ import com.intellij.execution.configurations.RunConfigurationOptions; import com.intellij.openapi.components.StoredProperty; +import com.redhat.devtools.lsp4ij.dap.configurations.DAPRunConfigurationOptionsBase; import com.redhat.devtools.lsp4ij.dap.configurations.options.AttachConfigurable; +import com.redhat.devtools.lsp4ij.dap.configurations.options.ServerTraceConfigurable; import org.jetbrains.annotations.Nullable; /** * DAP run configuration options for "attach" mode. */ -public class DAPAttachRunConfigurationOptions extends RunConfigurationOptions implements AttachConfigurable { +public class DAPAttachRunConfigurationOptions extends DAPRunConfigurationOptionsBase implements AttachConfigurable { private final StoredProperty attachAddress = string("") .provideDelegate(this, "attachAddress"); diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/attach/DAPAttachSettingsEditor.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/attach/DAPAttachSettingsEditor.java index c44d02f6f..69d68e2d2 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/attach/DAPAttachSettingsEditor.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/attach/DAPAttachSettingsEditor.java @@ -14,12 +14,15 @@ import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.options.SettingsEditor; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.ComboBox; import com.intellij.openapi.ui.ComponentValidator; import com.intellij.openapi.ui.ValidationInfo; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.DocumentAdapter; import com.intellij.util.ui.FormBuilder; +import com.redhat.devtools.lsp4ij.dap.DAPBundle; import com.redhat.devtools.lsp4ij.dap.configurations.options.AttachConfigurable; +import com.redhat.devtools.lsp4ij.settings.ServerTrace; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -31,9 +34,11 @@ * * @param the "attach" configurable. */ -public class DAPAttachSettingsEditor extends SettingsEditor { +public class DAPAttachSettingsEditor> extends SettingsEditor { private final JPanel root; + // Server trace + private final ComboBox serverTraceComboBox; private final JTextField myAddress = new JTextField(); private final JTextField myPort = new JTextField(Integer.toString(65535)); @@ -61,7 +66,10 @@ protected void textChanged(@NotNull DocumentEvent e) { FormBuilder builder = FormBuilder .createFormBuilder(); + builder.addLabeledComponent("Address:", myAddress); builder.addLabeledComponent("Port:", myPort); + serverTraceComboBox = new ComboBox<>(new DefaultComboBoxModel<>(ServerTrace.values())); + builder.addLabeledComponent(DAPBundle.message("dap.settings.editor.server.serverTrace.field"), serverTraceComboBox); JPanel panel = new JPanel(new BorderLayout()); panel.add(builder.getPanel(), BorderLayout.CENTER); @@ -71,16 +79,21 @@ protected void textChanged(@NotNull DocumentEvent e) { @Override protected void resetEditorFrom(@NotNull Settings settings) { + myAddress.setText(settings.getAttachAddress()); myPort.setText(settings.getAttachPort()); + serverTraceComboBox.setSelectedItem(settings.getServerTrace()); } @Override protected void applyEditorTo(@NotNull Settings settings) throws ConfigurationException { + settings.setAttachAddress(myAddress.getText()); settings.setAttachPort(myPort.getText()); + settings.setServerTrace((ServerTrace) serverTraceComboBox.getSelectedItem()); } @Override protected @NotNull JComponent createEditor() { return root; } + } diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/options/ServerTraceConfigurable.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/options/ServerTraceConfigurable.java new file mode 100644 index 000000000..236c566a8 --- /dev/null +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/configurations/options/ServerTraceConfigurable.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2025 Red Hat, Inc. + * Distributed under license by Red Hat, Inc. All rights reserved. + * This program is made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, + * and is available at https://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + ******************************************************************************/ +package com.redhat.devtools.lsp4ij.dap.configurations.options; + +import com.redhat.devtools.lsp4ij.settings.ServerTrace; +import org.jetbrains.annotations.Nullable; + +/** + * Server trace configurable. + */ +public interface ServerTraceConfigurable { + + ServerTrace getServerTrace(); + + void setServerTrace(ServerTrace serverTrace); + +} diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/descriptors/DebugAdapterDescriptor.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/descriptors/DebugAdapterDescriptor.java index 0e99969c6..2f9fa68d5 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/descriptors/DebugAdapterDescriptor.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/descriptors/DebugAdapterDescriptor.java @@ -24,13 +24,10 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.net.NetUtils; import com.intellij.xdebugger.XDebugSession; -import com.intellij.xdebugger.breakpoints.XBreakpointProperties; -import com.intellij.xdebugger.breakpoints.XLineBreakpoint; import com.redhat.devtools.lsp4ij.dap.DAPDebugProcess; import com.redhat.devtools.lsp4ij.dap.DebugMode; import com.redhat.devtools.lsp4ij.dap.breakpoints.DAPBreakpointHandler; import com.redhat.devtools.lsp4ij.dap.breakpoints.DAPBreakpointHandlerBase; -import com.redhat.devtools.lsp4ij.dap.breakpoints.DAPBreakpointProperties; import com.redhat.devtools.lsp4ij.dap.client.DAPClient; import com.redhat.devtools.lsp4ij.dap.client.LaunchUtils; import com.redhat.devtools.lsp4ij.dap.configurations.DAPRunConfigurationOptions; @@ -223,6 +220,12 @@ public DebugMode getDebugMode() { @NotNull public ServerTrace getServerTrace() { + if (options instanceof DAPRunConfigurationOptions dapOptions) { + var serverTrace = dapOptions.getServerTrace(); + if (serverTrace != null) { + return serverTrace; + } + } return ServerTrace.getDefaultValue(); } diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/descriptors/DefaultDebugAdapterDescriptor.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/descriptors/DefaultDebugAdapterDescriptor.java index d0bc27751..058d09e36 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/descriptors/DefaultDebugAdapterDescriptor.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/descriptors/DefaultDebugAdapterDescriptor.java @@ -22,13 +22,10 @@ import com.redhat.devtools.lsp4ij.dap.DebugMode; import com.redhat.devtools.lsp4ij.dap.client.LaunchUtils; import com.redhat.devtools.lsp4ij.dap.configurations.DAPRunConfigurationOptions; -import com.redhat.devtools.lsp4ij.dap.configurations.options.AttachConfigurable; import com.redhat.devtools.lsp4ij.dap.configurations.options.FileOptionConfigurable; import com.redhat.devtools.lsp4ij.dap.definitions.DebugAdapterServerDefinition; -import com.redhat.devtools.lsp4ij.dap.definitions.userdefined.UserDefinedDebugAdapterServerDefinition; import com.redhat.devtools.lsp4ij.installation.CommandLineUpdater; import com.redhat.devtools.lsp4ij.internal.StringUtils; -import com.redhat.devtools.lsp4ij.settings.ServerTrace; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -129,14 +126,6 @@ public DebugMode getDebugMode() { return super.getDebugMode(); } - @NotNull - public ServerTrace getServerTrace() { - if (options instanceof DAPRunConfigurationOptions dapOptions) { - return dapOptions.getServerTrace(); - } - return super.getServerTrace(); - } - /** * Returns the DAP server name. * @@ -148,7 +137,7 @@ public String getServerName() { if (options instanceof DAPRunConfigurationOptions dapOptions) { serverName = dapOptions.getServerName(); } - if (StringUtils.isBlank(serverName) ) { + if (StringUtils.isBlank(serverName)) { return super.getServerName(); } return serverName; @@ -156,7 +145,7 @@ public String getServerName() { @Override public boolean isDebuggableFile(@NotNull VirtualFile file, @NotNull Project project) { - if(getServerDefinition() != null && + if (getServerDefinition() != null && super.isDebuggableFile(file, project)) { return true; } From ff0d103f07364336485c7ea61e0c7c96a42e455f Mon Sep 17 00:00:00 2001 From: azerr Date: Tue, 12 Aug 2025 15:01:13 +0200 Subject: [PATCH 012/264] fix: Failed to stop language server blocLanguageServer Fixes #1206 Signed-off-by: azerr --- .../lsp4ij/LanguageServerWrapper.java | 22 +++++++------------ .../diagnostics/LSPDiagnosticUtils.java | 19 ++++++++++------ 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/redhat/devtools/lsp4ij/LanguageServerWrapper.java b/src/main/java/com/redhat/devtools/lsp4ij/LanguageServerWrapper.java index 4695dd532..c15bf163f 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/LanguageServerWrapper.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/LanguageServerWrapper.java @@ -46,8 +46,8 @@ import com.redhat.devtools.lsp4ij.server.*; import com.redhat.devtools.lsp4ij.server.capabilities.TextDocumentServerCapabilityRegistry; import com.redhat.devtools.lsp4ij.server.definition.LanguageServerDefinition; -import com.redhat.devtools.lsp4ij.settings.ServerTrace; import com.redhat.devtools.lsp4ij.settings.ProjectLanguageServerSettings; +import com.redhat.devtools.lsp4ij.settings.ServerTrace; import org.eclipse.lsp4j.*; import org.eclipse.lsp4j.jsonrpc.Launcher; import org.eclipse.lsp4j.jsonrpc.MessageConsumer; @@ -68,6 +68,7 @@ import java.util.function.Function; import java.util.function.UnaryOperator; +import static com.redhat.devtools.lsp4ij.features.diagnostics.LSPDiagnosticUtils.clearProblem; import static com.redhat.devtools.lsp4ij.internal.CancellationSupport.showNotificationError; import static com.redhat.devtools.lsp4ij.internal.IntelliJPlatformUtils.getClientInfo; @@ -633,10 +634,10 @@ public synchronized CompletableFuture stop(boolean alreadyStopping) { while (!this.openedDocuments.isEmpty()) { disconnect(this.openedDocuments.keySet().iterator().next(), false); } - while (!this.closedDocuments.isEmpty()) { - URI fileUri = closedDocuments.keySet().iterator().next(); - closedDocuments.remove(fileUri); - clearProblem(fileUri); + if (!closedDocuments.isEmpty()) { + Set fileUris = new HashSet<>(closedDocuments.keySet()); + closedDocuments.clear(); + clearProblem(fileUris, getClientFeatures(), getProject()); } this.languageServer = null; this.languageClient = null; @@ -647,13 +648,6 @@ public synchronized CompletableFuture stop(boolean alreadyStopping) { } } - private void clearProblem(@NotNull URI fileUri) { - VirtualFile file = FileUriSupport.findFileByUri(fileUri.toASCIIString(), getClientFeatures()); - if (file != null && clientFeatures.getDiagnosticFeature().canReportProblem(file)) { - LSPDiagnosticUtils.clearProblem(file, getProject()); - } - } - private void shutdownAll(LanguageServer languageServerInstance, StreamConnectionProvider provider, Future serverFuture) { if (languageServerInstance != null && provider != null && provider.isAlive()) { // The LSP language server instance and the process which starts the language server is alive. Process @@ -886,7 +880,7 @@ void disconnect(@Nullable URI fileUri, boolean stopIfNoOpenedFiles) { DocumentContentSynchronizer synchronizer = openedDocument.getSynchronizer(); synchronizer.getDocument().removeDocumentListener(synchronizer); synchronizer.dispose(); - clearProblem(fileUri); + clearProblem(Collections.singleton(fileUri), getClientFeatures(), getProject()); } if (stopIfNoOpenedFiles) { maybeShutdown(); @@ -1462,7 +1456,7 @@ public Alarm getTraceFlushAlarm() { * * @param context the context used to control or customize the installation. * @return a {@link CompletableFuture} that completes with the {@link ServerInstallationStatus} - * once the installation process is done. + * once the installation process is done. */ public @NotNull CompletableFuture install(@NotNull ServerInstallationContext context) { // Get the configured server installer, if any diff --git a/src/main/java/com/redhat/devtools/lsp4ij/features/diagnostics/LSPDiagnosticUtils.java b/src/main/java/com/redhat/devtools/lsp4ij/features/diagnostics/LSPDiagnosticUtils.java index 9b63d7be2..d32e80d19 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/features/diagnostics/LSPDiagnosticUtils.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/features/diagnostics/LSPDiagnosticUtils.java @@ -18,17 +18,16 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.problems.WolfTheProblemSolver; import com.intellij.util.concurrency.AppExecutorUtil; -import com.redhat.devtools.lsp4ij.ClosedDocument; -import com.redhat.devtools.lsp4ij.LSPDocumentBase; -import com.redhat.devtools.lsp4ij.LanguageServiceAccessor; -import com.redhat.devtools.lsp4ij.OpenedDocument; +import com.redhat.devtools.lsp4ij.*; import com.redhat.devtools.lsp4ij.client.features.FileUriSupport; +import com.redhat.devtools.lsp4ij.client.features.LSPClientFeatures; import org.eclipse.lsp4j.Diagnostic; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.net.URI; import java.util.Collection; +import java.util.Set; import java.util.concurrent.Callable; /** @@ -150,14 +149,20 @@ public static boolean canReportProblem(@NotNull VirtualFile file, return false; } - public static void clearProblem(@NotNull VirtualFile file, + public static void clearProblem(@NotNull Set fileUris, + @NotNull LSPClientFeatures clientFeatures, @NotNull Project project) { WolfTheProblemSolver wolf = WolfTheProblemSolver.getInstance(project); ReadAction.nonBlocking((Callable) () -> { - wolf.clearProblemsFromExternalSource(file, LSP4IJ_REPORT_PROBLEM_SOURCE); + for (URI fileUri : fileUris) { + VirtualFile file = FileUriSupport.findFileByUri(fileUri.toASCIIString(), clientFeatures); + if (file != null && clientFeatures.getDiagnosticFeature().canReportProblem(file)) { + wolf.clearProblemsFromExternalSource(file, LSP4IJ_REPORT_PROBLEM_SOURCE); + } + } return null; }) - .coalesceBy(file, project) + .coalesceBy(clientFeatures, project) .submit(AppExecutorUtil.getAppExecutorService()); } } From c164d0e38387d3bd211c3ea4c378a83ed63e9a72 Mon Sep 17 00:00:00 2001 From: azerr Date: Thu, 14 Aug 2025 16:53:57 +0200 Subject: [PATCH 013/264] feat: show DAP variable value in hover Signed-off-by: azerr --- .../dap/evaluation/DAPDebuggerEvaluator.java | 78 ++++++++++++++++++- 1 file changed, 74 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/evaluation/DAPDebuggerEvaluator.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/evaluation/DAPDebuggerEvaluator.java index 9b0ed4574..26c779f41 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/evaluation/DAPDebuggerEvaluator.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/evaluation/DAPDebuggerEvaluator.java @@ -10,7 +10,13 @@ ******************************************************************************/ package com.redhat.devtools.lsp4ij.dap.evaluation; +import com.intellij.openapi.application.ReadAction; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.TextRange; +import com.intellij.util.concurrency.AppExecutorUtil; import com.intellij.xdebugger.XSourcePosition; +import com.intellij.xdebugger.evaluation.ExpressionInfo; import com.intellij.xdebugger.evaluation.XDebuggerEvaluator; import com.intellij.xdebugger.frame.XValueCallback; import com.redhat.devtools.lsp4ij.dap.client.DAPClient; @@ -22,6 +28,7 @@ import org.eclipse.lsp4j.jsonrpc.ResponseErrorException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.concurrency.Promise; import java.lang.reflect.Method; import java.util.concurrent.CompletionException; @@ -86,10 +93,14 @@ public void evaluate(@NotNull String expression, Object origin = getOriginMethod.invoke(callback); if (origin != null) { String originName = origin.toString(); - // REPL for XEvaluationOrigin.INLINE, XEvaluationOrigin.CONSOLE, XEvaluationOrigin.DIALOG - if ("INLINE".equals(originName) || "CONSOLE".equals(originName) || "DIALOG".equals(originName)) { - return EvaluateArgumentsContext.REPL; - } + return switch (originName) { + case "INLINE", "CONSOLE", + "DIALOG" -> // XEvaluationOrigin.INLINE, XEvaluationOrigin.CONSOLE, XEvaluationOrigin.DIALOG + EvaluateArgumentsContext.REPL; + case "EDITOR" -> // XEvaluationOrigin.EDITOR + EvaluateArgumentsContext.HOVER; + default -> EvaluateArgumentsContext.WATCH; + }; } } } catch (ClassNotFoundException e) { @@ -123,4 +134,63 @@ private static String getErrorMessage(@NotNull Throwable error) { return error.getMessage(); } + @Override + public @NotNull Promise getExpressionInfoAtOffsetAsync( + @NotNull Project project, + @NotNull Document document, + int offset, + boolean sideEffectsAllowed + ) { + return ReadAction.nonBlocking(() -> { + TextRange textRange = getTextRange(document, offset); + if (textRange == null) { + return null; + } + // Extract the expression text + String expression = getExpression(document, offset, textRange); + + // Build ExpressionInfo with the text range and expression string + return new ExpressionInfo(textRange, expression); + }).inSmartMode(project) + .withDocumentsCommitted(project) + .submit(AppExecutorUtil.getAppExecutorService()); + } + + protected @Nullable TextRange getTextRange(@NotNull Document document, + int offset) { + // Get the entire document text + String text = document.getText(); + + // Safety check: ensure offset is within bounds + if (offset < 0 || offset >= text.length()) { + return null; + } + + // Find the start of the identifier at the given offset + int start = offset; + while (start > 0) { + char ch = text.charAt(start - 1); + if (Character.isJavaIdentifierPart(ch) || ch == '.') { + start--; + } else { + break; + } + } + + // Find the end of the identifier at the given offset + int end = offset; + while (end < text.length() && Character.isJavaIdentifierPart(text.charAt(end))) { + end++; + } + + // If there is no identifier at the offset, do not return an expression + if (start == end) { + return null; + } + return new TextRange(start, end); + } + + protected @NotNull String getExpression(@NotNull Document document, int offset, TextRange textRange) { + return document.getText(textRange); + } } From 27b81ed76e3a8995dd731a38d73eab35c36239d7 Mon Sep 17 00:00:00 2001 From: azerr Date: Sun, 17 Aug 2025 19:03:39 +0200 Subject: [PATCH 014/264] feat: DAP API to customize debugger editors provider Signed-off-by: azerr --- .../redhat/devtools/lsp4ij/dap/DAPDebugProcess.java | 2 +- .../lsp4ij/dap/DAPDebuggerEditorsProvider.java | 13 ++++++++++++- .../dap/descriptors/DebugAdapterDescriptor.java | 7 +++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/DAPDebugProcess.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/DAPDebugProcess.java index 842dc4c1f..6e75e20a8 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/DAPDebugProcess.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/DAPDebugProcess.java @@ -101,8 +101,8 @@ public DAPDebugProcess(@NotNull DAPCommandLineState dapState, this.dapState = dapState; var project = getSession().getProject(); this.executionResult = executionResult; - this.editorsProvider = new DAPDebuggerEditorsProvider(dapState.getFileType(), this); this.serverDescriptor = dapState.getServerDescriptor(); + this.editorsProvider = serverDescriptor.createDebuggerEditorsProvider(dapState.getFileType(), this); this.breakpointHandler = serverDescriptor.createBreakpointHandler(session, project); this.threadsPanel = new ThreadsPanel(this); this.status = Status.NONE; diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/DAPDebuggerEditorsProvider.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/DAPDebuggerEditorsProvider.java index 8ad995713..83393b89a 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/DAPDebuggerEditorsProvider.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/DAPDebuggerEditorsProvider.java @@ -67,6 +67,17 @@ protected PsiFile createExpressionCodeFragment(@NotNull Project project, fileType = file.getFileType(); language = file.getLanguage(); } - return new DAPExpressionCodeFragment(text, fileType, language, debugProcess, project); + return createExpressionCodeFragment(project, text, fileType, language); + } + + protected @NotNull PsiFile createExpressionCodeFragment(@NotNull Project project, + @NotNull String text, + @NotNull FileType fileType, + @NotNull Language language) { + return new DAPExpressionCodeFragment(text, fileType, language, getDebugProcess(), project); + } + + protected @Nullable DAPDebugProcess getDebugProcess() { + return debugProcess; } } diff --git a/src/main/java/com/redhat/devtools/lsp4ij/dap/descriptors/DebugAdapterDescriptor.java b/src/main/java/com/redhat/devtools/lsp4ij/dap/descriptors/DebugAdapterDescriptor.java index 2f9fa68d5..daf1e5d06 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/dap/descriptors/DebugAdapterDescriptor.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/dap/descriptors/DebugAdapterDescriptor.java @@ -24,7 +24,9 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.net.NetUtils; import com.intellij.xdebugger.XDebugSession; +import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider; import com.redhat.devtools.lsp4ij.dap.DAPDebugProcess; +import com.redhat.devtools.lsp4ij.dap.DAPDebuggerEditorsProvider; import com.redhat.devtools.lsp4ij.dap.DebugMode; import com.redhat.devtools.lsp4ij.dap.breakpoints.DAPBreakpointHandler; import com.redhat.devtools.lsp4ij.dap.breakpoints.DAPBreakpointHandlerBase; @@ -278,4 +280,9 @@ public boolean isDebuggableFile(@NotNull VirtualFile file, @NotNull Project proj public @NotNull DAPBreakpointHandlerBase createBreakpointHandler(@NotNull XDebugSession session, Project project) { return new DAPBreakpointHandler(session, this, project); } + + public @NotNull XDebuggerEditorsProvider createDebuggerEditorsProvider(@Nullable FileType fileType, + @NotNull DAPDebugProcess debugProcess) { + return new DAPDebuggerEditorsProvider(fileType, debugProcess); + } } From 7e9f532a0157026ba4ac934a725ec0d903639df3 Mon Sep 17 00:00:00 2001 From: azerr Date: Wed, 20 Aug 2025 21:12:16 +0200 Subject: [PATCH 015/264] fix: `textDocument/didOpen` not called when language server doesn't support codelens, highlight, etc Fixes #1224 Signed-off-by: azerr --- ...umentToLanguageServerSetupParticipant.java | 55 ++++++++++++++----- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/redhat/devtools/lsp4ij/ConnectDocumentToLanguageServerSetupParticipant.java b/src/main/java/com/redhat/devtools/lsp4ij/ConnectDocumentToLanguageServerSetupParticipant.java index d176ea532..98b51aa28 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/ConnectDocumentToLanguageServerSetupParticipant.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/ConnectDocumentToLanguageServerSetupParticipant.java @@ -11,53 +11,81 @@ package com.redhat.devtools.lsp4ij; import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.fileEditor.FileEditorManagerEvent; import com.intellij.openapi.fileEditor.FileEditorManagerListener; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManagerListener; +import com.intellij.openapi.util.Key; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; +import com.redhat.devtools.lsp4ij.client.indexing.ProjectIndexingManager; import com.redhat.devtools.lsp4ij.lifecycle.LanguageServerLifecycleManager; import org.jetbrains.annotations.NotNull; /** - * Track file opened / closed to start language servers / disconnect file from language servers. + * Manages the connection between open editor files and Language Servers: + *
    + *
  • Starts Language Servers when a supported file becomes active in the editor.
  • + *
  • Releases resources when a file is closed.
  • + *
  • Properly stops Language Servers when the project is closed.
  • + *
*/ public class ConnectDocumentToLanguageServerSetupParticipant implements ProjectManagerListener, FileEditorManagerListener { @Override public void projectOpened(@NotNull Project project) { + // Subscribe to file open/close/selection events for this project. project.getMessageBus().connect().subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, this); } @Override public void projectClosing(@NotNull Project project) { + // Stop active Language Servers and clean up resources before the project is closed. LanguageServerLifecycleManager.getInstance(project).dispose(); LanguageServiceAccessor.getInstance(project).projectClosing(project); } @Override public void fileOpened(@NotNull FileEditorManager source, @NotNull VirtualFile file) { - Project project = source.getProject(); - // As document matcher requires read action, and language server starts can take some times, we connect the file in a future - // to avoid starting language server in the EDT Thread which could freeze IJ. - // Wait for indexing is finished and read action is enabled - // --> force the start of all languages servers mapped with the given file when indexing is finished and read action is allowed - /*ProjectIndexingManager + // Do not send textDocument/didOpen here: + // this method is also called when a file is opened in the background (tab not visible). + // To optimize performance, Language Servers are only started when the editor tab becomes active. + } + + @Override + public void selectionChanged(@NotNull FileEditorManagerEvent event) { + VirtualFile file = event.getNewFile(); + if (file == null) { + return; + } + var project = event.getManager().getProject(); + PsiFile psiFile = LSPIJUtils.getPsiFile(file, project); + if (psiFile == null || LSPFileSupport.hasSupport(psiFile)) { + // No PsiFile available, or the file is already connected to a Language Server. + return; + } + if (!LanguageServersRegistry.getInstance().isFileSupported(file, project)) { + return; + } + // Since file-to-server matching requires a read action, + // and Language Server startup may be expensive, + // schedule the connection asynchronously after indexing is finished. + ProjectIndexingManager .waitForIndexingAll() .thenApplyAsync(unused -> { connectToLanguageServer(file, project); return null; - });*/ + }); } @Override public void fileClosed(@NotNull FileEditorManager source, @NotNull VirtualFile file) { - // file is closed + // When a file is closed: PsiFile psiFile = LSPIJUtils.getPsiFile(file, source.getProject()); if (psiFile != null) { if (LSPFileSupport.hasSupport(psiFile)) { - // The closed file is mapped with language servers, dispose it - // to cancel all LSP codeLens, inlayHint, color, etc futures + // If the file is associated with a Language Server, + // release its resources (code lenses, inlay hints, color providers, etc.). LSPFileSupport.getSupport(psiFile).dispose(); } } @@ -66,12 +94,9 @@ public void fileClosed(@NotNull FileEditorManager source, @NotNull VirtualFile f private static void connectToLanguageServer(@NotNull VirtualFile file, @NotNull Project project) { PsiFile psiFile = LSPIJUtils.getPsiFile(file, project); if (psiFile != null) { - // Force the start of all languages servers mapped with the given file - // Server capabilities filter is set to null to avoid waiting - // for the start of the server when server capabilities are checked + // Force the startup of all Language Servers mapped to this file. LanguageServiceAccessor.getInstance(project) .getLanguageServers(psiFile, null, null); } } - } From 81fb2fb87ae8de2adc7d085d990f306e4320694e Mon Sep 17 00:00:00 2001 From: Siarhei Date: Tue, 19 Aug 2025 14:30:45 +0300 Subject: [PATCH 016/264] fix: Send didRenameFiles notifications to any language server that supports it, regardless of willRenameFiles support or execution status (#1216) --- .../refactoring/LSPRefactoringListener.java | 26 ++++++------------- .../refactoring/LSPRenameFilesContext.java | 14 +++++----- .../LSPRenamePsiElementProcessor.java | 24 ++++++++++------- 3 files changed, 31 insertions(+), 33 deletions(-) diff --git a/src/main/java/com/redhat/devtools/lsp4ij/features/refactoring/LSPRefactoringListener.java b/src/main/java/com/redhat/devtools/lsp4ij/features/refactoring/LSPRefactoringListener.java index d1e1b5501..80fbeaa0a 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/features/refactoring/LSPRefactoringListener.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/features/refactoring/LSPRefactoringListener.java @@ -12,7 +12,7 @@ import com.intellij.refactoring.listeners.RefactoringEventData; import com.intellij.refactoring.listeners.RefactoringEventListener; -import org.eclipse.lsp4j.RenameFilesParams; + import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -30,24 +30,14 @@ public void refactoringStarted(@NotNull String refactoringId, @Nullable Refactor @Override public void refactoringDone(@NotNull String refactoringId, @Nullable RefactoringEventData afterData) { LSPRenameFilesContext context = LSPRenameFilesContextHolder.get(); - if (context != null) { - var file = context.file(); - // A rename file has been done and some language servers have consumed their - // LSP 'workspace/willRenameFiles' request to collect and apply WorkspaceEdit, notify - // Send for those language servers an LSP 'workspace/didRenameFiles' notifications. - context.servers() - .forEach(languageServerItem -> { - var serverWrapper = languageServerItem.getServerWrapper(); - if (languageServerItem.getClientFeatures().getRenameFeature().isDidRenameFilesSupported(file)) { - serverWrapper.sendNotification(ls -> { - RenameFilesParams params = context.params(); - ls.getWorkspaceService() - .didRenameFiles(params); - return ls; - }); - } - }); + + if (context == null) { + return; } + + context.renameFilesParams() + .forEach((ls, params) -> ls.getWorkspaceService().didRenameFiles(params)); + LSPRenameFilesContextHolder.set(null); } diff --git a/src/main/java/com/redhat/devtools/lsp4ij/features/refactoring/LSPRenameFilesContext.java b/src/main/java/com/redhat/devtools/lsp4ij/features/refactoring/LSPRenameFilesContext.java index f88ac1241..fa81298ae 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/features/refactoring/LSPRenameFilesContext.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/features/refactoring/LSPRenameFilesContext.java @@ -10,18 +10,20 @@ ******************************************************************************/ package com.redhat.devtools.lsp4ij.features.refactoring; +import java.util.Map; + import com.intellij.psi.PsiFile; import com.redhat.devtools.lsp4ij.LanguageServerItem; -import org.eclipse.lsp4j.RenameFilesParams; -import java.util.List; +import org.eclipse.lsp4j.RenameFilesParams; +import org.jetbrains.annotations.NotNull; /** * LSP rename files context. * - * @param params - * @param servers - * @param file + * @param file the PSI file being renamed + * @param renameFilesParams map of language server items to their corresponding rename file parameters */ -public record LSPRenameFilesContext(RenameFilesParams params, List servers, PsiFile file) { +public record LSPRenameFilesContext(@NotNull PsiFile file, + @NotNull Map renameFilesParams) { } diff --git a/src/main/java/com/redhat/devtools/lsp4ij/features/refactoring/LSPRenamePsiElementProcessor.java b/src/main/java/com/redhat/devtools/lsp4ij/features/refactoring/LSPRenamePsiElementProcessor.java index 3adbb4177..154f1c022 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/features/refactoring/LSPRenamePsiElementProcessor.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/features/refactoring/LSPRenamePsiElementProcessor.java @@ -41,9 +41,13 @@ import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import java.util.function.Function; +import java.util.stream.Collectors; import static com.redhat.devtools.lsp4ij.internal.CompletableFutures.isDoneNormally; import static com.redhat.devtools.lsp4ij.internal.CompletableFutures.waitUntilDone; +import static java.util.function.Function.identity; +import static java.util.stream.Collectors.toMap; /** * LSP {@link RenamePsiElementProcessor} implementation to consume @@ -66,17 +70,15 @@ public void prepareRenaming(@NotNull PsiElement element, @NotNull SearchScope scope) { PsiFile file = element.getContainingFile(); var project = file.getProject(); - - // Create LSP rename files parameters. - Map paramsPerServer = new HashMap<>(); - + Map didRenameParameters= new HashMap<>(); // Prepare future of LSP 'workspace/willRenameFiles' request CancellationSupport cancellationSupport = new CancellationSupport(); var willRenameFilesFuture = LanguageServiceAccessor.getInstance(project) .getLanguageServers(file, null, - f -> f.getRenameFeature().isWillRenameFilesSupported(file)) + f -> f.getRenameFeature().isWillRenameFilesSupported(file) || + f.getRenameFeature().isDidRenameFilesSupported(file)) .thenComposeAsync(languageServerItems -> { if (languageServerItems.isEmpty()) { @@ -88,7 +90,6 @@ public void prepareRenaming(@NotNull PsiElement element, .filter(ls -> ls.isWillRenameFilesSupported(file)) .map(ls -> { var params = createtRenameFilesParams(file, newName, ls.getClientFeatures()); - paramsPerServer.put(ls.getServerWrapper(), params); return cancellationSupport .execute(ls.getWorkspaceService().willRenameFiles(params), ls, @@ -97,6 +98,12 @@ public void prepareRenaming(@NotNull PsiElement element, }) .toList(); + languageServerItems.stream() + .filter(ls -> ls.getServerWrapper().isDidRenameFilesSupported(file)) + .forEach(ls -> didRenameParameters.put(ls, + createtRenameFilesParams(file, newName, ls.getClientFeatures()))); + + // TODO: we return the WorkspaceEdit of the first language server, what about when there are several // language servers which returns WorkspaceEdit? return r.isEmpty() ? CompletableFuture.completedFuture(null) : r.get(0); @@ -114,13 +121,12 @@ public void prepareRenaming(@NotNull PsiElement element, LOGGER.error("Error while consuming LSP 'workspace/willRenameFiles' request", e); } + LSPRenameFilesContextHolder.set(new LSPRenameFilesContext(file, didRenameParameters)); + if (isDoneNormally(willRenameFilesFuture)) { // Future has been done correctly, create a fake PsiElement which stores the WorkspaceEdit WorkspaceEditData editData = willRenameFilesFuture.getNow(null); if (editData != null && editData.edit() != null) { - var params = paramsPerServer.get(editData.languageServer().getServerWrapper()); - LSPRenameFilesContextHolder.set(new LSPRenameFilesContext(params, Collections.singletonList(editData.languageServer()), file)); - var edit = editData.edit(); var fileUriSupport = editData.languageServer().getClientFeatures(); var documentChanges = edit.getDocumentChanges(); From 622bd069cd966b0112bca45763c8f25920aedf32 Mon Sep 17 00:00:00 2001 From: Siarhei Date: Wed, 20 Aug 2025 13:48:06 +0300 Subject: [PATCH 017/264] keep serverWrapper.sendNotification which uses a proper Thread pooling to send notification --- .../features/refactoring/LSPRefactoringListener.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/redhat/devtools/lsp4ij/features/refactoring/LSPRefactoringListener.java b/src/main/java/com/redhat/devtools/lsp4ij/features/refactoring/LSPRefactoringListener.java index 80fbeaa0a..be09a329c 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/features/refactoring/LSPRefactoringListener.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/features/refactoring/LSPRefactoringListener.java @@ -35,8 +35,11 @@ public void refactoringDone(@NotNull String refactoringId, @Nullable Refactoring return; } - context.renameFilesParams() - .forEach((ls, params) -> ls.getWorkspaceService().didRenameFiles(params)); + context.renameFilesParams().forEach((languageServerItem, params) -> + languageServerItem.getServerWrapper().sendNotification(ls -> { + ls.getWorkspaceService().didRenameFiles(params); + return ls; + })); LSPRenameFilesContextHolder.set(null); } From 368d01275dc2abcca87b376eb747b3b81ce2416b Mon Sep 17 00:00:00 2001 From: azerr Date: Thu, 21 Aug 2025 15:32:47 +0200 Subject: [PATCH 018/264] fix: don't show LS editor notif when a given plugin is installed Signed-off-by: azerr --- .../launching/templates/LanguageServerTemplate.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/redhat/devtools/lsp4ij/launching/templates/LanguageServerTemplate.java b/src/main/java/com/redhat/devtools/lsp4ij/launching/templates/LanguageServerTemplate.java index 48cc47fc3..d61f901b7 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/launching/templates/LanguageServerTemplate.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/launching/templates/LanguageServerTemplate.java @@ -127,22 +127,23 @@ public Set getDisablePromotionFor() { * @return {@code true} if the template should be promoted; {@code false} otherwise. */ public boolean isPromotable() { + if (promotable != null) { + return promotable; + } if (disablePromotionFor == null || disablePromotionFor.isEmpty()) { return true; } - if (promotable == null) { - promotable = computePromotable(); - } + promotable = computePromotable(); return promotable; } private boolean computePromotable() { for (var pluginId : disablePromotionFor) { if (isPluginInstalled(pluginId)) { - return true; + return false; } } - return false; + return true; } private static boolean isPluginInstalled(String pluginIdString) { From d81f1c68f77fb17a4b7bf8a5eee430a8bdb753f7 Mon Sep 17 00:00:00 2001 From: azerr Date: Fri, 22 Aug 2025 10:13:48 +0200 Subject: [PATCH 019/264] feat: add EO LSP Server Signed-off-by: azerr --- docs/UserDefinedLanguageServer.md | 1 + .../user-defined-ls/eo-lsp-server/demo_ls.gif | Bin 0 -> 114284 bytes .../eo-lsp-server/installer_tab.png | Bin 0 -> 68545 bytes .../language_server_installing.png | Bin 0 -> 48852 bytes .../new_language_server_dialog.png | Bin 0 -> 57234 bytes .../eo-lsp-server/open_file.png | Bin 0 -> 42806 bytes .../textmate_bundles_settings.png | Bin 0 -> 116210 bytes docs/user-defined-ls/eo-lsp-server.md | 53 ++++++++++++++++++ .../lsp/eo-lsp-server/clientSettings.json | 1 + .../lsp/eo-lsp-server/installer.json | 37 ++++++++++++ .../templates/lsp/eo-lsp-server/settings.json | 3 + .../lsp/eo-lsp-server/settings.schema.json | 15 +++++ .../templates/lsp/eo-lsp-server/template.json | 19 +++++++ 13 files changed, 129 insertions(+) create mode 100644 docs/images/user-defined-ls/eo-lsp-server/demo_ls.gif create mode 100644 docs/images/user-defined-ls/eo-lsp-server/installer_tab.png create mode 100644 docs/images/user-defined-ls/eo-lsp-server/language_server_installing.png create mode 100644 docs/images/user-defined-ls/eo-lsp-server/new_language_server_dialog.png create mode 100644 docs/images/user-defined-ls/eo-lsp-server/open_file.png create mode 100644 docs/images/user-defined-ls/eo-lsp-server/textmate_bundles_settings.png create mode 100644 docs/user-defined-ls/eo-lsp-server.md create mode 100644 src/main/resources/templates/lsp/eo-lsp-server/clientSettings.json create mode 100644 src/main/resources/templates/lsp/eo-lsp-server/installer.json create mode 100644 src/main/resources/templates/lsp/eo-lsp-server/settings.json create mode 100644 src/main/resources/templates/lsp/eo-lsp-server/settings.schema.json create mode 100644 src/main/resources/templates/lsp/eo-lsp-server/template.json diff --git a/docs/UserDefinedLanguageServer.md b/docs/UserDefinedLanguageServer.md index 6094bf911..9c6bedc5e 100644 --- a/docs/UserDefinedLanguageServer.md +++ b/docs/UserDefinedLanguageServer.md @@ -155,6 +155,7 @@ pre-filled with server name, command, mappings and potential configuration. * [Clojure LSP](./user-defined-ls/clojure-lsp.md) * [Dart LSP](./user-defined-ls/dart-lsp.md) * [Docker Language Server](./user-defined-ls/docker-language-server.md) +* [EO LSP Server](./user-defined-ls/eo-lsp-server.md) * [Erlang Language Server](./user-defined-ls/erlang-ls.md) * [ESLint Language Server](./user-defined-ls/vscode-eslint-language-server.md) * [Go Language Server](./user-defined-ls/gopls.md) diff --git a/docs/images/user-defined-ls/eo-lsp-server/demo_ls.gif b/docs/images/user-defined-ls/eo-lsp-server/demo_ls.gif new file mode 100644 index 0000000000000000000000000000000000000000..10b56dade9b1ad04071b03f8abe9d81c8d2b7117 GIT binary patch literal 114284 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

sw&EBs;cXNKR|6` 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 literal 0 HcmV?d00001 diff --git a/docs/images/user-defined-ls/eo-lsp-server/installer_tab.png b/docs/images/user-defined-ls/eo-lsp-server/installer_tab.png new file mode 100644 index 0000000000000000000000000000000000000000..f676b659132f90031023fd793e6014a17542f50f GIT binary patch literal 68545 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 literal 0 HcmV?d00001 diff --git a/docs/images/user-defined-ls/eo-lsp-server/language_server_installing.png b/docs/images/user-defined-ls/eo-lsp-server/language_server_installing.png new file mode 100644 index 0000000000000000000000000000000000000000..6a6d4b7585feb380c2e73cc6b2451a7ab9a1cad5 GIT binary patch literal 48852 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

01@g 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 literal 0 HcmV?d00001 diff --git a/docs/images/user-defined-ls/eo-lsp-server/open_file.png b/docs/images/user-defined-ls/eo-lsp-server/open_file.png new file mode 100644 index 0000000000000000000000000000000000000000..51798077b6dbfa1f61d25672fdfc41ce69ae3b54 GIT binary patch literal 42806 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 literal 0 HcmV?d00001 diff --git a/docs/images/user-defined-ls/eo-lsp-server/textmate_bundles_settings.png b/docs/images/user-defined-ls/eo-lsp-server/textmate_bundles_settings.png new file mode 100644 index 0000000000000000000000000000000000000000..573847b9cdddd3380929f25418b5da5685b19478 GIT binary patch literal 116210 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%0Am9-`mdxoZy`iY&tx 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Ì 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 Date: Fri, 22 Aug 2025 12:25:48 +0200 Subject: [PATCH 020/264] fix: fix typo with eo-lsp-server id Signed-off-by: azerr --- src/main/resources/templates/lsp/eo-lsp-server/installer.json | 2 +- src/main/resources/templates/lsp/eo-lsp-server/template.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/templates/lsp/eo-lsp-server/installer.json b/src/main/resources/templates/lsp/eo-lsp-server/installer.json index 4bd6983e9..3249b4356 100644 --- a/src/main/resources/templates/lsp/eo-lsp-server/installer.json +++ b/src/main/resources/templates/lsp/eo-lsp-server/installer.json @@ -1,5 +1,5 @@ { - "id": "eo-lsp-serverr", + "id": "eo-lsp-server", "name": "LSP Server for EOLANG", "executeOnStartServer": false, "properties": { diff --git a/src/main/resources/templates/lsp/eo-lsp-server/template.json b/src/main/resources/templates/lsp/eo-lsp-server/template.json index 9a90070f4..45dde6c13 100644 --- a/src/main/resources/templates/lsp/eo-lsp-server/template.json +++ b/src/main/resources/templates/lsp/eo-lsp-server/template.json @@ -1,5 +1,5 @@ { - "id": "eo-lsp-serverr", + "id": "eo-lsp-server", "name": "LSP Server for EOLANG", "programArgs": { "windows": "cmd /C eo-lsp-server.cmd --stdio", From 83d5c16a2e203ba464c9365fa92e5fe865a266b2 Mon Sep 17 00:00:00 2001 From: azerr Date: Mon, 25 Aug 2025 13:54:48 +0200 Subject: [PATCH 021/264] feat: Allow fully publishing diagnostics on documents not specified in the file associations? Fixes #1232 Signed-off-by: azerr --- .../diagnostics/LSPDiagnosticAnnotator.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/redhat/devtools/lsp4ij/features/diagnostics/LSPDiagnosticAnnotator.java b/src/main/java/com/redhat/devtools/lsp4ij/features/diagnostics/LSPDiagnosticAnnotator.java index f6ce8d079..9fdd904eb 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/features/diagnostics/LSPDiagnosticAnnotator.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/features/diagnostics/LSPDiagnosticAnnotator.java @@ -51,21 +51,23 @@ public LSPDiagnosticAnnotator() { @Nullable @Override public Boolean collectInformation(@NotNull PsiFile file, @NotNull Editor editor, boolean hasErrors) { - if (!LanguageServersRegistry.getInstance().isFileSupported(file)) { - return Boolean.FALSE; - } // Loop for language server which report diagnostics for the given file // and mark all opened documents as 'displaying diagnostics' var servers = LanguageServiceAccessor.getInstance(file.getProject()) .getStartedServers(); + if (servers.isEmpty()) { + return Boolean.FALSE; + } + boolean hasOpenedDocument = false; for (var ls : servers) { URI fileUri = FileUriSupport.getFileUri(file.getVirtualFile(), ls.getClientFeatures()); OpenedDocument openedDocument = ls.getOpenedDocument(fileUri); if (openedDocument != null) { + hasOpenedDocument = true; openedDocument.markAsDisplayingDiagnostics(); } } - return Boolean.TRUE; + return hasOpenedDocument; } @Override @@ -78,6 +80,11 @@ public void doApply(@NotNull PsiFile psiFile, Boolean applyAnnotator, @NotNull A if (!applyAnnotator) { return; } + var servers = LanguageServiceAccessor.getInstance(psiFile.getProject()) + .getStartedServers(); + if (servers.isEmpty()) { + return; + } VirtualFile file = psiFile.getVirtualFile(); if (file == null) { return; @@ -88,8 +95,6 @@ public void doApply(@NotNull PsiFile psiFile, Boolean applyAnnotator, @NotNull A return; } // Loop for language server which report diagnostics for the given file - var servers = LanguageServiceAccessor.getInstance(psiFile.getProject()) - .getStartedServers(); for (var ls : servers) { URI fileUri = FileUriSupport.getFileUri(file, ls.getClientFeatures()); OpenedDocument openedDocument = ls.getOpenedDocument(fileUri); From 3d81f01e5ef891e64f6a258d320df95838e71199 Mon Sep 17 00:00:00 2001 From: azerr Date: Tue, 26 Aug 2025 08:28:38 +0200 Subject: [PATCH 022/264] docs: add 1.15.0 changelog Signed-off-by: azerr --- src/main/resources/META-INF/plugin.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index e1865c9da..cab949e92 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -5,6 +5,14 @@ Red-Hat 0.15.0 +

+ Learn more in the changelog. +

0.14.2