Fix but around dedented snippets and completions
This commit is contained in:
@@ -1628,7 +1628,7 @@ public class BoshEditorTest {
|
||||
"instance_groups:\n" +
|
||||
"- name: $10\n" +
|
||||
" azs:\n" +
|
||||
" - $11\n" +
|
||||
" - $11\n" +
|
||||
" instances: $12\n" +
|
||||
" jobs:\n" +
|
||||
" - name: $13\n" +
|
||||
@@ -1641,7 +1641,7 @@ public class BoshEditorTest {
|
||||
"instance_groups:\n" +
|
||||
"- name: $1\n" +
|
||||
" azs:\n" +
|
||||
" - $2\n" +
|
||||
" - $2\n" +
|
||||
" instances: $3\n" +
|
||||
" jobs:\n" +
|
||||
" - name: $4\n" +
|
||||
@@ -1738,6 +1738,81 @@ public class BoshEditorTest {
|
||||
);
|
||||
}
|
||||
|
||||
@Test public void snippet_dedented() throws Exception {
|
||||
Editor editor;
|
||||
editor = harness.newEditor(
|
||||
"name: \n" +
|
||||
"variables:\n" +
|
||||
"- name: voo\n" +
|
||||
" type: aaa\n" +
|
||||
"<*>"
|
||||
);
|
||||
editor.assertContextualCompletions(LanguageId.BOSH_DEPLOYMENT, DEDENTED_COMPLETION.and(SNIPPET_COMPLETION),
|
||||
" <*>"
|
||||
, // ==>
|
||||
"instance_groups:\n" +
|
||||
"- name: $1\n" +
|
||||
" azs:\n" +
|
||||
" - $2\n" +
|
||||
" instances: $3\n" +
|
||||
" jobs:\n" +
|
||||
" - name: $4\n" +
|
||||
" release: $5\n" +
|
||||
" vm_type: $6\n" +
|
||||
" stemcell: $7\n" +
|
||||
" networks:\n" +
|
||||
" - name: $8<*>"
|
||||
, //=========
|
||||
"releases:\n" +
|
||||
"- name: $1\n" +
|
||||
" version: $2<*>"
|
||||
, //========
|
||||
"stemcells:\n" +
|
||||
"- alias: $1\n" +
|
||||
" version: $2<*>"
|
||||
, //========
|
||||
"update:\n" +
|
||||
" canaries: $1\n" +
|
||||
" max_in_flight: $2\n" +
|
||||
" canary_watch_time: $3\n" +
|
||||
" update_watch_time: $4<*>"
|
||||
, //========
|
||||
"- name: $1\n" +
|
||||
" type: $2<*>"
|
||||
);
|
||||
}
|
||||
|
||||
@Test public void relaxedCALessSpaces() throws Exception {
|
||||
Editor editor;
|
||||
editor = harness.newEditor(
|
||||
"name: \n" +
|
||||
"variables:\n" +
|
||||
"- name: voo\n" +
|
||||
" type: aaa\n" +
|
||||
"<*>"
|
||||
);
|
||||
editor.assertContextualCompletions(LanguageId.BOSH_DEPLOYMENT, DEDENTED_COMPLETION.and(SNIPPET_COMPLETION.negate()),
|
||||
" <*>"
|
||||
, //==>
|
||||
"instance_groups:\n" +
|
||||
"- name: <*>"
|
||||
, //----
|
||||
"releases:\n" +
|
||||
"- name: <*>"
|
||||
, //----
|
||||
"stemcells:\n" +
|
||||
"- <*>"
|
||||
, //---
|
||||
"tags:\n" +
|
||||
" <*>"
|
||||
, //---
|
||||
"update:\n" +
|
||||
" <*>"
|
||||
, //---
|
||||
"- name: <*>"
|
||||
);
|
||||
}
|
||||
|
||||
@Test public void relaxedCAmoreSpaces() throws Exception {
|
||||
Editor editor = harness.newEditor(
|
||||
"name: foo\n" +
|
||||
@@ -1753,7 +1828,7 @@ public class BoshEditorTest {
|
||||
);
|
||||
}
|
||||
|
||||
@Test @Ignore public void keyCompletionThatNeedANewline() throws Exception {
|
||||
@Test @Ignore public void keyCompletionThatNeedsANewline() throws Exception {
|
||||
Editor editor = harness.newEditor(
|
||||
"name: foo\n" +
|
||||
"update: canwa<*>"
|
||||
|
||||
@@ -12,9 +12,11 @@
|
||||
package org.springframework.ide.vscode.commons.util;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -185,5 +187,19 @@ public class StringUtil {
|
||||
return line.substring(start);
|
||||
}
|
||||
|
||||
|
||||
public static String[] split(String string, char c) {
|
||||
//Why not use String.split? Because when the string being split ends with separator, it drops the final
|
||||
// empty string. But... we need that empty string! I.e. we want the number of pieces to allways be equal
|
||||
// to the number of separators + 1, even if it means some of the Strings are ""
|
||||
List<String> pieces = new ArrayList<>();
|
||||
int start = 0;
|
||||
int next = string.indexOf(c);
|
||||
while (next>=0) {
|
||||
pieces.add(string.substring(start, next));
|
||||
start = next+1;
|
||||
next = string.indexOf(c, start);
|
||||
}
|
||||
pieces.add(string.substring(start));
|
||||
return pieces.toArray(new String[pieces.size()]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,6 +193,7 @@ public class YamlCompletionEngine implements ICompletionEngine {
|
||||
int spacesStart = spacesEnd-numSpacesToRemove;
|
||||
int numArrows = numSpacesToRemove / YamlIndentUtil.INDENT_BY;
|
||||
String spaces = new DocumentRegion(doc, spacesStart, spacesEnd).toString();
|
||||
YamlIndentUtil indenter = new YamlIndentUtil(doc);
|
||||
if (spaces.length()==numSpacesToRemove && SPACES.matcher(spaces).matches()) {
|
||||
ScoreableProposal transformed = new TransformedCompletion(proposal) {
|
||||
@Override public String tranformLabel(String originalLabel) {
|
||||
@@ -200,6 +201,11 @@ public class YamlCompletionEngine implements ICompletionEngine {
|
||||
}
|
||||
@Override public DocumentEdits transformEdit(DocumentEdits originalEdit) {
|
||||
originalEdit.firstDelete(spacesStart, spacesEnd);
|
||||
originalEdit.transformFirstNonWhitespaceEdit((offset, insertText) -> {
|
||||
String prefix = insertText.substring(0, offset);
|
||||
String dedented = indenter.applyIndentation(insertText.substring(offset), -numSpacesToRemove);
|
||||
return prefix + dedented;
|
||||
});
|
||||
return originalEdit;
|
||||
}
|
||||
@Override
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
package org.springframework.ide.vscode.commons.yaml.util;
|
||||
|
||||
import org.springframework.ide.vscode.commons.util.Assert;
|
||||
import org.springframework.ide.vscode.commons.util.StringUtil;
|
||||
import org.springframework.ide.vscode.commons.util.text.IDocument;
|
||||
import org.springframework.ide.vscode.commons.yaml.structure.YamlDocument;
|
||||
|
||||
@@ -89,9 +90,35 @@ public class YamlIndentUtil {
|
||||
* Notes:
|
||||
* - '\n' are replaced by the default line delimeter for the current document.
|
||||
* - indentation is not applied to the first line of text.
|
||||
* - negative indentations are support and result in removing upto that number of spaces after each newline
|
||||
*/
|
||||
public String applyIndentation(String text, int indentBy) {
|
||||
return text.replaceAll("\\n", newlineWithIndent(indentBy));
|
||||
if (indentBy>0) {
|
||||
return text.replaceAll("\\n", newlineWithIndent(indentBy));
|
||||
} else if (indentBy<0) {
|
||||
int dedentBy = - indentBy;
|
||||
StringBuilder dedented = new StringBuilder();
|
||||
boolean first = true;
|
||||
for (String line : StringUtil.split(text, '\n')) {
|
||||
if (!first) {
|
||||
dedented.append('\n');
|
||||
line = dedentLine(line, dedentBy);
|
||||
}
|
||||
dedented.append(line);
|
||||
first = false;
|
||||
}
|
||||
return dedented.toString();
|
||||
} else { // indentBy==0
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
private String dedentLine(String line, int dedentBy) {
|
||||
int i = 0;
|
||||
while (i<line.length() && i<dedentBy && line.charAt(i)==' ') {
|
||||
i++;
|
||||
}
|
||||
return line.substring(i);
|
||||
}
|
||||
|
||||
public String applyIndentation(String text, String indentStr) {
|
||||
|
||||
@@ -46,6 +46,7 @@ import org.eclipse.lsp4j.TextDocumentPositionParams;
|
||||
import org.eclipse.lsp4j.TextEdit;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
import org.junit.Assert;
|
||||
import org.springframework.ide.vscode.commons.util.StringUtil;
|
||||
import org.springframework.ide.vscode.commons.util.Unicodes;
|
||||
import org.springframework.ide.vscode.commons.util.text.LanguageId;
|
||||
|
||||
@@ -230,7 +231,7 @@ public class Editor {
|
||||
String badSnippet = parts[0];
|
||||
String snippetBefore;
|
||||
String snippetAfter;
|
||||
String[] badParts = split(badSnippet, '^');
|
||||
String[] badParts = StringUtil.split(badSnippet, '^');
|
||||
Assert.assertTrue(badParts.length<=3);
|
||||
if (badParts.length == 1) {
|
||||
snippetBefore = "";
|
||||
@@ -264,22 +265,6 @@ public class Editor {
|
||||
&& problem.getMessage().contains(messageSnippet);
|
||||
}
|
||||
|
||||
private String[] split(String string, char c) {
|
||||
//Why not use String.split? Because when the string being split ends with separator, it drops the final
|
||||
// empty string. But... we need that empty string! I.e. we want the number of pieces to allways be equal
|
||||
// to the number of separators + 1, even if it means some of the Strings are ""
|
||||
List<String> pieces = new ArrayList<>();
|
||||
int start = 0;
|
||||
int next = string.indexOf(c);
|
||||
while (next>=0) {
|
||||
pieces.add(string.substring(start, next));
|
||||
start = next+1;
|
||||
next = string.indexOf(c, start);
|
||||
}
|
||||
pieces.add(string.substring(start));
|
||||
return pieces.toArray(new String[pieces.size()]);
|
||||
}
|
||||
|
||||
private String getText(Position start, int length) {
|
||||
int offset = doc.toOffset(start);
|
||||
String text = doc.getText();
|
||||
|
||||
Reference in New Issue
Block a user