diff --git a/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/model/LanguageConfiguration.java b/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/model/LanguageConfiguration.java index a8f034534..908a77ec8 100644 --- a/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/model/LanguageConfiguration.java +++ b/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/model/LanguageConfiguration.java @@ -12,10 +12,14 @@ */ package org.eclipse.tm4e.languageconfiguration.internal.model; +import static org.eclipse.tm4e.core.internal.utils.NullSafetyHelper.*; + import java.io.BufferedReader; import java.io.Reader; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.stream.Collectors; import org.eclipse.jdt.annotation.NonNull; @@ -66,7 +70,7 @@ private static String removeTrailingCommas(String jsonString) { public static @Nullable LanguageConfiguration load(@NonNull final Reader reader) { // GSON does not support trailing commas so we have to manually remove them -> maybe better switch to jackson json parser? final var jsonString = removeTrailingCommas(new BufferedReader(reader).lines().collect(Collectors.joining("\n"))); - return new GsonBuilder() + final LanguageConfiguration langCfg = new GsonBuilder() .registerTypeAdapter(String.class, (JsonDeserializer) (json, typeOfT, context) -> { if (json.isJsonObject()) { /* for example: @@ -240,6 +244,32 @@ private static String removeTrailingCommas(String jsonString) { }) .create() .fromJson(jsonString, LanguageConfiguration.class); + + if (castNullable(langCfg.autoClosingPairs) == null) { + langCfg.autoClosingPairs = Collections.emptyList(); + } else { + langCfg.autoClosingPairs.removeIf(Objects::isNull); + } + + if (castNullable(langCfg.brackets) == null) { + langCfg.brackets = Collections.emptyList(); + } else { + langCfg.brackets.removeIf(Objects::isNull); + } + + if (castNullable(langCfg.onEnterRules) == null) { + langCfg.onEnterRules = Collections.emptyList(); + } else { + langCfg.onEnterRules.removeIf(Objects::isNull); + } + + if (castNullable(langCfg.surroundingPairs) == null) { + langCfg.surroundingPairs = Collections.emptyList(); + } else { + langCfg.surroundingPairs.removeIf(Objects::isNull); + } + + return langCfg; } private static @Nullable RegExPattern getAsPattern(@Nullable final JsonElement element) { @@ -261,39 +291,33 @@ private static String removeTrailingCommas(String jsonString) { } private static @Nullable String getAsString(@Nullable final JsonElement element) { - if (element == null) { - return null; - } - try { - return element.getAsString(); - } catch (final Exception ex) { - LanguageConfigurationPlugin.logError("Failed to convert JSON element [" + element + "] to String.", ex); - return null; - } + if (element != null) + try { + return element.getAsString(); + } catch (final Exception ex) { + LanguageConfigurationPlugin.logError("Failed to convert JSON element [" + element + "] to String.", ex); + } + return null; } private static boolean getAsBoolean(@Nullable final JsonElement element, final boolean defaultValue) { - if (element == null) { - return defaultValue; - } - try { - return element.getAsBoolean(); - } catch (final Exception ex) { - LanguageConfigurationPlugin.logError("Failed to convert JSON element [" + element + "] to boolean.", ex); - return defaultValue; - } + if (element != null) + try { + return element.getAsBoolean(); + } catch (final Exception ex) { + LanguageConfigurationPlugin.logError("Failed to convert JSON element [" + element + "] to boolean.", ex); + } + return defaultValue; } private static @Nullable Integer getAsInteger(@Nullable final JsonElement element) { - if (element == null) { - return null; - } - try { - return element.getAsInt(); - } catch (final Exception ex) { - LanguageConfigurationPlugin.logError("Failed to convert JSON element [" + element + "] to Integer.", ex); - return null; - } + if (element != null) + try { + return element.getAsInt(); + } catch (final Exception ex) { + LanguageConfigurationPlugin.logError("Failed to convert JSON element [" + element + "] to Integer.", ex); + } + return null; } private @Nullable CommentRule comments; @@ -308,14 +332,14 @@ private static boolean getAsBoolean(@Nullable final JsonElement element, final b return comments; } - private @Nullable List brackets; + private List brackets = lazyNonNull(); /** * Returns the language's brackets. This configuration implicitly affects pressing Enter around these brackets. * * @return the language's brackets */ - public @Nullable List getBrackets() { + public List getBrackets() { return brackets; } @@ -332,18 +356,18 @@ private static boolean getAsBoolean(@Nullable final JsonElement element, final b // TODO @Nullable IndentionRule getIndentionRules(); - private @Nullable List onEnterRules; + private List onEnterRules = lazyNonNull(); /** * Returns the language's rules to be evaluated when pressing Enter. * * @return the language's rules to be evaluated when pressing Enter. */ - public @Nullable List getOnEnterRules() { + public List getOnEnterRules() { return onEnterRules; } - private @Nullable List autoClosingPairs; + private List autoClosingPairs = lazyNonNull(); /** * Returns the language's auto closing pairs. The 'close' character is automatically inserted with the 'open' @@ -351,12 +375,11 @@ private static boolean getAsBoolean(@Nullable final JsonElement element, final b * * @return the language's auto closing pairs. */ - - public @Nullable List getAutoClosingPairs() { + public List getAutoClosingPairs() { return autoClosingPairs; } - private @Nullable List surroundingPairs; + private List surroundingPairs = lazyNonNull(); /** * Returns the language's surrounding pairs. When the 'open' character is typed on a selection, the selected string @@ -364,7 +387,7 @@ private static boolean getAsBoolean(@Nullable final JsonElement element, final b * * @return the language's surrounding pairs. */ - public @Nullable List getSurroundingPairs() { + public List getSurroundingPairs() { return surroundingPairs; } diff --git a/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/registry/LanguageConfigurationDefinition.java b/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/registry/LanguageConfigurationDefinition.java index c992d8f90..d6ad810d5 100644 --- a/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/registry/LanguageConfigurationDefinition.java +++ b/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/registry/LanguageConfigurationDefinition.java @@ -98,7 +98,7 @@ CharacterPairSupport getCharacterPair() { OnEnterSupport getOnEnter() { if (this.onEnter == null) { final LanguageConfiguration conf = getLanguageConfiguration(); - if (conf == null || conf.getBrackets() == null && conf.getOnEnterRules() == null) + if (conf == null || conf.getBrackets().isEmpty() && conf.getOnEnterRules().isEmpty()) return null; this.onEnter = new OnEnterSupport(conf.getBrackets(), conf.getOnEnterRules()); diff --git a/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/supports/CharacterPairSupport.java b/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/supports/CharacterPairSupport.java index e6b1b6078..4dad428db 100644 --- a/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/supports/CharacterPairSupport.java +++ b/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/supports/CharacterPairSupport.java @@ -18,7 +18,6 @@ import java.util.Collections; import java.util.List; -import java.util.Objects; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.tm4e.languageconfiguration.internal.model.AutoClosingPair; @@ -44,18 +43,17 @@ public final class CharacterPairSupport { @SuppressWarnings("unchecked") public CharacterPairSupport(final LanguageConfiguration config) { final var autoClosingPairs = config.getAutoClosingPairs(); - final var brackets = config.getBrackets(); - - if (autoClosingPairs != null) { - this.autoClosingPairs = autoClosingPairs.stream().filter(Objects::nonNull) - .map(el -> new AutoClosingPairConditional(el.open, el.close, el.notIn)) - .toList(); - } else if (brackets != null) { - this.autoClosingPairs = brackets.stream().filter(Objects::nonNull) - .map(el -> new AutoClosingPairConditional(el.open, el.close, Collections.emptyList())) - .toList(); + if (!autoClosingPairs.isEmpty()) { + this.autoClosingPairs = autoClosingPairs; } else { - this.autoClosingPairs = Collections.emptyList(); + final var brackets = config.getBrackets(); + if (!brackets.isEmpty()) { + this.autoClosingPairs = brackets.stream() + .map(el -> new AutoClosingPairConditional(el.open, el.close, Collections.emptyList())) + .toList(); + } else { + this.autoClosingPairs = Collections.emptyList(); + } } final var autoCloseBefore = config.getAutoCloseBefore(); @@ -64,8 +62,8 @@ public CharacterPairSupport(final LanguageConfiguration config) { : CharacterPairSupport.DEFAULT_AUTOCLOSE_BEFORE_LANGUAGE_DEFINED; final var surroundingPairs = config.getSurroundingPairs(); - this.surroundingPairs = surroundingPairs != null - ? surroundingPairs.stream().filter(Objects::nonNull).toList() + this.surroundingPairs = !surroundingPairs.isEmpty() + ? surroundingPairs : (List) (List) this.autoClosingPairs; } diff --git a/org.eclipse.tm4e.languageconfiguration/src/test/java/org/eclipse/tm4e/languageconfiguration/internal/supports/ParsingTest.java b/org.eclipse.tm4e.languageconfiguration/src/test/java/org/eclipse/tm4e/languageconfiguration/internal/supports/ParsingTest.java index 47908cdb8..f343dcf2e 100644 --- a/org.eclipse.tm4e.languageconfiguration/src/test/java/org/eclipse/tm4e/languageconfiguration/internal/supports/ParsingTest.java +++ b/org.eclipse.tm4e.languageconfiguration/src/test/java/org/eclipse/tm4e/languageconfiguration/internal/supports/ParsingTest.java @@ -71,12 +71,12 @@ void testCanLoadPhpLanguageConfig() throws Exception { assertNotNull(comments); assertNotNull(comments.blockComment); assertEquals("//", comments.lineComment); - assertNotNull(languageConfiguration.getBrackets()); - assertNotNull(languageConfiguration.getAutoClosingPairs()); + assertEquals(3, languageConfiguration.getBrackets().size()); + assertEquals(6, languageConfiguration.getAutoClosingPairs().size()); assertEquals(";:.,=}])>` \n\t", languageConfiguration.getAutoCloseBefore()); assertNotNull(languageConfiguration.getWordPattern()); - assertNotNull(languageConfiguration.getOnEnterRules()); - assertNotNull(languageConfiguration.getSurroundingPairs()); + assertEquals(5, languageConfiguration.getOnEnterRules().size()); + assertEquals(6, languageConfiguration.getSurroundingPairs().size()); assertNotNull(languageConfiguration.getFolding()); } @@ -88,12 +88,12 @@ void testCanLoadRustLanguageConfig() throws Exception { assertNotNull(comments); assertNotNull(comments.blockComment); assertEquals("//", comments.lineComment); - assertNotNull(languageConfiguration.getBrackets()); - assertNotNull(languageConfiguration.getAutoClosingPairs()); + assertEquals(4, languageConfiguration.getBrackets().size()); + assertEquals(6, languageConfiguration.getAutoClosingPairs().size()); assertNull(languageConfiguration.getAutoCloseBefore()); assertNull(languageConfiguration.getWordPattern()); - assertNotNull(languageConfiguration.getOnEnterRules()); - assertNotNull(languageConfiguration.getSurroundingPairs()); + assertEquals(6, languageConfiguration.getOnEnterRules().size()); + assertEquals(6, languageConfiguration.getSurroundingPairs().size()); assertNull(languageConfiguration.getFolding()); } diff --git a/org.eclipse.tm4e.languageconfiguration/src/test/resources/rust-language-configuration.json b/org.eclipse.tm4e.languageconfiguration/src/test/resources/rust-language-configuration.json index fe9d8edb1..bb9b37a52 100644 --- a/org.eclipse.tm4e.languageconfiguration/src/test/resources/rust-language-configuration.json +++ b/org.eclipse.tm4e.languageconfiguration/src/test/resources/rust-language-configuration.json @@ -25,12 +25,12 @@ ["'", "'"], ["\"", "\""] ], - "onEnterRules":[ - {"beforeText": "^\\s*/{3}.*$", "action":{ "indentAction": "None", "appendText": "/// " }}, - {"beforeText": "^\\s*/{2}\\!.*$", "action": { "indentAction": "None", "appendText": "//! " }}, - {"beforeText": "^\\s*/\\*(\\*|\\!)(?!/)([^\\*]|\\*(?!/))*$", "afterText": "^\\s*\\*/$", "action": { "indentAction": "IndentOutdent", "appendText": " * " }}, - {"beforeText": "^\\s*/\\*(\\*|\\!)(?!/)([^\\*]|\\*(?!/))*$", "action": { "indentAction": "None", "appendText": " * " }}, - {"beforeText": "^(\\ \\ )*\\ \\*(\\ ([^\\*]|\\*(?!/))*)?$", "action": { "indentAction": "None", "appendText": " * " }}, - {"beforeText": "^(\\ \\ )*\\ \\*/\\s*$", "action": { "indentAction": "None", "removeText": 1 }} + "onEnterRules": [ + {"beforeText": "^\\s*/{3}.*$", "action": { "indent": "none", "appendText": "/// " }}, + {"beforeText": "^\\s*/{2}\\!.*$", "action": { "indent": "none", "appendText": "//! " }}, + {"beforeText": "^\\s*/\\*(\\*|\\!)(?!/)([^\\*]|\\*(?!/))*$", "afterText": "^\\s*\\*/$", "action": { "indent": "IndentOutdent", "appendText": " * " }}, + {"beforeText": "^\\s*/\\*(\\*|\\!)(?!/)([^\\*]|\\*(?!/))*$", "action": { "indent": "none", "appendText": " * " }}, + {"beforeText": "^(\\ \\ )*\\ \\*(\\ ([^\\*]|\\*(?!/))*)?$", "action": { "indent": "none", "appendText": " * " }}, + {"beforeText": "^(\\ \\ )*\\ \\*/\\s*$", "action": { "indent": "none", "removeText": 1 }} ] }