diff --git a/vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/ValueParser.java b/vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/ValueParser.java index d06881746..35b218cd9 100644 --- a/vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/ValueParser.java +++ b/vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/ValueParser.java @@ -23,4 +23,8 @@ public interface ValueParser { * that the String is not the format this parser expects. */ Object parse(String str) throws Exception; + + static ValueParser of(ValueParser x) { + return x; + } } \ No newline at end of file diff --git a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/schema/YTypeFactory.java b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/schema/YTypeFactory.java index 1c2c4f386..31c25007f 100644 --- a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/schema/YTypeFactory.java +++ b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/schema/YTypeFactory.java @@ -185,8 +185,9 @@ public class YTypeFactory { return null; } - public void addHintProvider(Callable> hintProvider) { + public AbstractType addHintProvider(Callable> hintProvider) { addHintProvider((DynamicSchemaContext dc) -> hintProvider); + return this; } public AbstractType addHintProvider(SchemaContextAware>> hintProvider) { diff --git a/vscode-extensions/vscode-concourse/src/main/java/org/springframework/ide/vscode/concourse/PipelineYmlSchema.java b/vscode-extensions/vscode-concourse/src/main/java/org/springframework/ide/vscode/concourse/PipelineYmlSchema.java index 0f4be308e..bc3a5f3d2 100644 --- a/vscode-extensions/vscode-concourse/src/main/java/org/springframework/ide/vscode/concourse/PipelineYmlSchema.java +++ b/vscode-extensions/vscode-concourse/src/main/java/org/springframework/ide/vscode/concourse/PipelineYmlSchema.java @@ -10,6 +10,7 @@ *******************************************************************************/ package org.springframework.ide.vscode.concourse; +import java.time.ZoneId; import java.util.Set; import java.util.stream.Collectors; @@ -17,11 +18,14 @@ import org.springframework.ide.vscode.commons.languageserver.LanguageIds; import org.springframework.ide.vscode.commons.util.MimeTypes; import org.springframework.ide.vscode.commons.util.Renderable; import org.springframework.ide.vscode.commons.util.Renderables; +import org.springframework.ide.vscode.commons.util.ValueParseException; +import org.springframework.ide.vscode.commons.util.ValueParser; import org.springframework.ide.vscode.commons.util.ValueParsers; import org.springframework.ide.vscode.commons.yaml.ast.NodeUtil; import org.springframework.ide.vscode.commons.yaml.ast.YamlFileAST; import org.springframework.ide.vscode.commons.yaml.path.YamlPath; import org.springframework.ide.vscode.commons.yaml.path.YamlPathSegment; +import org.springframework.ide.vscode.commons.yaml.schema.BasicYValueHint; import org.springframework.ide.vscode.commons.yaml.schema.DynamicSchemaContext; import org.springframework.ide.vscode.commons.yaml.schema.YType; import org.springframework.ide.vscode.commons.yaml.schema.YTypeFactory; @@ -106,6 +110,20 @@ public class PipelineYmlSchema implements YamlSchema { .parseWith(ConcourseValueParsers.DURATION); public final YType t_time_of_day = f.yatomic("TimeOfDay") .parseWith(ConcourseValueParsers.TIME_OF_DAY); + public final YType t_location = f.yatomic("Location") + //Note: we could have used f.yenum here too. But it saves memory if we don't keep the large set of ValueHints in memory. + // That's why we attach custom hint provider and parser here that do essentially the same thing. + .addHintProvider(() -> { + return ZoneId.getAvailableZoneIds().stream() + .map(BasicYValueHint::new) + .collect(Collectors.toList()); + }) + .parseWith(ValueParser.of((zoneId) -> { + if (!ZoneId.getAvailableZoneIds().contains(zoneId)) { + throw new ValueParseException("Unknown 'Location'. See https://en.wikipedia.org/wiki/List_of_tz_database_time_zones"); + } + return zoneId; + })); public final AbstractType task; @@ -542,7 +560,7 @@ public class PipelineYmlSchema implements YamlSchema { { AbstractType source = f.ybean("TimeSource"); addProp(source, "interval", t_duration); - addProp(source, "location", t_ne_string); + addProp(source, "location", t_location); addProp(source, "start", t_time_of_day); addProp(source, "stop", t_time_of_day); addProp(source, "days", f.yseq(t_day)); diff --git a/vscode-extensions/vscode-concourse/src/test/java/org/springframework/ide/vscode/concourse/ConcourseEditorTest.java b/vscode-extensions/vscode-concourse/src/test/java/org/springframework/ide/vscode/concourse/ConcourseEditorTest.java index a8ef47919..e4ef2027e 100644 --- a/vscode-extensions/vscode-concourse/src/test/java/org/springframework/ide/vscode/concourse/ConcourseEditorTest.java +++ b/vscode-extensions/vscode-concourse/src/test/java/org/springframework/ide/vscode/concourse/ConcourseEditorTest.java @@ -778,6 +778,17 @@ public class ConcourseEditorTest { "Tuesday<*>", "Wednesday<*>" ); + + assertContextualCompletions( + "resources:\n" + + "- name: every5minutes\n" + + " type: time\n" + + " location: <*>" + , // ====================== + "Van<*>" + , // => + "America/Vancouver" + ); } @Test public void timeResourceSourceReconcile() throws Exception { @@ -788,7 +799,7 @@ public class ConcourseEditorTest { "- name: every5minutes\n" + " type: time\n" + " source:\n" + - " location: PST\n" + + " location: PST8PDT\n" + " start: 7AM\n" + " stop: 8AM\n" + " interval: 5m\n" + @@ -802,6 +813,7 @@ public class ConcourseEditorTest { "- name: every5minutes\n" + " type: time\n" + " source:\n" + + " location: some-location\n" + " start: the-start-time\n" + " stop: the-stop-time\n" + " interval: the-interval\n" + @@ -810,6 +822,7 @@ public class ConcourseEditorTest { " - Someday\n" ); editor.assertProblems( + "some-location|Unknown 'Location'", "the-start-time|not a valid 'Time'", "the-stop-time|not a valid 'Time'", "the-interval|not a valid 'Duration'",