Skip to content

Commit 4a429af

Browse files
Basic support for onTypeFormatting (#1255)
1 parent 9c26ffa commit 4a429af

4 files changed

Lines changed: 82 additions & 1 deletion

File tree

org.eclipse.lsp4e/plugin.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -926,5 +926,12 @@
926926
id="org.eclipse.lsp4e.pathParameterType"
927927
type="org.eclipse.core.runtime.IPath" />
928928
</extension>
929+
<extension
930+
point="org.eclipse.ui.genericeditor.autoEditStrategies">
931+
<autoEditStrategy
932+
class="org.eclipse.lsp4e.format.DocumentFormatOnTypeAutoEditStrategy"
933+
contentType="org.eclipse.core.runtime.text">
934+
</autoEditStrategy>
935+
</extension>
929936

930937
</plugin>

org.eclipse.lsp4e/src/org/eclipse/lsp4e/LanguageServerWrapper.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
import org.eclipse.lsp4j.CodeActionOptions;
8383
import org.eclipse.lsp4j.DidChangeWorkspaceFoldersParams;
8484
import org.eclipse.lsp4j.DocumentFormattingOptions;
85+
import org.eclipse.lsp4j.DocumentOnTypeFormattingOptions;
8586
import org.eclipse.lsp4j.DocumentRangeFormattingOptions;
8687
import org.eclipse.lsp4j.ExecuteCommandOptions;
8788
import org.eclipse.lsp4j.InitializeParams;
@@ -1040,6 +1041,11 @@ void registerCapability(RegistrationParams params) {
10401041
serverCapabilities.setTypeHierarchyProvider(Boolean.TRUE);
10411042
addRegistration(reg, () -> serverCapabilities.setTypeHierarchyProvider(typeHierarchyBeforeRegistration));
10421043
break;
1044+
case "textDocument/onTypeFormatting": //$NON-NLS-1$
1045+
final var onTypeFormattingBeforeRegistration = serverCapabilities.getDocumentOnTypeFormattingProvider();
1046+
serverCapabilities.setDocumentOnTypeFormattingProvider(reg.getRegisterOptions() instanceof DocumentOnTypeFormattingOptions opts ? opts : null);
1047+
addRegistration(reg, () -> serverCapabilities.setDocumentOnTypeFormattingProvider(onTypeFormattingBeforeRegistration));
1048+
break;
10431049
}});
10441050
}
10451051

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 Red Hat, Inc.
3+
* This program and the accompanying materials are made
4+
* available under the terms of the Eclipse Public License 2.0
5+
* which is available at https://www.eclipse.org/legal/epl-2.0/
6+
*
7+
* SPDX-License-Identifier: EPL-2.0
8+
*******************************************************************************/
9+
package org.eclipse.lsp4e.format;
10+
11+
import org.eclipse.jdt.annotation.Nullable;
12+
import org.eclipse.jface.text.BadLocationException;
13+
import org.eclipse.jface.text.DocumentCommand;
14+
import org.eclipse.jface.text.IAutoEditStrategy;
15+
import org.eclipse.jface.text.IDocument;
16+
import org.eclipse.lsp4e.LSPEclipseUtils;
17+
import org.eclipse.lsp4e.LanguageServerPlugin;
18+
import org.eclipse.lsp4e.LanguageServers;
19+
import org.eclipse.lsp4e.operations.format.LSPFormatter;
20+
import org.eclipse.lsp4j.DocumentOnTypeFormattingParams;
21+
import org.eclipse.lsp4j.FormattingOptions;
22+
import org.eclipse.lsp4j.TextDocumentIdentifier;
23+
import org.eclipse.lsp4j.jsonrpc.messages.Either;
24+
25+
public class DocumentFormatOnTypeAutoEditStrategy implements IAutoEditStrategy {
26+
27+
@Override
28+
public void customizeDocumentCommand(@Nullable IDocument document, @Nullable DocumentCommand command) {
29+
if (document == null || command == null || command.getCommandCount() > 1 || command.text.isEmpty()) {
30+
return;
31+
}
32+
var executor = LanguageServers.forDocument(document)
33+
.withCapability(capabilities -> Either.forLeft(capabilities.getDocumentOnTypeFormattingProvider() != null
34+
&& (command.text.equals(capabilities.getDocumentOnTypeFormattingProvider().getFirstTriggerCharacter()) ||
35+
(capabilities.getDocumentOnTypeFormattingProvider().getMoreTriggerCharacter() != null && capabilities.getDocumentOnTypeFormattingProvider().getMoreTriggerCharacter().contains(command.text)))));
36+
if (!executor.anyMatching()) {
37+
return;
38+
}
39+
FormattingOptions formattingOptions = LSPFormatter.getFormatOptions();
40+
TextDocumentIdentifier textDocumentIdentifier = LSPEclipseUtils.toTextDocumentIdentifier(document);
41+
if (textDocumentIdentifier == null) {
42+
return;
43+
}
44+
try {
45+
DocumentOnTypeFormattingParams params = new DocumentOnTypeFormattingParams(textDocumentIdentifier, formattingOptions, LSPEclipseUtils.toPosition(command.offset, document), command.text);
46+
executor.computeFirst(ls -> ls.getTextDocumentService().onTypeFormatting(params)).join()
47+
.ifPresent(edits -> {
48+
edits.forEach(edit -> {
49+
try {
50+
int fromOffset = LSPEclipseUtils.toOffset(edit.getRange().getStart(), document);
51+
int toOffset = LSPEclipseUtils.toOffset(edit.getRange().getEnd(), document);
52+
if (fromOffset == command.offset) {
53+
command.text += edit.getNewText();
54+
} else {
55+
command.addCommand(fromOffset, toOffset - fromOffset, edit.getNewText(), null);
56+
}
57+
} catch (BadLocationException ex) {
58+
LanguageServerPlugin.logError(ex);
59+
}
60+
});
61+
});
62+
} catch (BadLocationException e) {
63+
LanguageServerPlugin.logError(e);
64+
}
65+
}
66+
67+
}

org.eclipse.lsp4e/src/org/eclipse/lsp4e/internal/SupportedFeatures.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import org.eclipse.lsp4j.InlayHintCapabilities;
4343
import org.eclipse.lsp4j.InsertTextMode;
4444
import org.eclipse.lsp4j.MarkupKind;
45+
import org.eclipse.lsp4j.OnTypeFormattingCapabilities;
4546
import org.eclipse.lsp4j.PublishDiagnosticsCapabilities;
4647
import org.eclipse.lsp4j.RangeFormattingCapabilities;
4748
import org.eclipse.lsp4j.ReferencesCapabilities;
@@ -129,7 +130,7 @@ public static TextDocumentClientCapabilities getTextDocumentClientCapabilities()
129130
MarkupKind.MARKDOWN, //
130131
MarkupKind.PLAINTEXT));
131132
textDocumentClientCapabilities.setHover(hoverCapabilities);
132-
textDocumentClientCapabilities.setOnTypeFormatting(null); // TODO
133+
textDocumentClientCapabilities.setOnTypeFormatting(new OnTypeFormattingCapabilities(true));
133134
textDocumentClientCapabilities.setRangeFormatting(new RangeFormattingCapabilities());
134135
textDocumentClientCapabilities.setReferences(new ReferencesCapabilities());
135136
final var renameCapabilities = new RenameCapabilities();

0 commit comments

Comments
 (0)