diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/DocumentRegion.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/DocumentRegion.java index 4a2c58bff..b44f00a1d 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/DocumentRegion.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/DocumentRegion.java @@ -282,4 +282,12 @@ public class DocumentRegion implements CharSequence { } return false; } + + /** + * Take documentRegion at the end of + */ + public DocumentRegion textAtEnd(int numChars) { + numChars = Math.min(getLength(), numChars); + return new DocumentRegion(doc, end-numChars, end); + } } \ No newline at end of file diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SnippetBuilder.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SnippetBuilder.java index d749e5da9..ce57b8eb8 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SnippetBuilder.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SnippetBuilder.java @@ -42,7 +42,6 @@ public class SnippetBuilder { * in the near future. */ protected String createPlaceHolder(int id) { - //Default implementation now only handes the undocumented snippet format that vscode supports. return "$"+id; } diff --git a/headless-services/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/ValueParsers.java b/headless-services/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/ValueParsers.java index 2662440d9..ec74ca344 100644 --- a/headless-services/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/ValueParsers.java +++ b/headless-services/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/ValueParsers.java @@ -21,7 +21,7 @@ public class ValueParsers { if (StringUtil.hasText(s)) { return s; } else { - throw new IllegalArgumentException("String should not be empty"); + throw new ValueParseException("String should not be empty"); } }; diff --git a/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/reconcile/YamlSchemaProblems.java b/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/reconcile/YamlSchemaProblems.java index 1ecd8979e..7298dc039 100644 --- a/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/reconcile/YamlSchemaProblems.java +++ b/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/reconcile/YamlSchemaProblems.java @@ -131,6 +131,8 @@ public class YamlSchemaProblems { underline = underline.subSequence(underline.length()-1, underline.length()); } } + } else { + underline = underline.trimEnd().textAtEnd(1); } return problem(MISSING_PROPERTY, msg, underline); } diff --git a/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/Editor.java b/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/Editor.java index 49a97f090..947f1f16a 100644 --- a/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/Editor.java +++ b/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/Editor.java @@ -218,7 +218,7 @@ public class Editor { String badSnippet = parts[0]; String snippetBefore; String snippetAfter; - String[] badParts = badSnippet.split("\\^"); + String[] badParts = split(badSnippet, '^'); Assert.assertTrue(badParts.length<=3); if (badParts.length == 1) { snippetBefore = ""; @@ -252,6 +252,22 @@ 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 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(); diff --git a/headless-services/concourse-language-server/src/test/java/org/springframework/ide/vscode/concourse/ConcourseEditorTest.java b/headless-services/concourse-language-server/src/test/java/org/springframework/ide/vscode/concourse/ConcourseEditorTest.java index 558913001..78b1d5f96 100644 --- a/headless-services/concourse-language-server/src/test/java/org/springframework/ide/vscode/concourse/ConcourseEditorTest.java +++ b/headless-services/concourse-language-server/src/test/java/org/springframework/ide/vscode/concourse/ConcourseEditorTest.java @@ -2495,7 +2495,7 @@ public class ConcourseEditorTest { editor = harness.newEditor(LanguageId.CONCOURSE_TASK, "image: some-image" ); - editor.assertProblems("image: some-image|[platform, run] are required"); + editor.assertProblems("image: some-imag^e^|[platform, run] are required"); editor = harness.newEditor(LanguageId.CONCOURSE_TASK, "platform: a-platform\n" + @@ -2526,7 +2526,20 @@ public class ConcourseEditorTest { ); } - @Test public void reconcileTaskFileMissingToplevelProperties() throws Exception { + @Test public void taskFileMissingToplevelPropertiesUnderlinesLastNonWhitespaceChar() throws Exception { + Editor editor; + + editor = harness.newEditor(LanguageId.CONCOURSE_TASK, + "image: some-image" + ); + editor.assertProblems("image: some-imag^e^|[platform, run] are required"); + + editor = harness.newEditor(LanguageId.CONCOURSE_TASK, + "image: some-image\n" + + "\n" + + " \n" + ); + editor.assertProblems("image: some-imag^e^|[platform, run] are required"); }