Fix but around dedented snippets and completions

This commit is contained in:
Kris De Volder
2017-08-02 10:42:03 -07:00
parent 7c19c5df85
commit 775d715c35
5 changed files with 131 additions and 22 deletions

View File

@@ -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<*>"

View File

@@ -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()]);
}
}

View File

@@ -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

View File

@@ -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) {

View File

@@ -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();