get rid of manual XML read/write — ShortenCommandLine.readShortenClasspathMethod...
authorVladimir Krivosheev <vladimir.krivosheev@jetbrains.com>
Thu, 6 Sep 2018 13:51:43 +0000 (15:51 +0200)
committerVladimir Krivosheev <vladimir.krivosheev@jetbrains.com>
Thu, 6 Sep 2018 14:10:53 +0000 (16:10 +0200)
17 files changed:
java/execution/impl/src/com/intellij/execution/JavaTestConfigurationBase.java
java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java
java/execution/impl/src/com/intellij/execution/application/JvmMainMethodRunConfigurationOptions.kt
java/execution/impl/src/com/intellij/execution/testDiscovery/TestDiscoveryConfigurationProducer.java
platform/lang-api/src/com/intellij/execution/ShortenCommandLine.java
platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationBase.java
platform/lang-impl/src/com/intellij/execution/ConfigurationWithCommandLineShortener.java
platform/projectModel-api/src/com/intellij/configurationStore/properties/ObjectStoredProperty.kt
platform/projectModel-api/src/com/intellij/openapi/components/BaseState.kt
platform/util/src/com/intellij/util/xmlb/XmlSerializerImpl.java
platform/util/src/com/intellij/util/xmlb/XmlSerializerUtil.java
plugins/configuration-script/src/com/intellij/configurationScript/JsonBuilder.kt
plugins/configuration-script/src/com/intellij/configurationScript/RunConfigurationJsonSchemaGenerator.kt
plugins/configuration-script/src/com/intellij/configurationScript/RunConfigurationListReader.kt
plugins/configuration-script/src/com/intellij/configurationScript/runConfigurationTemplateProvider.kt [moved from plugins/configuration-script/src/com/intellij/configurationScript/IntellijConfigurationAppInitializer.kt with 100% similarity]
plugins/configuration-script/test/ConfigurationFileTest.kt
plugins/configuration-script/test/PropertyValueReaderTest.kt [new file with mode: 0644]

index 8b1071d46365908ce68cd57d3dcb1404bb888f4b..c62e4df950dde93448c7cf92d1622571b9fd46bf 100644 (file)
@@ -61,7 +61,7 @@ public abstract class JavaTestConfigurationBase extends ModuleBasedConfiguration
   }
 
   @Override
-  public void setShortenCommandLine(ShortenCommandLine shortenCommandLine) {
+  public void setShortenCommandLine(@Nullable ShortenCommandLine shortenCommandLine) {
     myShortenCommandLine = shortenCommandLine;
   }
 
index b8b59f2c269b180d3d3fe3927889b1e5181a0245..7e68cc96c3317c2f16e207f6c9fb3fc24e7dedcb 100644 (file)
@@ -9,6 +9,7 @@ import com.intellij.execution.junit.RefactoringListeners;
 import com.intellij.execution.runners.ExecutionEnvironment;
 import com.intellij.execution.util.JavaParametersUtil;
 import com.intellij.execution.util.ProgramParametersUtil;
+import com.intellij.openapi.components.BaseState;
 import com.intellij.openapi.module.Module;
 import com.intellij.openapi.options.SettingsEditor;
 import com.intellij.openapi.options.SettingsEditorGroup;
@@ -35,14 +36,18 @@ public class ApplicationConfiguration extends ModuleBasedConfiguration<JavaRunCo
              RefactoringListenerProvider, InputRedirectAware {
 
   /* deprecated, but 3rd-party used variables */
+  @SuppressWarnings("DeprecatedIsStillUsed")
   @Deprecated public String MAIN_CLASS_NAME;
+  @SuppressWarnings("DeprecatedIsStillUsed")
   @Deprecated public String PROGRAM_PARAMETERS;
+  @SuppressWarnings("DeprecatedIsStillUsed")
   @Deprecated public String WORKING_DIRECTORY;
+  @SuppressWarnings("DeprecatedIsStillUsed")
   @Deprecated public boolean ALTERNATIVE_JRE_PATH_ENABLED;
+  @SuppressWarnings("DeprecatedIsStillUsed")
   @Deprecated public String ALTERNATIVE_JRE_PATH;
   /* */
 
-  private ShortenCommandLine myShortenCommandLine = null;
   private final InputRedirectAware.InputRedirectOptions myInputRedirectOptions = new InputRedirectOptions();
 
   public ApplicationConfiguration(String name, @NotNull Project project, @NotNull ApplicationConfigurationType configurationType) {
@@ -275,11 +280,19 @@ public class ApplicationConfiguration extends ModuleBasedConfiguration<JavaRunCo
     return JavaRunConfigurationModule.getModulesForClass(getProject(), getMainClassName());
   }
 
-  @SuppressWarnings("deprecation")
   @Override
   public void readExternal(@NotNull final Element element) {
     super.readExternal(element);
 
+    syncOldStateFields();
+
+    JavaRunConfigurationExtensionManager.getInstance().readExternal(this, element);
+    setShortenCommandLine(ShortenCommandLine.readShortenClasspathMethod(element));
+    myInputRedirectOptions.readExternal(element);
+  }
+
+  @SuppressWarnings("deprecation")
+  private void syncOldStateFields() {
     JvmMainMethodRunConfigurationOptions options = getOptions();
 
     String workingDirectory = options.getWorkingDirectory();
@@ -295,10 +308,12 @@ public class ApplicationConfiguration extends ModuleBasedConfiguration<JavaRunCo
     WORKING_DIRECTORY = workingDirectory;
     ALTERNATIVE_JRE_PATH = options.getAlternativeJrePath();
     ALTERNATIVE_JRE_PATH_ENABLED = options.isAlternativeJrePathEnabled();
+  }
 
-    JavaRunConfigurationExtensionManager.getInstance().readExternal(this, element);
-    setShortenCommandLine(ShortenCommandLine.readShortenClasspathMethod(element));
-    myInputRedirectOptions.readExternal(element);
+  @Override
+  public void setState(@NotNull BaseState state) {
+    super.setState(state);
+    syncOldStateFields();
   }
 
   @Override
@@ -306,19 +321,18 @@ public class ApplicationConfiguration extends ModuleBasedConfiguration<JavaRunCo
     super.writeExternal(element);
 
     JavaRunConfigurationExtensionManager.getInstance().writeExternal(this, element);
-    ShortenCommandLine.writeShortenClasspathMethod(element, myShortenCommandLine);
     myInputRedirectOptions.writeExternal(element);
   }
 
   @Nullable
   @Override
   public ShortenCommandLine getShortenCommandLine() {
-    return myShortenCommandLine;
+    return getOptions().getShortenClasspath();
   }
 
   @Override
-  public void setShortenCommandLine(ShortenCommandLine mode) {
-    myShortenCommandLine = mode;
+  public void setShortenCommandLine(@Nullable ShortenCommandLine mode) {
+    getOptions().setShortenClasspath(mode);
   }
 
   @NotNull
index 4d8ab7f68608c248d685fe77ca5334060e8b1e13..42cebf80c8f90b0bcfe75d165d90e79ffbb6e918 100644 (file)
@@ -2,26 +2,32 @@
 package com.intellij.execution.application
 
 import com.intellij.execution.JvmConfigurationOptions
+import com.intellij.execution.ShortenCommandLine
 import com.intellij.util.xmlb.annotations.OptionTag
 import com.intellij.util.xmlb.annotations.XMap
 import java.util.*
 
 open class JvmMainMethodRunConfigurationOptions : JvmConfigurationOptions() {
   @get:OptionTag("PROGRAM_PARAMETERS")
-  open var programParameters: String? by string()
+  open var programParameters by string()
 
   @get:OptionTag("WORKING_DIRECTORY")
-  open var workingDirectory: String? by string()
+  open var workingDirectory by string()
 
   @get:OptionTag("INCLUDE_PROVIDED_SCOPE")
-  var includeProvidedScope: Boolean by property(false)
+  var includeProvidedScope by property(false)
 
   @get:OptionTag("ENABLE_SWING_INSPECTOR")
-  var isSwingInspectorEnabled: Boolean by property(false)
+  var isSwingInspectorEnabled by property(false)
 
   @get:OptionTag("PASS_PARENT_ENVS")
-  var isPassParentEnv: Boolean by property(true)
+  var isPassParentEnv by property(true)
 
   @get:XMap(propertyElementName = "envs", entryTagName = "env", keyAttributeName = "name")
   var env: MutableMap<String, String> by property(LinkedHashMap())
+
+  // see ConfigurationWithCommandLineShortener - "null if option was not selected explicitly, legacy user-local options to be used"
+  // so, we cannot use NONE as default value
+  @get:OptionTag(nameAttribute = "", valueAttribute = "name")
+  var shortenClasspath by enum<ShortenCommandLine>()
 }
\ No newline at end of file
index 5882168506e6c01f82b554e02056e7d661cdad0d..c0f5d5b8a2324cf7ea60ae6b38c80979135b3bc5 100644 (file)
@@ -238,7 +238,7 @@ public abstract class TestDiscoveryConfigurationProducer extends JavaRunConfigur
     }
 
     @Override
-    public void setShortenCommandLine(ShortenCommandLine mode) {
+    public void setShortenCommandLine(@Nullable ShortenCommandLine mode) {
       myConfiguration.setShortenCommandLine(mode);
     }
 
index 071b77d9b38b34df2651b38d375b4788764f1bfb..dbc2bcb19587b5bd9026233976826d84c7d16932 100644 (file)
@@ -1,16 +1,4 @@
-// Copyright 2000-2017 JetBrains s.r.o.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
 package com.intellij.execution;
 
 import com.intellij.openapi.project.Project;
@@ -74,6 +62,7 @@ public enum ShortenCommandLine {
     return null;
   }
 
+  @Deprecated
   public static void writeShortenClasspathMethod(@NotNull Element element, ShortenCommandLine shortenCommandLine) {
     if (shortenCommandLine != null) {
       element.addContent(new Element("shortenClasspath").setAttribute("name", shortenCommandLine.name()));
index 91d791b832575a55b5a3e2b6f666ff13a5342007..55065a910c6c79b580361c0f591f7aaadfea4ed8 100644 (file)
@@ -21,6 +21,7 @@ import com.intellij.util.SmartList;
 import com.intellij.util.xmlb.annotations.Attribute;
 import com.intellij.util.xmlb.annotations.Transient;
 import org.jdom.Element;
+import org.jetbrains.annotations.ApiStatus;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -215,7 +216,8 @@ public abstract class RunConfigurationBase extends UserDataHolderBase implements
     myOptions = XmlSerializer.deserialize(element, getOptionsClass());
   }
 
-  public final void setState(@NotNull BaseState state) {
+  @ApiStatus.Experimental
+  public void setState(@NotNull BaseState state) {
     myOptions = (RunConfigurationOptions)state;
   }
 
index 9055106d22f5fa0bc33d4ab2a296bb7433e575a3..65f655c5db41a7c9c7afa18cf67599d451e202d8 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
 package com.intellij.execution;
 
 import com.intellij.openapi.project.Project;
@@ -14,7 +14,7 @@ public interface ConfigurationWithCommandLineShortener {
   /**
    * Called from UI, when user explicitly selects method to be used to shorten the command line or from the deserialization
    */
-  void setShortenCommandLine(ShortenCommandLine mode);
+  void setShortenCommandLine(@Nullable ShortenCommandLine mode);
 
   Project getProject();
 }
index b4df3632b7327c0688dee0809dd221f6973b430e..f7222d35dfd6f74836cf7dd416f84c8fc7c09e39 100644 (file)
@@ -4,9 +4,10 @@ package com.intellij.configurationStore.properties
 import com.intellij.openapi.components.*
 import com.intellij.openapi.util.ModificationTracker
 import com.intellij.openapi.util.text.StringUtil
+import com.intellij.util.xmlb.XmlSerializerUtil
 import kotlin.reflect.KProperty
 
-internal abstract class ObjectStateStoredPropertyBase<T>(protected var value: T) : StoredPropertyBase<T>() {
+abstract class ObjectStateStoredPropertyBase<T>(protected var value: T) : StoredPropertyBase<T>() {
   override val jsonType: JsonSchemaType
     get() = JsonSchemaType.OBJECT
 
@@ -55,6 +56,33 @@ internal open class ObjectStoredProperty<T>(private val defaultValue: T) : Objec
   }
 }
 
+class EnumStoredProperty<T : Enum<*>>(private val defaultValue: T?, val clazz: Class<T>) : ObjectStateStoredPropertyBase<T?>(defaultValue), ScalarProperty {
+  override val jsonType: JsonSchemaType
+    get() = JsonSchemaType.STRING
+
+  override fun isEqualToDefault() = value === defaultValue
+
+  override fun getModificationCount() = 0L
+
+  override fun setValue(thisRef: BaseState, property: KProperty<*>, @Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE") newValue: T?) {
+    val v = newValue ?: defaultValue
+    if (value !== v) {
+      thisRef.intIncrementModificationCount()
+      value = v
+    }
+  }
+
+  @Suppress("UNCHECKED_CAST")
+  override fun parseAndSetValue(rawValue: String?) {
+    if (rawValue == null) {
+      value = defaultValue
+    }
+    else {
+      value = XmlSerializerUtil.stringToEnum(rawValue, clazz, true /* lowercase in YAML by default */) as T? ?: defaultValue
+    }
+  }
+}
+
 internal class StateObjectStoredProperty<T : BaseState?>(initialValue: T) : ObjectStateStoredPropertyBase<T>(initialValue) {
   override fun isEqualToDefault(): Boolean {
     val value = value
index d5151f17e3e37833a94b1eaaedabed59185baab8..a269963a5d5422f756bd6e4d40dc43247d42e5a1 100644 (file)
@@ -32,7 +32,7 @@ abstract class BaseState : SerializationFilter, ModificationTracker {
     properties.add(p as StoredProperty<Any>)
   }
 
-  fun <T> property(): StoredPropertyBase<T?> {
+  protected fun <T> property(): StoredPropertyBase<T?> {
     val result = ObjectStoredProperty<T?>(null)
     addProperty(result)
     return result
@@ -42,7 +42,7 @@ abstract class BaseState : SerializationFilter, ModificationTracker {
    * Value considered as default only if all properties have default values.
    * Passed instance is not used for `isDefault` check. It is just an initial value.
    */
-  fun <T : BaseState?> property(initialValue: T): StoredPropertyBase<T> {
+  protected fun <T : BaseState?> property(initialValue: T): StoredPropertyBase<T> {
     val result = StateObjectStoredProperty(initialValue)
     addProperty(result)
     return result
@@ -51,7 +51,7 @@ abstract class BaseState : SerializationFilter, ModificationTracker {
   /**
    * For non-BaseState classes explicit `isDefault` must be provided, because no other way to check.
    */
-  fun <T> property(initialValue: T, isDefault: (value: T) -> Boolean): StoredPropertyBase<T> {
+  protected fun <T> property(initialValue: T, isDefault: (value: T) -> Boolean): StoredPropertyBase<T> {
     val result = object : ObjectStoredProperty<T>(initialValue) {
       override fun isEqualToDefault() = isDefault(value)
     }
@@ -64,7 +64,7 @@ abstract class BaseState : SerializationFilter, ModificationTracker {
    * Collection considered as default if empty. It is *your* responsibility to call `incrementModificationCount` on collection modification.
    * You cannot set value to a new collection - on set current collection is cleared and new collection is added to current.
    */
-  fun <E, C : MutableCollection<E>> property(initialValue: C): StoredPropertyBase<C> {
+  protected fun <E, C : MutableCollection<E>> property(initialValue: C): StoredPropertyBase<C> {
     val result = CollectionStoredProperty(initialValue)
     addProperty(result)
     return result
@@ -73,7 +73,7 @@ abstract class BaseState : SerializationFilter, ModificationTracker {
   /**
    * Charset is an immutable, so, it is safe to use it as default value.
    */
-  fun <T : Charset> property(initialValue: T): StoredPropertyBase<T> {
+  protected fun <T : Charset> property(initialValue: T): StoredPropertyBase<T> {
     val result = ObjectStoredProperty(initialValue)
     addProperty(result)
     return result
@@ -82,27 +82,41 @@ abstract class BaseState : SerializationFilter, ModificationTracker {
   /**
    * Enum is an immutable, so, it is safe to use it as default value.
    */
-  fun <T : Enum<*>> property(defaultValue: T): StoredPropertyBase<T> {
+  protected fun <T : Enum<*>> property(defaultValue: T): StoredPropertyBase<T> {
     val result = ObjectStoredProperty(defaultValue)
     addProperty(result)
     return result
   }
 
   /**
+   * `null` is always normalized to null.
+   */
+  protected inline fun <reified T : Enum<*>> enum(defaultValue: T? = null): StoredPropertyBase<T?> {
+    return doEnum(defaultValue, T::class.java)
+  }
+
+  @PublishedApi
+  internal fun <T : Enum<*>> doEnum(defaultValue: T? = null, clazz: Class<T>): StoredPropertyBase<T?> {
+    val result = EnumStoredProperty(defaultValue, clazz)
+    addProperty(result)
+    return result
+  }
+
+  /**
    * Not-null list. Initialized as SmartList.
    */
-  fun <T : Any> list(): StoredPropertyBase<MutableList<T>> {
+  protected fun <T : Any> list(): StoredPropertyBase<MutableList<T>> {
     val result = ListStoredProperty<T>()
     addProperty(result)
     @Suppress("UNCHECKED_CAST")
     return result as StoredPropertyBase<MutableList<T>>
   }
 
-  fun <K : Any, V: Any> property(value: MutableMap<K, V>): StoredPropertyBase<MutableMap<K, V>> {
+  protected fun <K : Any, V: Any> property(value: MutableMap<K, V>): StoredPropertyBase<MutableMap<K, V>> {
     return map(value)
   }
 
-  fun <K : Any, V: Any> map(value: MutableMap<K, V> = THashMap()): StoredPropertyBase<MutableMap<K, V>> {
+  protected fun <K : Any, V: Any> map(value: MutableMap<K, V> = THashMap()): StoredPropertyBase<MutableMap<K, V>> {
     val result = MapStoredProperty(value)
     addProperty(result)
     return result
@@ -111,36 +125,36 @@ abstract class BaseState : SerializationFilter, ModificationTracker {
   /**
    * Empty string is always normalized to null.
    */
-  fun property(defaultValue: String?): StoredPropertyBase<String?> = string(defaultValue)
+  protected fun property(defaultValue: String?): StoredPropertyBase<String?> = string(defaultValue)
 
   /**
    * Empty string is always normalized to null.
    */
-  fun string(defaultValue: String? = null): StoredPropertyBase<String?> {
+  protected fun string(defaultValue: String? = null): StoredPropertyBase<String?> {
     val result = NormalizedStringStoredProperty(defaultValue)
     addProperty(result)
     return result
   }
 
-  fun property(defaultValue: Int = 0): StoredPropertyBase<Int> {
+  protected fun property(defaultValue: Int = 0): StoredPropertyBase<Int> {
     val result = IntStoredProperty(defaultValue, null)
     addProperty(result)
     return result
   }
 
-  fun property(defaultValue: Long = 0): StoredPropertyBase<Long> {
+  protected fun property(defaultValue: Long = 0): StoredPropertyBase<Long> {
     val result = LongStoredProperty(defaultValue, null)
     addProperty(result)
     return result
   }
 
-  fun property(defaultValue: Float = 0f, valueNormalizer: ((value: Float) -> Float)? = null): StoredPropertyBase<Float> {
+  protected fun property(defaultValue: Float = 0f, valueNormalizer: ((value: Float) -> Float)? = null): StoredPropertyBase<Float> {
     val result = FloatStoredProperty(defaultValue, valueNormalizer)
     addProperty(result)
     return result
   }
 
-  fun property(defaultValue: Boolean = false): StoredPropertyBase<Boolean> {
+  protected fun property(defaultValue: Boolean = false): StoredPropertyBase<Boolean> {
     val result = ObjectStoredProperty(defaultValue)
     addProperty(result)
     return result
@@ -217,26 +231,8 @@ abstract class BaseState : SerializationFilter, ModificationTracker {
     }
   }
 
-  fun getProperties() = properties
-}
-
-// move buildJsonSchema and other such functions from BaseState to exclude from completion
-// internal usage only
-@ApiStatus.Experimental
-fun buildJsonSchema(state: BaseState, builder: StringBuilder) {
-  val properties = state.getProperties()
-  // todo object definition
-  for (property in properties) {
-    builder.jsonEscapedString(property.name!!).append(':').append('{')
-    builder.jsonEscapedString("type").append(':').jsonEscapedString(property.jsonType.jsonName)
-    builder.append('}')
-    if (property !== properties.last()) {
-      builder.append(',')
-    }
-  }
-}
-
-private fun StringBuilder.jsonEscapedString(value: String): StringBuilder {
-  append('"').append(value).append('"')
-  return this
+  // internal usage only
+  @Suppress("FunctionName")
+  @ApiStatus.Experimental
+  fun __getProperties() = properties
 }
\ No newline at end of file
index cae26e096199ec84fd09c804d31f29ff75867578..9eee32801287f3c81b163391e6f7af4003669a05 100644 (file)
@@ -255,20 +255,8 @@ public final class XmlSerializerImpl {
       accessor.setShort(host, Short.parseShort(value));
     }
     else if (valueClass.isEnum()) {
-      Object deserializedValue = null;
-      for (Object enumConstant : valueClass.getEnumConstants()) {
-        if (enumConstant.toString().equals(value)) {
-          deserializedValue = enumConstant;
-        }
-      }
-      if (deserializedValue == null) {
-        for (Object enumConstant : valueClass.getEnumConstants()) {
-          if (enumConstant.toString().equalsIgnoreCase(value)) {
-            deserializedValue = enumConstant;
-          }
-        }
-      }
-      accessor.set(host, deserializedValue);
+      //noinspection unchecked
+      accessor.set(host, XmlSerializerUtil.stringToEnum(value, (Class<? extends Enum<?>>)valueClass, false));
     }
     else if (Date.class.isAssignableFrom(valueClass)) {
       try {
index 3638e21d2c574ec2c6fadba20714e33a676b20a2..2e3389c11d144dda292304d016ccddccf2cb4830 100644 (file)
@@ -1,22 +1,9 @@
-/*
- * Copyright 2000-2015 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
 package com.intellij.util.xmlb;
 
 import com.intellij.util.ReflectionUtil;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.List;
 
@@ -48,4 +35,22 @@ public class XmlSerializerUtil {
   public static List<MutableAccessor> getAccessors(@NotNull Class<?> aClass) {
     return BeanBinding.getAccessors(aClass);
   }
+
+  @Nullable
+  public static Object stringToEnum(@NotNull String value, @NotNull Class<? extends Enum<?>> valueClass, boolean isAlwaysIgnoreCase) {
+    Enum<?>[] enumConstants = valueClass.getEnumConstants();
+    if (!isAlwaysIgnoreCase) {
+      for (Object enumConstant : enumConstants) {
+        if (enumConstant.toString().equals(value)) {
+          return enumConstant;
+        }
+      }
+    }
+    for (Object enumConstant : enumConstants) {
+      if (enumConstant.toString().equalsIgnoreCase(value)) {
+        return enumConstant;
+      }
+    }
+    return null;
+  }
 }
index 643c11907669d3e57bbb95d3e48fbe8e6159186e..20d1b6900813cf07f598e312714e191073585751 100644 (file)
@@ -76,16 +76,24 @@ internal class JsonObjectBuilder(private val builder: StringBuilder) {
   }
 
   fun rawMap(key: CharSequence, build: (StringBuilder) -> Unit) {
+    mapOrArray('{', '}', key, build)
+  }
+
+  fun rawArray(key: CharSequence, build: (StringBuilder) -> Unit) {
+    mapOrArray('[', ']', key, build)
+  }
+
+  private fun mapOrArray(openChar: Char, closeChar: Char, key: CharSequence, build: (StringBuilder) -> Unit) {
     builder
       .appendCommaIfNeed()
       .jsonEscapedString(key)
       .append(':')
-      .append('{')
+      .append(openChar)
       .append('\n')
     build(builder)
     builder
       .append('\n')
-      .append('}')
+      .append(closeChar)
   }
 
   fun rawBuilder(key: CharSequence, child: JsonObjectBuilder) {
index f24eb43ddbf52c138be0b462008348ceb9673593..e6b063d4dd762ef7c4c16433a754f705e204db41 100644 (file)
@@ -1,8 +1,9 @@
 package com.intellij.configurationScript
 
+import com.intellij.configurationStore.properties.EnumStoredProperty
 import com.intellij.execution.configurations.ConfigurationFactory
 import com.intellij.execution.configurations.ConfigurationType
-import com.intellij.openapi.components.buildJsonSchema
+import com.intellij.openapi.components.BaseState
 import com.intellij.openapi.diagnostic.debug
 import com.intellij.openapi.util.text.StringUtil
 import com.intellij.util.ReflectionUtil
@@ -175,12 +176,38 @@ internal class RunConfigurationJsonSchemaGenerator {
       if (description != null) {
         "description" toUnescaped description
       }
-      rawMap("properties") { buildJsonSchema(state, it) }
+      map("properties") { buildJsonSchema(state, this) }
     }
     "additionalProperties" to false
   }
 }
 
+// move buildJsonSchema and other such functions from BaseState to exclude from completion
+private fun buildJsonSchema(state: BaseState, builder: JsonObjectBuilder) {
+  val properties = state.__getProperties()
+  // todo object definition
+  for (property in properties) {
+    builder.map(property.name!!) {
+      "type" to property.jsonType.jsonName
+      if (property is EnumStoredProperty<*>) {
+        describeEnum(property)
+      }
+    }
+  }
+}
+
+private fun JsonObjectBuilder.describeEnum(property: EnumStoredProperty<*>) {
+  rawArray("enum") { stringBuilder ->
+    val enumConstants = property.clazz.enumConstants
+    for (enum in enumConstants) {
+      stringBuilder.append('"').append(enum.toString().toLowerCase()).append('"')
+      if (enum !== enumConstants.last()) {
+        stringBuilder.append(',')
+      }
+    }
+  }
+}
+
 // returns null if id is not valid
 internal fun rcTypeIdToPropertyName(configurationType: ConfigurationType): CharSequence? {
   val result = idToPropertyName(configurationType.tag, configurationType, null) ?: return null
index a2eb95a1ffad25a0cc3b8c03c08e4e1cd6d10757..1ad015ad5a1770076018ef674c552fa289be7af7 100644 (file)
@@ -107,7 +107,7 @@ internal class RunConfigurationListReader(private val processor: (factory: Confi
 
   private fun readRc(optionsClass: Class<out BaseState>, node: MappingNode, factory: ConfigurationFactory) {
     val state = ReflectionUtil.newInstance(optionsClass)
-    val properties = state.getProperties()
+    val properties = state.__getProperties()
     for (tuple in node.value) {
       val valueNode = tuple.valueNode
       val key = (tuple.keyNode as ScalarNode).value
index 2204f9568ef59c44cf7bf029f83155e973d22425..6559434353d839eabbf322831533fb4e3aed3569 100644 (file)
@@ -119,7 +119,7 @@ class ConfigurationFileTest {
   }
 }
 
-private fun parse(@Language("YAML") data: String, isTemplatesOnly: Boolean = false): List<Any> {
+internal fun parse(@Language("YAML") data: String, isTemplatesOnly: Boolean = false): List<Any> {
   val list = SmartList<Any>()
   parseConfigurationFile(data.trimIndent().reader(), isTemplatesOnly) { _, state ->
     list.add(state)
diff --git a/plugins/configuration-script/test/PropertyValueReaderTest.kt b/plugins/configuration-script/test/PropertyValueReaderTest.kt
new file mode 100644 (file)
index 0000000..c3f521c
--- /dev/null
@@ -0,0 +1,28 @@
+package com.intellij.configurationScript
+
+import com.intellij.execution.ShortenCommandLine
+import com.intellij.execution.application.JvmMainMethodRunConfigurationOptions
+import com.intellij.testFramework.ProjectRule
+import com.intellij.testFramework.assertions.Assertions.assertThat
+import org.junit.ClassRule
+import org.junit.Test
+
+class PropertyValueReaderTest {
+  companion object {
+    @JvmField
+    @ClassRule
+    val projectRule = ProjectRule()
+  }
+
+  @Test
+  fun `enum`() {
+    val result = parse("""
+    runConfigurations:
+      jvmMainMethod:
+        shortenClasspath: MANIFEST
+    """)
+    val options = JvmMainMethodRunConfigurationOptions()
+    options.shortenClasspath = ShortenCommandLine.MANIFEST
+    assertThat(result).containsExactly(options)
+  }
+}
\ No newline at end of file