Fix PT-136196057: correct indentation after 'do' step completion
This commit is contained in:
@@ -129,19 +129,25 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine {
|
||||
edits.apply(newDoc);
|
||||
TextEdit vscodeEdit = new TextEdit();
|
||||
vscodeEdit.setRange(doc.toRange(replaceEdit.start, replaceEdit.end-replaceEdit.start));
|
||||
vscodeEdit.setNewText(vscodeIndentFix(vscodeEdit.getRange().getStart(), replaceEdit.newText));
|
||||
vscodeEdit.setNewText(vscodeIndentFix(doc, vscodeEdit.getRange().getStart(), replaceEdit.newText));
|
||||
//TODO: cursor offset within newText? for now we assume its always at the end.
|
||||
item.setTextEdit(vscodeEdit);
|
||||
}
|
||||
}
|
||||
|
||||
private String vscodeIndentFix(Position start, String newText) {
|
||||
private 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.
|
||||
int vscodeMagicIndent = start.getCharacter();
|
||||
return StringUtil.stripIndentation(vscodeMagicIndent, newText);
|
||||
//See here: https://github.com/Microsoft/language-server-protocol/issues/83
|
||||
int referenceLine = start.getLine();
|
||||
int referenceLineIndent = doc.getLineIndentation(referenceLine);
|
||||
int vscodeMagicIndent = Math.min(start.getCharacter(), referenceLineIndent);
|
||||
return vscodeMagicIndent>0
|
||||
? StringUtil.stripIndentation(vscodeMagicIndent, newText)
|
||||
: newText;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CompletionItem> resolveCompletion(CompletionItem unresolved) {
|
||||
//TODO: item is pre-resoved so we don't do anything, but we really should somehow defer some work, such as
|
||||
|
||||
@@ -208,4 +208,47 @@ public class TextDocument implements IDocument {
|
||||
return "TextDocument(uri="+uri+",\n"+this.text+"\n)";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of leading spaces in front of a line. If the line only contains spaces then
|
||||
* this returns the number of spaces the line contains.
|
||||
* <p>
|
||||
* This may return -1 if, for some reason, a line's indentation cannot be determined (e.g. the line does
|
||||
* not exist in the document)
|
||||
*/
|
||||
public int getLineIndentation(int line) {
|
||||
//TODO: this works fine only if we assume all indentation is done with spaces only.
|
||||
// To generalize this it should probably return a String containing exactly the spaces
|
||||
// and tabs at the front of the line.
|
||||
IRegion r = getLineInformation(line);
|
||||
if (r==null) {
|
||||
//not a line in the document so it has no indentation
|
||||
return -1;
|
||||
}
|
||||
int len = r.getLength();
|
||||
int startOfLine = r.getOffset();
|
||||
int leadingSpaces = 0;
|
||||
while (leadingSpaces<len) {
|
||||
char c = getSafeChar(startOfLine+leadingSpaces);
|
||||
if (c==' ') {
|
||||
leadingSpaces++;
|
||||
} else if (c!=' ') {
|
||||
return leadingSpaces;
|
||||
}
|
||||
leadingSpaces++;
|
||||
}
|
||||
return leadingSpaces;
|
||||
}
|
||||
|
||||
/**
|
||||
* Like getChar but never throws {@link BadLocationException}. Instead it
|
||||
* return (char)0 for offsets outside the document.
|
||||
*/
|
||||
public char getSafeChar(int offset) {
|
||||
try {
|
||||
return getChar(offset);
|
||||
} catch (BadLocationException e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -271,9 +271,14 @@ public class Editor {
|
||||
if (edit!=null) {
|
||||
String replaceWith = edit.getNewText();
|
||||
//Apply indentfix, this is magic vscode seems to apply to edits returned by language server. So our harness has to
|
||||
// mimick that behavior. I'm not sure this fix is really emulating it faithfully as its undocumented :-(
|
||||
int indentFix = edit.getRange().getStart().getCharacter();
|
||||
replaceWith = replaceWith.replaceAll("\\n", "\n"+Strings.repeat(" ", indentFix));
|
||||
// mimick that behavior. See https://github.com/Microsoft/language-server-protocol/issues/83
|
||||
int referenceLine = edit.getRange().getStart().getLine();
|
||||
int cursorOffset = edit.getRange().getStart().getCharacter();
|
||||
String referenceIndent = document.getLineIndentString(referenceLine);
|
||||
if (cursorOffset<referenceIndent.length()) {
|
||||
referenceIndent = referenceIndent.substring(0, cursorOffset);
|
||||
}
|
||||
replaceWith = replaceWith.replaceAll("\\n", "\n"+referenceIndent);
|
||||
|
||||
int cursorReplaceOffset = replaceWith.indexOf(VS_CODE_CURSOR_MARKER);
|
||||
if (cursorReplaceOffset>=0) {
|
||||
|
||||
@@ -142,4 +142,24 @@ public class TextDocumentInfo {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getLineIndentString(int line) {
|
||||
int start = startOfLine(line);
|
||||
int scan = start;
|
||||
char c = getSafeChar(scan);
|
||||
StringBuilder indentStr = new StringBuilder();
|
||||
while (c==' '|| c=='\t') {
|
||||
indentStr.append(c);
|
||||
c = getSafeChar(++scan);
|
||||
}
|
||||
return indentStr.toString();
|
||||
}
|
||||
|
||||
private char getSafeChar(int pos) {
|
||||
String text = getText();
|
||||
if (pos>0 && pos<text.length()) {
|
||||
return text.charAt(pos);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -158,6 +158,22 @@ public class PipelineYamlEditorTest {
|
||||
" <*>"
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void PT_136196057_do_step_completion_indentation() throws Exception {
|
||||
assertCompletions(
|
||||
"jobs:\n" +
|
||||
"- name:\n"+
|
||||
" plan:\n" +
|
||||
" - do<*>"
|
||||
, // =>
|
||||
"jobs:\n" +
|
||||
"- name:\n"+
|
||||
" plan:\n" +
|
||||
" - do:\n" +
|
||||
" - <*>"
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void primaryStepHovers() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user