From ca7b6af890041c68cae6a357522a295ec40cd489 Mon Sep 17 00:00:00 2001 From: sebthom Date: Thu, 25 Jan 2024 21:09:29 +0100 Subject: [PATCH] refact: minor code cleanup --- .../core/internal/grammar/LineTokenizer.java | 2 +- .../core/internal/oniguruma/OnigResult.java | 10 +-- .../core/internal/oniguruma/OnigString.java | 2 +- .../core/internal/parser/TMParserJSON.java | 2 +- .../core/internal/parser/TMParserPList.java | 10 +-- .../tm4e/core/internal/theme/ColorMap.java | 2 +- .../core/internal/utils/MoreCollections.java | 8 ++ .../tm4e/core/registry/IGrammarSource.java | 4 +- .../tm4e/core/registry/IThemeSource.java | 4 +- .../internal/model/CompleteEnterAction.java | 8 +- .../internal/model/EnterAction.java | 22 ++--- .../internal/model/LanguageConfiguration.java | 88 ++++++++----------- .../LanguageConfigurationDefinition.java | 49 +++++------ .../LanguageConfigurationRegistryManager.java | 51 +++++------ .../internal/supports/OnEnterSupport.java | 24 +++-- .../internal/utils/TextUtils.java | 81 ++++++++--------- .../widgets/OnEnterRuleTableWidget.java | 55 +++++------- .../internal/model/OnEnterSupportTest.java | 10 +-- 18 files changed, 182 insertions(+), 250 deletions(-) diff --git a/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/internal/grammar/LineTokenizer.java b/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/internal/grammar/LineTokenizer.java index 922d2194f..0a752aa74 100644 --- a/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/internal/grammar/LineTokenizer.java +++ b/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/internal/grammar/LineTokenizer.java @@ -64,7 +64,7 @@ private static class MatchResult { } private static final class MatchInjectionsResult extends MatchResult { - boolean isPriorityMatch; + final boolean isPriorityMatch; MatchInjectionsResult(final RuleId matchedRuleId, final OnigCaptureIndex[] captureIndices, final boolean isPriorityMatch) { super(matchedRuleId, captureIndices); diff --git a/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/internal/oniguruma/OnigResult.java b/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/internal/oniguruma/OnigResult.java index 92f472fbe..ebfdf4456 100644 --- a/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/internal/oniguruma/OnigResult.java +++ b/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/internal/oniguruma/OnigResult.java @@ -42,10 +42,7 @@ void setIndex(final int index) { int locationAt(final int index) { final int bytes = region.getBeg(index); - if (bytes > 0) { - return bytes; - } - return 0; + return bytes > 0 ? bytes : 0; } int count() { @@ -54,9 +51,6 @@ int count() { int lengthAt(final int index) { final int bytes = region.getEnd(index) - region.getBeg(index); - if (bytes > 0) { - return bytes; - } - return 0; + return bytes > 0 ? bytes : 0; } } diff --git a/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/internal/oniguruma/OnigString.java b/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/internal/oniguruma/OnigString.java index 290d5db69..d15f9d7bf 100644 --- a/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/internal/oniguruma/OnigString.java +++ b/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/internal/oniguruma/OnigString.java @@ -166,7 +166,7 @@ private OnigString(final String content, final byte[] bytesUTF8) { bytesCount = bytesUTF8.length; } - protected final String throwOutOfBoundsException(final String indexName, final int index, final int minIndex, final int maxIndex) { + protected final void throwOutOfBoundsException(final String indexName, final int index, final int minIndex, final int maxIndex) { throw new ArrayIndexOutOfBoundsException( indexName + " index " + index + " is out of range " + minIndex + ".." + maxIndex + " of " + this); } diff --git a/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/internal/parser/TMParserJSON.java b/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/internal/parser/TMParserJSON.java index ecddddee3..618f0781e 100644 --- a/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/internal/parser/TMParserJSON.java +++ b/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/internal/parser/TMParserJSON.java @@ -31,7 +31,7 @@ protected Map loadRaw(final Reader source) { } @Override - public final > T parse(final Reader source, final ObjectFactory factory) throws Exception { + public final > T parse(final Reader source, final ObjectFactory factory) { final Map rawRoot = loadRaw(source); return transform(rawRoot, factory); } diff --git a/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/internal/parser/TMParserPList.java b/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/internal/parser/TMParserPList.java index 38bad9f7b..b35ef9463 100644 --- a/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/internal/parser/TMParserPList.java +++ b/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/internal/parser/TMParserPList.java @@ -33,7 +33,6 @@ import org.eclipse.jdt.annotation.Nullable; import org.xml.sax.Attributes; import org.xml.sax.InputSource; -import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; @@ -89,14 +88,13 @@ public > T parse(final Reader source, final Object final StringBuilder text = new StringBuilder(); @Override - public void characters(final char @Nullable [] chars, final int start, final int count) throws SAXException { + public void characters(final char @Nullable [] chars, final int start, final int count) { text.append(chars, start, count); } @Override @NonNullByDefault({}) - public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) - throws SAXException { + public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) { text.setLength(0); switch (localName) { case PLIST_DICT: { @@ -121,7 +119,7 @@ public void startElement(final String uri, final String localName, final String @Override @NonNullByDefault({}) - public void endElement(final String uri, final String localName, final String qName) throws SAXException { + public void endElement(final String uri, final String localName, final String qName) { switch (localName) { case PLIST_ARRAY: { final var parentRef = parents.remove(parents.size() - 1); @@ -199,7 +197,7 @@ public void endElement(final String uri, final String localName, final String qN } @SuppressWarnings("unchecked") - protected void setCurrentProperty(final Object value) { + private void setCurrentProperty(final Object value) { path.removeLast(); final var obj = parents.get(parents.size() - 1); switch (obj.sourceKind) { diff --git a/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/internal/theme/ColorMap.java b/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/internal/theme/ColorMap.java index 1f2ae6639..6683b72eb 100644 --- a/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/internal/theme/ColorMap.java +++ b/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/internal/theme/ColorMap.java @@ -26,7 +26,7 @@ */ public final class ColorMap { - private boolean _isFrozen; + private final boolean _isFrozen; private int _lastColorId = -1; // -1 and not 0 as in upstream project on purpose private final List _id2color = new ArrayList<>(); private final Map _color2id = new LinkedHashMap<>(); diff --git a/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/internal/utils/MoreCollections.java b/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/internal/utils/MoreCollections.java index e1c776acb..6ddd96c99 100644 --- a/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/internal/utils/MoreCollections.java +++ b/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/internal/utils/MoreCollections.java @@ -15,6 +15,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.function.Predicate; import org.eclipse.jdt.annotation.Nullable; @@ -105,6 +106,13 @@ public static String toStringWithIndex(final List list) { return sb.append(']').toString(); } + /** + * @return a new list without null elements + */ + public static List noNulls(final @Nullable List coll) { + return coll == null || coll.isEmpty() ? Collections.emptyList() : coll.stream().filter(Objects::nonNull).toList(); + } + private MoreCollections() { } } diff --git a/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/registry/IGrammarSource.java b/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/registry/IGrammarSource.java index 1d6896b04..2cf906a33 100644 --- a/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/registry/IGrammarSource.java +++ b/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/registry/IGrammarSource.java @@ -85,7 +85,7 @@ static IGrammarSource fromResource(final Class clazz, final String resourceNa final var contentType1 = contentType == null ? guessFileFormat(resourceName) : contentType; return new IGrammarSource() { @Override - public Reader getReader() throws IOException { + public Reader getReader() { return new BufferedReader(new InputStreamReader( clazz.getResourceAsStream(resourceName), charset == null ? StandardCharsets.UTF_8 : charset)); @@ -107,7 +107,7 @@ static IGrammarSource fromString(final ContentType contentType, final String con return new IGrammarSource() { @Override - public Reader getReader() throws IOException { + public Reader getReader() { return new StringReader(content); } diff --git a/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/registry/IThemeSource.java b/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/registry/IThemeSource.java index b203725da..0945d9fb1 100644 --- a/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/registry/IThemeSource.java +++ b/org.eclipse.tm4e.core/src/main/java/org/eclipse/tm4e/core/registry/IThemeSource.java @@ -85,7 +85,7 @@ static IThemeSource fromResource(final Class clazz, final String resourceName final var contentType1 = contentType == null ? guessFileFormat(resourceName) : contentType; return new IThemeSource() { @Override - public Reader getReader() throws IOException { + public Reader getReader() { return new BufferedReader(new InputStreamReader( clazz.getResourceAsStream(resourceName), charset == null ? StandardCharsets.UTF_8 : charset)); @@ -107,7 +107,7 @@ static IThemeSource fromString(final ContentType contentType, final String conte return new IThemeSource() { @Override - public Reader getReader() throws IOException { + public Reader getReader() { return new StringReader(content); } diff --git a/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/model/CompleteEnterAction.java b/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/model/CompleteEnterAction.java index ef8a4766d..d09cb0a79 100644 --- a/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/model/CompleteEnterAction.java +++ b/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/model/CompleteEnterAction.java @@ -11,6 +11,7 @@ */ package org.eclipse.tm4e.languageconfiguration.internal.model; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.tm4e.core.internal.utils.StringUtils; /** @@ -25,11 +26,10 @@ public final class CompleteEnterAction extends EnterAction { */ public final String indentation; - public CompleteEnterAction(final EnterAction action, final String indentation) { - super(action.indentAction); + public CompleteEnterAction(IndentAction indentAction, @Nullable String appendText, @Nullable Integer removeText, + final String indentation) { + super(indentAction, appendText, removeText); this.indentation = indentation; - this.appendText = action.appendText; - this.removeText = action.removeText; } @Override diff --git a/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/model/EnterAction.java b/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/model/EnterAction.java index 509986538..7420918f0 100644 --- a/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/model/EnterAction.java +++ b/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/model/EnterAction.java @@ -73,33 +73,21 @@ public static IndentAction get(final @Nullable String value) { /** * Describes text to be appended after the new line and after the indentation. */ - @Nullable - public String appendText; + public final @Nullable String appendText; /** * Describes the number of characters to remove from the new line's indentation. */ - @Nullable - public Integer removeText; + public final @Nullable Integer removeText; public EnterAction(final IndentAction indentAction) { - this.indentAction = indentAction; + this(indentAction, null, null); } - /** - * @param appendText the appendText to set - */ - EnterAction withAppendText(@Nullable final String appendText) { + public EnterAction(final IndentAction indentAction, final @Nullable String appendText, final @Nullable Integer removeText) { + this.indentAction = indentAction; this.appendText = appendText; - return this; - } - - /** - * @param removeText the removeText to set - */ - EnterAction withRemoveText(@Nullable final Integer removeText) { this.removeText = removeText; - return this; } @Override 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 3f2988128..0bba83ac0 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 @@ -22,6 +22,7 @@ import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.tm4e.languageconfiguration.LanguageConfigurationPlugin; import org.eclipse.tm4e.languageconfiguration.internal.model.EnterAction.IndentAction; import org.eclipse.tm4e.languageconfiguration.internal.utils.RegExpUtils; @@ -64,8 +65,7 @@ private static String removeTrailingCommas(String jsonString) { * reader. */ @NonNullByDefault({}) - @Nullable - public static LanguageConfiguration load(@NonNull final Reader reader) { + 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() @@ -108,11 +108,9 @@ public static LanguageConfiguration load(@NonNull final Reader reader) { final var afterText = getAsPattern(jsonObj.get("afterText")); //$NON-NLS-1$ final var previousLineText = getAsPattern(jsonObj.get("previousLineText")); //$NON-NLS-1$ final var indentAction = IndentAction.get(indentActionString); - final var removeText = getAsInteger(actionJsonObj.get("removeText")); //$NON-NLS-1$ final var appendText = getAsString(actionJsonObj.get("appendText")); //$NON-NLS-1$ - final var action = new EnterAction(indentAction); - action.appendText = appendText; - action.removeText = removeText; + final var removeText = getAsInteger(actionJsonObj.get("removeText")); //$NON-NLS-1$ + final var action = new EnterAction(indentAction, appendText, removeText); return new OnEnterRule(beforeText, afterText, previousLineText, action); } } @@ -209,12 +207,12 @@ public static LanguageConfiguration load(@NonNull final Reader reader) { close = getAsString(autoClosePair.get("close")); //$NON-NLS-1$ final var notInElem = autoClosePair.get("notIn"); //$NON-NLS-1$ if (notInElem != null && notInElem.isJsonArray()) { - notInElem.getAsJsonArray().forEach(element -> { - final var string = getAsString(element); + for (final JsonElement elem : notInElem.getAsJsonArray()) { + final var string = getAsString(elem); if (string != null) { notInList.add(string); } - }); + } } } @@ -246,14 +244,12 @@ public static LanguageConfiguration load(@NonNull final Reader reader) { .fromJson(jsonString, LanguageConfiguration.class); } - @Nullable - private static Pattern getAsPattern(@Nullable final JsonElement element) { + private static @Nullable Pattern getAsPattern(@Nullable final JsonElement element) { final var pattern = getPattern(element); return pattern == null ? null : RegExpUtils.create(pattern); } - @Nullable - private static String getPattern(@Nullable final JsonElement element) { + private static @Nullable String getPattern(@Nullable final JsonElement element) { if (element == null) { return null; } @@ -270,14 +266,14 @@ private static String getPattern(@Nullable final JsonElement element) { return getAsString(element); } - @Nullable - private static String getAsString(@Nullable final JsonElement element) { + private static @Nullable String getAsString(@Nullable final JsonElement element) { if (element == null) { return null; } try { return element.getAsString(); - } catch (final Exception e) { + } catch (final Exception ex) { + LanguageConfigurationPlugin.logError("Failed to convert JSON element [" + element + "] to String.", ex); return null; } } @@ -288,25 +284,25 @@ private static boolean getAsBoolean(@Nullable final JsonElement element, final b } try { return element.getAsBoolean(); - } catch (final Exception e) { + } catch (final Exception ex) { + LanguageConfigurationPlugin.logError("Failed to convert JSON element [" + element + "] to boolean.", ex); return defaultValue; } } - @Nullable - private static Integer getAsInteger(@Nullable final JsonElement element) { + private static @Nullable Integer getAsInteger(@Nullable final JsonElement element) { if (element == null) { return null; } try { return element.getAsInt(); - } catch (final Exception e) { + } catch (final Exception ex) { + LanguageConfigurationPlugin.logError("Failed to convert JSON element [" + element + "] to Integer.", ex); return null; } } - @Nullable - private CommentRule comments; + private @Nullable CommentRule comments; /** * Returns the language's comments. The comments are used by {@link AutoClosingPairConditional} when @@ -314,54 +310,46 @@ private static Integer getAsInteger(@Nullable final JsonElement element) { * * @return the language's comments. */ - @Nullable - public CommentRule getComments() { + public @Nullable CommentRule getComments() { return comments; } - @Nullable - private List brackets; + private @Nullable List brackets; /** * Returns the language's brackets. This configuration implicitly affects pressing Enter around these brackets. * * @return the language's brackets */ - @Nullable - public List getBrackets() { + public @Nullable List getBrackets() { return brackets; } - @Nullable - private String wordPattern; + private @Nullable String wordPattern; /** * Returns the language's definition of a word. This is the regex used when referring to a word. * * @return the language's word pattern. */ - @Nullable - public String getWordPattern() { + public @Nullable String getWordPattern() { return wordPattern; } // TODO @Nullable IndentionRule getIndentionRules(); - @Nullable - private List onEnterRules; + private @Nullable List onEnterRules; /** * Returns the language's rules to be evaluated when pressing Enter. * * @return the language's rules to be evaluated when pressing Enter. */ - @Nullable - public List getOnEnterRules() { + public @Nullable List getOnEnterRules() { return onEnterRules; } - @Nullable - private List autoClosingPairs; + private @Nullable List autoClosingPairs; /** * Returns the language's auto closing pairs. The 'close' character is automatically inserted with the 'open' @@ -369,13 +357,12 @@ public List getOnEnterRules() { * * @return the language's auto closing pairs. */ - @Nullable - public List getAutoClosingPairs() { + + public @Nullable List getAutoClosingPairs() { return autoClosingPairs; } - @Nullable - private List surroundingPairs; + private @Nullable List surroundingPairs; /** * Returns the language's surrounding pairs. When the 'open' character is typed on a selection, the selected string @@ -383,31 +370,26 @@ public List getAutoClosingPairs() { * * @return the language's surrounding pairs. */ - @Nullable - public List getSurroundingPairs() { + public @Nullable List getSurroundingPairs() { return surroundingPairs; } - // TODO @Nullable List getColorizedBracketPairs(); + // TODO private @Nullable List getColorizedBracketPairs(); - @Nullable - private String autoCloseBefore; + private @Nullable String autoCloseBefore; - @Nullable - public String getAutoCloseBefore() { + public @Nullable String getAutoCloseBefore() { return autoCloseBefore; } - @Nullable - private FoldingRules folding; + private @Nullable FoldingRules folding; /** * Returns the language's folding rules. * * @return the language's folding rules. */ - @Nullable - public FoldingRules getFolding() { + public @Nullable FoldingRules getFolding() { return folding; } } 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 90a9069a3..c992d8f90 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 @@ -40,14 +40,9 @@ public final class LanguageConfigurationDefinition extends TMResource implements private boolean bracketAutoClosingEnabled = true; private boolean matchingPairsEnabled = true; - @Nullable - private CharacterPairSupport characterPair; - - @Nullable - private OnEnterSupport onEnter; - - @Nullable - private CommentSupport comment; + private @Nullable CharacterPairSupport characterPair; + private @Nullable OnEnterSupport onEnter; + private @Nullable CommentSupport comment; public LanguageConfigurationDefinition(final IContentType contentType, final String path) { super(path); @@ -59,9 +54,8 @@ public LanguageConfigurationDefinition(final IConfigurationElement ce) throws Co final var contentTypeId = ce.getAttribute(XMLConstants.CONTENT_TYPE_ID_ATTR); final var contentType = ContentTypeHelper.getContentTypeById(contentTypeId); if (contentType == null) - throw new CoreException( - new Status(IStatus.ERROR, LanguageConfiguration.class, - "Cannot load language configuration with unknown content type ID " + contentTypeId)); + throw new CoreException(new Status(IStatus.ERROR, LanguageConfiguration.class, + "Cannot load language configuration with unknown content type ID " + contentTypeId)); this.contentType = contentType; } @@ -69,8 +63,8 @@ public LanguageConfigurationDefinition(final IConfigurationElement ce) throws Co * Constructor for user preferences (loaded from Json with Gson). */ public LanguageConfigurationDefinition(final IContentType contentType, final String path, - @Nullable final String pluginId, - final boolean onEnterEnabled, final boolean bracketAutoClosingEnabled, final boolean matchingPairsEnabled) { + @Nullable final String pluginId, final boolean onEnterEnabled, final boolean bracketAutoClosingEnabled, + final boolean matchingPairsEnabled) { super(path, pluginId); this.contentType = contentType; this.onEnterEnabled = onEnterEnabled; @@ -87,9 +81,10 @@ public LanguageConfigurationDefinition(final IContentType contentType, final Str CharacterPairSupport getCharacterPair() { if (this.characterPair == null) { final LanguageConfiguration conf = getLanguageConfiguration(); - if (conf != null) { - this.characterPair = new CharacterPairSupport(conf); - } + if (conf == null) + return null; + + this.characterPair = new CharacterPairSupport(conf); } return characterPair; } @@ -103,25 +98,27 @@ CharacterPairSupport getCharacterPair() { OnEnterSupport getOnEnter() { if (this.onEnter == null) { final LanguageConfiguration conf = getLanguageConfiguration(); - if (conf != null && (conf.getBrackets() != null || conf.getOnEnterRules() != null)) { - this.onEnter = new OnEnterSupport(conf.getBrackets(), conf.getOnEnterRules()); - } + if (conf == null || conf.getBrackets() == null && conf.getOnEnterRules() == null) + return null; + + this.onEnter = new OnEnterSupport(conf.getBrackets(), conf.getOnEnterRules()); } return onEnter; } /** - * Returns the "commment" support and null otherwise. + * Returns the "comment" support and null otherwise. * - * @return the "commment" support and null otherwise. + * @return the "comment" support and null otherwise. */ @Nullable CommentSupport getCommentSupport() { if (this.comment == null) { final LanguageConfiguration conf = getLanguageConfiguration(); - if (conf != null) { - this.comment = new CommentSupport(conf.getComments()); - } + if (conf == null) + return null; + + this.comment = new CommentSupport(conf.getComments()); } return comment; } @@ -131,9 +128,8 @@ public IContentType getContentType() { return contentType; } - @Nullable @Override - public LanguageConfiguration getLanguageConfiguration() { + public @Nullable LanguageConfiguration getLanguageConfiguration() { try (var in = getInputStream()) { return LanguageConfiguration.load(new InputStreamReader(in, Charset.defaultCharset())); } catch (final IOException ex) { @@ -171,5 +167,4 @@ public boolean isMatchingPairsEnabled() { public void setMatchingPairsEnabled(final boolean matchingPairsEnabled) { this.matchingPairsEnabled = matchingPairsEnabled; } - } diff --git a/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/registry/LanguageConfigurationRegistryManager.java b/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/registry/LanguageConfigurationRegistryManager.java index f2603e29c..e28e989d6 100644 --- a/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/registry/LanguageConfigurationRegistryManager.java +++ b/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/registry/LanguageConfigurationRegistryManager.java @@ -58,8 +58,7 @@ public static LanguageConfigurationRegistryManager getInstance() { return InstanceHolder.INSTANCE; } - @Nullable - private LanguageConfigurationDefinition getDefinition(final IContentType contentType) { + private @Nullable LanguageConfigurationDefinition getDefinition(final IContentType contentType) { LanguageConfigurationDefinition bestFit = null; for (final var iDefinition : getDefinitions()) { if (iDefinition instanceof final LanguageConfigurationDefinition definition) { @@ -73,9 +72,8 @@ private LanguageConfigurationDefinition getDefinition(final IContentType content return bestFit; } - @Nullable - public AutoClosingPairConditional getAutoClosingPair(final String text, final int offset, - final String newCharacter, final IContentType contentType) { + public @Nullable AutoClosingPairConditional getAutoClosingPair(final String text, final int offset, final String newCharacter, + final IContentType contentType) { final var definition = getDefinition(contentType); if (definition == null || !definition.isBracketAutoClosingEnabled()) { return null; @@ -145,10 +143,7 @@ public List getSurroundingPairs(final IContentType contentType) * @see * https://github.com/microsoft/vscode/blob/main/src/vs/editor/common/languages/enterAction.ts */ - @Nullable - public CompleteEnterAction getEnterAction(final IDocument document, final int offset, - final IContentType contentType) { - String indentation = TextUtils.getLinePrefixingWhitespaceAtPosition(document, offset); + public @Nullable CompleteEnterAction getEnterAction(final IDocument document, final int offset, final IContentType contentType) { // let scopedLineTokens = this.getScopedLineTokens(model, range.startLineNumber, range.startColumn); final var onEnterSupport = this._getOnEnterSupport(contentType /* scopedLineTokens.languageId */); if (onEnterSupport == null) { @@ -182,54 +177,48 @@ public CompleteEnterAction getEnterAction(final IDocument document, final int of // } // } - EnterAction enterResult = null; - try { - enterResult = onEnterSupport.onEnter(previousLineText, beforeEnterText, afterEnterText); - } catch (final Exception e) { - // onUnexpectedError(e); - } - + final @Nullable EnterAction enterResult = onEnterSupport.onEnter(previousLineText, beforeEnterText, afterEnterText); if (enterResult == null) { return null; } + final IndentAction indentAction = enterResult.indentAction; + String appendText = enterResult.appendText; + final Integer removeText = enterResult.removeText; + // Here we add `\t` to appendText first because enterAction is leveraging appendText and removeText to change indentation. - if (enterResult.appendText == null) { - if (enterResult.indentAction == IndentAction.Indent - || enterResult.indentAction == IndentAction.IndentOutdent) { - enterResult.appendText = "\t"; //$NON-NLS-1$ + if (appendText == null) { + if (indentAction == IndentAction.Indent + || indentAction == IndentAction.IndentOutdent) { + appendText = "\t"; } else { - enterResult.appendText = ""; //$NON-NLS-1$ + appendText = ""; } } - final var removeText = enterResult.removeText; + String indentation = TextUtils.getIndentationAtPosition(document, offset); if (removeText != null) { indentation = indentation.substring(0, indentation.length() - removeText); } - return new CompleteEnterAction(enterResult, indentation); - } catch (final BadLocationException e1) { + return new CompleteEnterAction(indentAction, appendText, removeText, indentation); + } catch (final BadLocationException | RuntimeException ex) { // ignore } return null; } - @Nullable - public CommentSupport getCommentSupport(final IContentType contentType) { + public @Nullable CommentSupport getCommentSupport(final IContentType contentType) { final var definition = this.getDefinition(contentType); return definition == null ? null : definition.getCommentSupport(); } - @Nullable - private OnEnterSupport _getOnEnterSupport(final IContentType contentType) { + private @Nullable OnEnterSupport _getOnEnterSupport(final IContentType contentType) { final var definition = this.getDefinition(contentType); return definition == null ? null : definition.getOnEnter(); - } - @Nullable - private CharacterPairSupport _getCharacterPairSupport(final IContentType contentType) { + private @Nullable CharacterPairSupport _getCharacterPairSupport(final IContentType contentType) { final var definition = this.getDefinition(contentType); return definition == null ? null : definition.getCharacterPair(); } diff --git a/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/supports/OnEnterSupport.java b/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/supports/OnEnterSupport.java index 348b2d2e1..3d290de8e 100644 --- a/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/supports/OnEnterSupport.java +++ b/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/supports/OnEnterSupport.java @@ -28,7 +28,7 @@ * On enter support. * * @see - * https://github.com/microsoft/vscode/blob/main/src/vs/editor/common/languages/supports/onEnter.ts + * github.com/microsoft/vscode/blob/main/src/vs/editor/common/languages/supports/onEnter.ts */ public class OnEnterSupport { @@ -50,16 +50,15 @@ public OnEnterSupport(@Nullable final List brackets, @Nullable fi this.regExpRules = regExpRules != null ? regExpRules : Collections.emptyList(); } - @Nullable - public EnterAction onEnter( + public @Nullable EnterAction onEnter( // TODO autoIndent: EditorAutoIndentStrategy, final String previousLineText, final String beforeEnterText, final String afterEnterText) { // (1): `regExpRules` + // if (autoIndent >= EditorAutoIndentStrategy.Advanced) { for (final OnEnterRule rule : regExpRules) { - final var beforeTextPattern = rule.beforeText; - if (!beforeTextPattern.matcher(beforeEnterText).find()) + if (!rule.beforeText.matcher(beforeEnterText).find()) continue; final var afterTextPattern = rule.afterText; @@ -74,6 +73,7 @@ public EnterAction onEnter( } // (2): Special indent-outdent + // if (autoIndent >= EditorAutoIndentStrategy.Brackets) { if (!beforeEnterText.isEmpty() && !afterEnterText.isEmpty()) { for (final ProcessedBracketPair bracket : brackets) { if (bracket.matchOpen(beforeEnterText) && bracket.matchClose(afterEnterText)) { @@ -83,6 +83,7 @@ public EnterAction onEnter( } // (3): Open bracket based logic + // if (autoIndent >= EditorAutoIndentStrategy.Brackets) { if (!beforeEnterText.isEmpty()) { for (final ProcessedBracketPair bracket : brackets) { if (bracket.matchOpen(beforeEnterText)) { @@ -98,11 +99,8 @@ private static final class ProcessedBracketPair { private static final Pattern B_REGEXP = Pattern.compile("\\B"); //$NON-NLS-1$ - @Nullable - private final Pattern openRegExp; - - @Nullable - private final Pattern closeRegExp; + private final @Nullable Pattern openRegExp; + private final @Nullable Pattern closeRegExp; private ProcessedBracketPair(final CharacterPair charPair) { openRegExp = createOpenBracketRegExp(charPair.open); @@ -117,8 +115,7 @@ private boolean matchClose(final String afterEnterText) { return closeRegExp != null && closeRegExp.matcher(afterEnterText).find(); } - @Nullable - private static Pattern createOpenBracketRegExp(final String bracket) { + private static @Nullable Pattern createOpenBracketRegExp(final String bracket) { final var str = new StringBuilder(RegExpUtils.escapeRegExpCharacters(bracket)); final var c = String.valueOf(str.charAt(0)); if (!B_REGEXP.matcher(c).find()) { @@ -128,8 +125,7 @@ private static Pattern createOpenBracketRegExp(final String bracket) { return RegExpUtils.create(str.toString()); } - @Nullable - private static Pattern createCloseBracketRegExp(final String bracket) { + private static @Nullable Pattern createCloseBracketRegExp(final String bracket) { final var str = new StringBuilder(RegExpUtils.escapeRegExpCharacters(bracket)); final var c = String.valueOf(str.charAt(str.length() - 1)); if (!B_REGEXP.matcher(c).find()) { diff --git a/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/utils/TextUtils.java b/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/utils/TextUtils.java index 4d4a9444d..a004c1647 100644 --- a/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/utils/TextUtils.java +++ b/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/utils/TextUtils.java @@ -14,34 +14,30 @@ import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.DocumentCommand; import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.TextUtilities; public final class TextUtils { /** - * Returns true if text of the command is an enter and false otherwise. - * * @return true if text of the command is an enter and false otherwise. */ public static boolean isEnter(final IDocument doc, final DocumentCommand cmd) { return cmd.length == 0 && cmd.text != null && TextUtilities.equals(doc.getLegalLineDelimiters(), cmd.text) != -1; } - public static String normalizeIndentation(final String str, final int tabSize, final boolean insertSpaces) { - int firstNonWhitespaceIndex = TextUtils.firstNonWhitespaceIndex(str); + public static String normalizeIndentation(final String text, final int tabSize, final boolean insertSpaces) { + int firstNonWhitespaceIndex = firstNonWhitespaceIndex(text); if (firstNonWhitespaceIndex == -1) { - firstNonWhitespaceIndex = str.length(); + firstNonWhitespaceIndex = text.length(); } - return TextUtils.normalizeIndentationFromWhitespace(str.substring(0, firstNonWhitespaceIndex), tabSize, - insertSpaces) + str.substring(firstNonWhitespaceIndex); + return normalizeIndentationFromWhitespace(text.substring(0, firstNonWhitespaceIndex), tabSize, insertSpaces) + + text.substring(firstNonWhitespaceIndex); } - private static String normalizeIndentationFromWhitespace(final String str, final int tabSize, - final boolean insertSpaces) { + private static String normalizeIndentationFromWhitespace(final String text, final int tabSize, final boolean insertSpaces) { int spacesCnt = 0; - for (int i = 0; i < str.length(); i++) { - if (str.charAt(i) == '\t') { + for (int i = 0; i < text.length(); i++) { + if (text.charAt(i) == '\t') { spacesCnt += tabSize; } else { spacesCnt++; @@ -65,10 +61,13 @@ private static String normalizeIndentationFromWhitespace(final String str, final } /** - * Returns the start of the string at the offset in the text. If the string is - * not in the text at the offset, returns -1.
- * Ex:
- * text = "apple banana", offset=8, string="banana" returns=6 + * Returns the start of the string at the offset in the text. If the string is not in the text at the offset, returns -1. + *

+ * Example: + * + *

+	 * text="apple banana", offset=8, string="banana" -> returns 6
+	 * 
*/ public static int startIndexOfOffsetTouchingString(final String text, final int offset, final String string) { int start = offset - string.length(); @@ -87,9 +86,9 @@ public static int startIndexOfOffsetTouchingString(final String text, final int * Returns first index of the string that is not whitespace. If string is empty * or contains only whitespaces, returns -1 */ - private static int firstNonWhitespaceIndex(final String str) { - for (int i = 0, len = str.length(); i < len; i++) { - final char c = str.charAt(i); + private static int firstNonWhitespaceIndex(final String text) { + for (int i = 0, len = text.length(); i < len; i++) { + final char c = text.charAt(i); if (c != ' ' && c != '\t') { return i; } @@ -118,17 +117,15 @@ public static String getIndentationFromWhitespace(final String whitespace, final return whitespace.substring(0, indentOffset); } - public static String getLinePrefixingWhitespaceAtPosition(final IDocument d, final int offset) { + public static String getIndentationAtPosition(final IDocument doc, final int offset) { try { - // find start of line - final int p = offset; - final IRegion info = d.getLineInformationOfOffset(p); - final int start = info.getOffset(); + // find start offset of current line + final int lineStartOffset = doc.getLineInformationOfOffset(offset).getOffset(); // find white spaces - final int end = findEndOfWhiteSpace(d, start, offset); + final int indentationEndOffset = findEndOfWhiteSpace(doc, lineStartOffset, offset); - return d.get(start, end - start); + return doc.get(lineStartOffset, indentationEndOffset - lineStartOffset); } catch (final BadLocationException excp) { // stop work } @@ -140,42 +137,40 @@ public static String getLinePrefixingWhitespaceAtPosition(final IDocument d, fin * end whose character is not a space or tab character. If no such * offset is found, end is returned. * - * @param document the document to search in - * @param offset the offset at which searching start - * @param end the offset at which searching stops + * @param doc the document to search in + * @param startAt the offset at which searching start + * @param endAt the offset at which searching stops * - * @return the offset in the specified range whose character is not a space or - * tab + * @return the offset in the specified range whose character is not a space or tab * * @exception BadLocationException if position is an invalid range in the given document */ - private static int findEndOfWhiteSpace(final IDocument document, int offset, final int end) - throws BadLocationException { - while (offset < end) { - final char c = document.getChar(offset); + private static int findEndOfWhiteSpace(final IDocument doc, int startAt, final int endAt) throws BadLocationException { + while (startAt < endAt) { + final char c = doc.getChar(startAt); if (c != ' ' && c != '\t') { - return offset; + return startAt; } - offset++; + startAt++; } - return end; + return endAt; } /** * Determines if all the characters at any offset of the specified document line are the whitespace characters. * - * @param document the document to search in + * @param doc the document to search in * @param line zero-based document line number * * @return true if all the characters of the specified document line are the whitespace * characters, otherwise returns false */ - public static boolean isBlankLine(final IDocument document, final int line) { + public static boolean isBlankLine(final IDocument doc, final int line) { try { - int offset = document.getLineOffset(line); - final int lineEnd = offset + document.getLineLength(line); + int offset = doc.getLineOffset(line); + final int lineEnd = offset + doc.getLineLength(line); while (offset < lineEnd) { - if (!Character.isWhitespace(document.getChar(offset))) { + if (!Character.isWhitespace(doc.getChar(offset))) { return false; } offset++; diff --git a/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/widgets/OnEnterRuleTableWidget.java b/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/widgets/OnEnterRuleTableWidget.java index 10aeb4179..b60017bca 100644 --- a/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/widgets/OnEnterRuleTableWidget.java +++ b/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/widgets/OnEnterRuleTableWidget.java @@ -14,6 +14,7 @@ import static org.eclipse.tm4e.languageconfiguration.internal.LanguageConfigurationMessages.*; import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; import org.eclipse.jdt.annotation.Nullable; @@ -42,32 +43,21 @@ final class OnEnterRuleTableWidget extends TableViewer { final GC gc = new GC(table.getShell()); gc.setFont(JFaceResources.getDialogFont()); - final var columnLayout = new TableColumnLayout(); - final var column1 = new TableColumn(table, SWT.NONE); - column1.setText(OnEnterRuleTableWidget_beforeText); - int minWidth = computeMinimumColumnWidth(gc, OnEnterRuleTableWidget_beforeText); - columnLayout.setColumnData(column1, new ColumnWeightData(2, minWidth, true)); - - final var column2 = new TableColumn(table, SWT.NONE); - column2.setText(OnEnterRuleTableWidget_afterText); - minWidth = computeMinimumColumnWidth(gc, OnEnterRuleTableWidget_afterText); - columnLayout.setColumnData(column2, new ColumnWeightData(2, minWidth, true)); - - final var column3 = new TableColumn(table, SWT.NONE); - column3.setText(OnEnterRuleTableWidget_indentAction); - minWidth = computeMinimumColumnWidth(gc, OnEnterRuleTableWidget_indentAction); - columnLayout.setColumnData(column3, new ColumnWeightData(1, minWidth, true)); - - final var column4 = new TableColumn(table, SWT.NONE); - column4.setText(OnEnterRuleTableWidget_appendText); - minWidth = computeMinimumColumnWidth(gc, OnEnterRuleTableWidget_appendText); - columnLayout.setColumnData(column4, new ColumnWeightData(1, minWidth, true)); - - final var column5 = new TableColumn(table, SWT.NONE); - column5.setText(OnEnterRuleTableWidget_removeText); - minWidth = computeMinimumColumnWidth(gc, OnEnterRuleTableWidget_removeText); - columnLayout.setColumnData(column5, new ColumnWeightData(1, minWidth, true)); + final var colDefs = new LinkedHashMap(); + colDefs.put(OnEnterRuleTableWidget_beforeText, 2); + colDefs.put(OnEnterRuleTableWidget_afterText, 2); + colDefs.put(OnEnterRuleTableWidget_indentAction, 1); + colDefs.put(OnEnterRuleTableWidget_appendText, 1); + colDefs.put(OnEnterRuleTableWidget_removeText, 1); + + final var colLayout = new TableColumnLayout(); + for (final var colDef : colDefs.entrySet()) { + final var col = new TableColumn(table, SWT.NONE); + col.setText(colDef.getKey()); + final int minWidth = computeMinimumColumnWidth(gc, colDef.getKey()); + colLayout.setColumnData(col, new ColumnWeightData(colDef.getValue(), minWidth, true)); + } gc.dispose(); } @@ -81,14 +71,13 @@ private static final class OnEnterRuleContentProvider implements IStructuredCont private List onEnterRulesList = Collections.emptyList(); @Override - public Object[] getElements(@Nullable final Object input) { + public Object[] getElements(final @Nullable Object input) { return onEnterRulesList.toArray(OnEnterRule[]::new); } @SuppressWarnings("unchecked") @Override - public void inputChanged(@Nullable final Viewer viewer, @Nullable final Object oldInput, - @Nullable final Object newInput) { + public void inputChanged(final @Nullable Viewer viewer, final @Nullable Object oldInput, final @Nullable Object newInput) { if (newInput == null) { onEnterRulesList = Collections.emptyList(); } else { @@ -104,20 +93,18 @@ public void dispose() { private static final class OnEnterRuleLabelProvider extends LabelProvider implements ITableLabelProvider { - @Nullable @Override - public Image getColumnImage(@Nullable final Object element, final int columnIndex) { + public @Nullable Image getColumnImage(final @Nullable Object element, final int columnIndex) { return null; } - @Nullable @Override - public String getText(@Nullable final Object element) { + public String getText(final @Nullable Object element) { return getColumnText(element, 0); } @Override - public @Nullable String getColumnText(@Nullable final Object element, final int columnIndex) { + public String getColumnText(@Nullable final Object element, final int columnIndex) { if (element == null) return ""; @@ -130,7 +117,7 @@ public String getText(@Nullable final Object element) { case 2 -> action.indentAction.toString(); case 3 -> action.appendText != null ? action.appendText : ""; case 4 -> action.removeText != null ? action.removeText.toString() : ""; - default -> ""; //$NON-NLS-1$ + default -> ""; }; } } diff --git a/org.eclipse.tm4e.languageconfiguration/src/test/java/org/eclipse/tm4e/languageconfiguration/internal/model/OnEnterSupportTest.java b/org.eclipse.tm4e.languageconfiguration/src/test/java/org/eclipse/tm4e/languageconfiguration/internal/model/OnEnterSupportTest.java index 88108b79b..20e348ff0 100644 --- a/org.eclipse.tm4e.languageconfiguration/src/test/java/org/eclipse/tm4e/languageconfiguration/internal/model/OnEnterSupportTest.java +++ b/org.eclipse.tm4e.languageconfiguration/src/test/java/org/eclipse/tm4e/languageconfiguration/internal/model/OnEnterSupportTest.java @@ -83,24 +83,24 @@ class Support extends OnEnterSupport { new OnEnterRule( // e.g. /** | */ "^\\s*\\/\\*\\*(?!\\/)([^\\*]|\\*(?!\\/))*$", "^\\s*\\*\\/$", null, - new EnterAction(IndentAction.IndentOutdent).withAppendText(" * ")), + new EnterAction(IndentAction.IndentOutdent, " * ", null)), new OnEnterRule( // e.g. /** ...| "^\\s*\\/\\*\\*(?!\\/)([^\\*]|\\*(?!\\/))*$", null, null, - new EnterAction(IndentAction.None).withAppendText(" * ")), + new EnterAction(IndentAction.None, " * ", null)), new OnEnterRule( // e.g. * ...| "^(\\t|(\\ \\ ))*\\ \\*(\\ ([^\\*]|\\*(?!\\/))*)?$", null, "(?=^(\\s*(\\/\\*\\*|\\*)).*)(?=(?!(\\s*\\*\\/)))", - new EnterAction(IndentAction.None).withAppendText("* ")), + new EnterAction(IndentAction.None, "* ", null)), new OnEnterRule( // e.g. */| "^(\\t|(\\ \\ ))*\\ \\*\\/\\s*$", null, null, - new EnterAction(IndentAction.None).withRemoveText(1)), + new EnterAction(IndentAction.None, null, 1)), new OnEnterRule( // e.g. *-----*/| "^(\\t|(\\ \\ ))*\\ \\*[^/]*\\*\\/\\s*$", null, null, - new EnterAction(IndentAction.None).withRemoveText(1)))); + new EnterAction(IndentAction.None, null, 1)))); } void testIndentAction(final String previousLineText, final String beforeText, final String afterText,