GH-1154: removed logic to handle client-side magic indentation, no longer necessary as completions are marked as-is for indentation

This commit is contained in:
Martin Lippert
2024-04-23 11:39:52 +02:00
parent 9b35be3bb1
commit 029cc73476
8 changed files with 62 additions and 123 deletions

View File

@@ -15,7 +15,7 @@ else
fi
cd ${sources}
xvfb-run ./mvnw clean install -DargLine="-Dlsp.completions.indentation.enable=true -Dlsp.yaml.completions.errors.disable=true"
xvfb-run ./mvnw clean install -DargLine="-Dlsp.yaml.completions.errors.disable=true"
# Copy fatjars to `out` directory
timestamp=`date -u +%Y%m%d%H%M`

View File

@@ -43,7 +43,6 @@ public class SpringBootLanguageServer extends STS4LanguageServerProcessStreamCon
// args.add("-Xdebug");
// args.add("-Xrunjdwp:server=y,transport=dt_socket,address=1044,suspend=n");
args.add("-Dlsp.completions.indentation.enable=true");
args.add("-Xmx1024m");
args.add("-XX:TieredStopAtLevel=1");

View File

@@ -31,7 +31,6 @@ public class BoshLanguageServer extends STS4LanguageServerProcessStreamConnector
"application.properties",
Arrays.asList(
"-Dlsp.lazy.completions.disable=true",
"-Dlsp.completions.indentation.enable=true",
"-XX:TieredStopAtLevel=1"
)
);

View File

@@ -47,7 +47,6 @@ public class CloudFoundryManifestLanguageServer extends STS4LanguageServerProces
"application.properties",
Arrays.asList(
"-Dlsp.lazy.completions.disable=true",
"-Dlsp.completions.indentation.enable=true",
"-XX:TieredStopAtLevel=1"
)
);

View File

@@ -31,7 +31,6 @@ public class ConcourseLanguageServer extends STS4LanguageServerProcessStreamConn
"application.properties",
Arrays.asList(
"-Dlsp.lazy.completions.disable=true",
"-Dlsp.completions.indentation.enable=true",
"-XX:TieredStopAtLevel=1"
)
);

View File

@@ -48,9 +48,7 @@ import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguage
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
import org.springframework.ide.vscode.commons.languageserver.util.SortKeys;
import org.springframework.ide.vscode.commons.protocol.CursorMovement;
import org.springframework.ide.vscode.commons.util.BadLocationException;
import org.springframework.ide.vscode.commons.util.Renderable;
import org.springframework.ide.vscode.commons.util.StringUtil;
import org.springframework.ide.vscode.commons.util.text.IRegion;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
@@ -399,7 +397,7 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine {
private void resolveMainEdit(TextDocument doc, ICompletionProposal completion, CompletionItem item) {
AtomicBoolean usedSnippets = new AtomicBoolean();
Optional<TextEdit> mainEdit = adaptEdits(doc, completion.getTextEdit(), usedSnippets, isCommandExecution(item));
Optional<TextEdit> mainEdit = adaptEdits(doc, completion.getTextEdit(), usedSnippets);
if (mainEdit.isPresent()) {
item.setTextEdit(Either.forLeft(mainEdit.get()));
if (server.hasCompletionSnippetSupport()) {
@@ -419,7 +417,7 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine {
if (!edit.isResolved()) {
edit.resolve();
}
adaptEdits(doc, edit, null, isCommandExecution(item)).ifPresent(extraEdit -> {
adaptEdits(doc, edit, null).ifPresent(extraEdit -> {
item.setAdditionalTextEdits(ImmutableList.of(extraEdit));
});
} else {
@@ -435,7 +433,7 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine {
return null;
}
private Optional<TextEdit> adaptEdits(TextDocument doc, DocumentEdits edits, AtomicBoolean usedSnippets, boolean ignoreClientIndent) {
private Optional<TextEdit> adaptEdits(TextDocument doc, DocumentEdits edits, AtomicBoolean usedSnippets) {
try {
TextReplace replaceEdit = edits == null ? null : edits.asReplacement(doc);
if (usedSnippets != null && edits != null) {
@@ -448,9 +446,10 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine {
TextDocument newDoc = doc.copy();
edits.apply(newDoc);
TextEdit vscodeEdit = new TextEdit();
vscodeEdit.setRange(doc.toRange(replaceEdit.start, replaceEdit.end-replaceEdit.start));
vscodeEdit.setRange(doc.toRange(replaceEdit.start, replaceEdit.end - replaceEdit.start));
String newText = replaceEdit.newText;
IRegion selection = edits.getSelection();
if (selection!=null && usedSnippets != null) {
//Special handling for the case where cursor is *not* just at the end of the newText
int cursor = selection.getOffset() + selection.getLength();
@@ -465,9 +464,7 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine {
usedSnippets.set(true);
}
}
// if (isMagicIndentingClient() && !ignoreClientIndent) {
// newText = vscodeIndentFix(doc, vscodeEdit.getRange().getStart(), replaceEdit.newText);
// }
vscodeEdit.setNewText(newText);
return Optional.of(vscodeEdit);
}
@@ -477,42 +474,6 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine {
}
}
/**
* When this is true, it means the client does 'magic indents' (basically.. that is only on vscode since the magics aren't part of the LSP spec).
*/
// private boolean isMagicIndentingClient() {
// return !Boolean.getBoolean("lsp.completions.indentation.enable");
// }
private static String vscodeIndentFix(TextDocument doc, Position start, String newText) {
//Vscode applies some magic indent to a multi-line edit text. We do everything ourself so we have adjust for the magic
// and do some kind of 'inverse magic' here.
//See here: https://github.com/Microsoft/language-server-protocol/issues/83
IndentUtil indenter = new IndentUtil(doc);
try {
String refIndent = indenter.getReferenceIndent(doc.toOffset(start), doc);
if (!refIndent.isEmpty()) {
return StringUtil.stripIndentation(refIndent, newText);
}
} catch (BadLocationException e) {
log.error("{}", e);
}
return newText;
}
private static String revertVscodeIndentFix(TextDocument doc, Position start, String newText) {
IndentUtil indenter = new IndentUtil(doc);
try {
String refIndent = indenter.getReferenceIndent(doc.toOffset(start), doc);
if (!refIndent.isEmpty()) {
return StringUtil.reverseStripIndentation(refIndent, newText);
}
} catch (BadLocationException e) {
log.error("{}", e);
}
return newText;
}
@Override
public CompletionItem resolveCompletion(CancelChecker cancelToken, CompletionItem unresolved) {
resolver.resolveNow(cancelToken, unresolved);
@@ -532,7 +493,4 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine {
}
private boolean isCommandExecution(CompletionItem item) {
return RESOLVE_EDIT_COMMAND == item.getLabel();
}
}

View File

@@ -465,18 +465,6 @@ public class Editor {
String replaceWith = edit.getLeft().getNewText();
int cursorReplaceOffset = 0;
// if (!Boolean.getBoolean("lsp.completions.indentation.enable")) {
// //Apply indentfix, this is magic vscode seems to apply to edits returned by language server. So our harness has to
// // mimick that behavior. See https://github.com/Microsoft/language-server-protocol/issues/83
// int referenceLine = edit.getLeft().getRange().getStart().getLine();
// int cursorOffset = edit.getLeft().getRange().getStart().getCharacter();
// String referenceIndent = doc.getLineIndentString(referenceLine);
// if (cursorOffset<referenceIndent.length()) {
// referenceIndent = referenceIndent.substring(0, cursorOffset);
// }
// replaceWith = replaceWith.replaceAll("\\n", "\n"+referenceIndent);
// }
// Replace the cursor string
cursorReplaceOffset = replaceWith.indexOf(VS_CODE_CURSOR_MARKER);
if (cursorReplaceOffset >= 0) {

View File

@@ -651,68 +651,65 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest {
//This test not working in vscode. It is only meant to work in environment that
// a) don't apply magic indents
// b) allow completions with no restrictions on the main edit.
withSystemProperty("lsp.completions.indentation.enable", "true", () -> {
String[] names = {"foo", "nested", "bar"};
int levels = 4;
generateNestedProperties(levels, names, "");
String[] names = {"foo", "nested", "bar"};
int levels = 4;
generateNestedProperties(levels, names, "");
//Note: jumpy completions use the snippet '$0' placeholder to move the cursor
//Our harness actually does not understand / interpret snippet placeholders.
//Thus the examples below expected outcome will have both a '$0' and '<*>'
//showing the cursor position. You can think of the second '<*>' as showing
//where the cursor will end up when the client doesn't have snippet support capability.
//Note: jumpy completions use the snippet '$0' placeholder to move the cursor
//Our harness actually does not understand / interpret snippet placeholders.
//Thus the examples below expected outcome will have both a '$0' and '<*>'
//showing the cursor position. You can think of the second '<*>' as showing
//where the cursor will end up when the client doesn't have snippet support capability.
assertCompletion(
"foo:\n" +
" nested:\n" +
" bar:\n" +
" foo:\n" +
"other:\n" +
"foo.nested.bar.b<*>"
,
"foo:\n" +
" nested:\n" +
" bar:\n" +
" foo:\n" +
" bar: $0\n" +
"other:<*>"
);
assertCompletion(
"foo:\n" +
" nested:\n" +
" bar:\n" +
" foo:\n" +
"other:\n" +
"foo.nested.bar.b<*>"
,
"foo:\n" +
" nested:\n" +
" bar:\n" +
" foo:\n" +
" bar: $0\n" +
"other:<*>"
);
assertCompletion(
"foo:\n" +
" nested:\n" +
" bar:\n" +
" foo:\n" +
"other:\n" +
"foo.nested.nested.b<*>"
,
"foo:\n" +
" nested:\n" +
" bar:\n" +
" foo:\n" +
" nested:\n" +
" bar: $0\n" +
"other:<*>"
);
assertCompletion(
"foo:\n" +
" nested:\n" +
" bar:\n" +
" foo:\n" +
"other:\n" +
"foo.nested.nested.b<*>"
,
"foo:\n" +
" nested:\n" +
" bar:\n" +
" foo:\n" +
" nested:\n" +
" bar: $0\n" +
"other:<*>"
);
assertCompletion(
"foo.nested.nested.b<*>\n" +
"foo:\n" +
" nested:\n" +
" bar:\n" +
" foo:\n" +
"other:"
,
"foo:\n" +
" nested:\n" +
" bar:\n" +
" foo:\n" +
" nested:\n" +
" bar: <*>\n" +
"other:"
);
return; // Skip running this test
});
assertCompletion(
"foo.nested.nested.b<*>\n" +
"foo:\n" +
" nested:\n" +
" bar:\n" +
" foo:\n" +
"other:"
,
"foo:\n" +
" nested:\n" +
" bar:\n" +
" foo:\n" +
" nested:\n" +
" bar: <*>\n" +
"other:"
);
}
@Test