Java tutorial
/** * Copyright (c) 2015-2017 Angelo ZERR. * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Angelo Zerr <angelo.zerr@gmail.com> - initial API and implementation */ package org.eclipse.tm4e.languageconfiguration.internal; import java.io.Reader; import java.util.ArrayList; import java.util.List; import org.eclipse.tm4e.languageconfiguration.ILanguageConfiguration; import org.eclipse.tm4e.languageconfiguration.internal.supports.AutoClosingPairConditional; import org.eclipse.tm4e.languageconfiguration.internal.supports.CharacterPair; import org.eclipse.tm4e.languageconfiguration.internal.supports.Comments; import org.eclipse.tm4e.languageconfiguration.internal.supports.EnterAction; import org.eclipse.tm4e.languageconfiguration.internal.supports.EnterAction.IndentAction; import org.eclipse.tm4e.languageconfiguration.internal.supports.Folding; import org.eclipse.tm4e.languageconfiguration.internal.supports.OnEnterRule; import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonObject; /** * VSCode language-configuration.json * * @see https://code.visualstudio.com/docs/extensionAPI/extension-points#_contributeslanguages */ public class LanguageConfiguration implements ILanguageConfiguration { /** * Returns an instance of {@link LanguageConfiguration} loaded from the VSCode * language-configuration.json file reader. * * @param reader * @return an instance of {@link LanguageConfiguration} loaded from the VSCode * language-configuration.json file reader. */ public static LanguageConfiguration load(Reader reader) { return new GsonBuilder().registerTypeAdapter(OnEnterRule.class, (JsonDeserializer<OnEnterRule>) (json, typeOfT, context) -> { String beforeText = null; String afterText = null; EnterAction action = null; if (json.isJsonObject()) { JsonObject object = json.getAsJsonObject(); beforeText = getAsString(object.get("beforeText")); //$NON-NLS-1$ afterText = getAsString(object.get("afterText")); //$NON-NLS-1$ JsonElement actionElement = object.get("action"); //$NON-NLS-1$ if (actionElement != null && actionElement.isJsonObject()) { JsonObject actionObject = actionElement.getAsJsonObject(); IndentAction indentAction = IndentAction .valueOf(getAsString(actionObject.get("indentAction"))); //$NON-NLS-1$ Integer removeText = getAsInt(actionObject.get("removeText")); //$NON-NLS-1$ String appendText = getAsString(actionObject.get("appendText")); //$NON-NLS-1$ if (indentAction != null) { action = new EnterAction(indentAction); action.setAppendText(appendText); action.setRemoveText(removeText); } } } if (beforeText == null || action == null) { return null; } return new OnEnterRule(beforeText, afterText, action); }).registerTypeAdapter(Comments.class, (JsonDeserializer<Comments>) (json, typeOfT, context) -> { // ex: {"lineComment": "//","blockComment": [ "/*", "*/" ]} String lineComment = null; CharacterPair blockComment = null; if (json.isJsonObject()) { JsonObject object = json.getAsJsonObject(); lineComment = getAsString(object.get("lineComment")); //$NON-NLS-1$ JsonElement blockCommentElement = object.get("blockComment"); //$NON-NLS-1$ if (blockCommentElement != null && blockCommentElement.isJsonArray()) { JsonArray blockCommentArray = blockCommentElement.getAsJsonArray(); if (blockCommentArray.size() == 2) { String blockCommentStart = getAsString(blockCommentArray.get(0)); String blockCommentEnd = getAsString(blockCommentArray.get(1)); if (blockCommentStart != null && blockCommentEnd != null) { blockComment = new CharacterPair(blockCommentStart, blockCommentEnd); } } } } if (lineComment == null && blockComment == null) { return null; } return new Comments(lineComment, blockComment); }).registerTypeAdapter(CharacterPair.class, (JsonDeserializer<CharacterPair>) (json, typeOfT, context) -> { String open = null; String close = null; if (json.isJsonArray()) { // ex: ["{","}"] JsonArray characterPairs = json.getAsJsonArray(); if (characterPairs.size() == 2) { open = getAsString(characterPairs.get(0)); close = getAsString(characterPairs.get(1)); } } if (open == null || close == null) { return null; } return new CharacterPair(open, close); }) .registerTypeAdapter(AutoClosingPairConditional.class, (JsonDeserializer<AutoClosingPairConditional>) (json, typeOfT, context) -> { List<String> notInList = new ArrayList<>(); String open = null; String close = null; if (json.isJsonArray()) { // ex: ["{","}"] JsonArray characterPairs = json.getAsJsonArray(); if (characterPairs.size() == 2) { open = getAsString(characterPairs.get(0)); close = getAsString(characterPairs.get(1)); } } else if (json.isJsonObject()) { // ex: {"open":"'","close":"'", "notIn": ["string", "comment"]} JsonObject object = json.getAsJsonObject(); open = getAsString(object.get("open")); //$NON-NLS-1$ close = getAsString(object.get("close")); //$NON-NLS-1$ JsonElement notInElement = object.get("notIn"); //$NON-NLS-1$ if (notInElement != null && notInElement.isJsonArray()) { JsonArray notInArray = notInElement.getAsJsonArray(); notInArray.forEach(element -> { String string = getAsString(element); if (string != null) { notInList.add(string); } }); } } if (open == null || close == null) { return null; } return new AutoClosingPairConditional(open, close, notInList); }) .registerTypeAdapter(Folding.class, (JsonDeserializer<Folding>) (json, typeOfT, context) -> { // ex: {"offSide": true, "markers": {"start": "^\\s*/", "end": "^\\s*"}} boolean offSide = false; String startMarker = null; String endMarker = null; if (json.isJsonObject()) { JsonObject object = json.getAsJsonObject(); offSide = getAsBoolean(object.get("offSide"), offSide); //$NON-NLS-1$ JsonElement markersElement = object.get("markers"); //$NON-NLS-1$ if (markersElement != null && markersElement.isJsonObject()) { JsonObject markersObject = markersElement.getAsJsonObject(); startMarker = getAsString(markersObject.get("start")); //$NON-NLS-1$ endMarker = getAsString(markersObject.get("end")); //$NON-NLS-1$ } } if (startMarker == null || endMarker == null) { return null; } return new Folding(offSide, startMarker, endMarker); }).create().fromJson(reader, LanguageConfiguration.class); } private static String getAsString(JsonElement element) { if (element == null) { return null; } try { return element.getAsString(); } catch (Exception e) { return null; } } private static Boolean getAsBoolean(JsonElement element, Boolean defaultValue) { if (element == null) { return defaultValue; } try { return element.getAsBoolean(); } catch (Exception e) { return defaultValue; } } private static Integer getAsInt(JsonElement element) { if (element == null) { return null; } try { return element.getAsInt(); } catch (Exception e) { return null; } } /** * Defines the comment symbols */ private Comments comments; /** * The language's brackets. This configuration implicitly affects pressing Enter * around these brackets. */ private List<CharacterPair> brackets; /** * The language's rules to be evaluated when pressing Enter. */ private List<OnEnterRule> onEnterRules; /** * The language's auto closing pairs. The 'close' character is automatically * inserted with the 'open' character is typed. If not set, the configured * brackets will be used. */ private List<AutoClosingPairConditional> autoClosingPairs; /** * The language's surrounding pairs. When the 'open' character is typed on a * selection, the selected string is surrounded by the open and close * characters. If not set, the autoclosing pairs settings will be used. */ private List<CharacterPair> surroundingPairs; /** * Defines when and how code should be folded in the editor */ private Folding folding; /** * Regex which defines what is considered to be a word in the programming * language. */ private String wordPattern; @Override public Comments getComments() { return comments; } @Override public List<CharacterPair> getBrackets() { return brackets; } @Override public List<AutoClosingPairConditional> getAutoClosingPairs() { return autoClosingPairs; } @Override public List<OnEnterRule> getOnEnterRules() { return onEnterRules; } @Override public List<CharacterPair> getSurroundingPairs() { return surroundingPairs; } @Override public Folding getFolding() { return folding; } @Override public String getWordPattern() { return wordPattern; } }