From b6bc21f26ccd7c9faa0dc361d8f897f4c2b0e014 Mon Sep 17 00:00:00 2001 From: Reinhard Pointner Date: Sun, 5 Aug 2018 19:02:20 +0700 Subject: [PATCH] Experiment with first class RSTA support --- ivy.xml | 1 + lib/jar.includes | 1 + .../ui/rename/FormatExpressionTokenMaker.java | 150 ++++++++++++++++++ .../FormatExpressionTokenMakerFactory.java | 22 +++ 4 files changed, 174 insertions(+) create mode 100644 source/net/filebot/ui/rename/FormatExpressionTokenMaker.java create mode 100644 source/net/filebot/ui/rename/FormatExpressionTokenMakerFactory.java diff --git a/ivy.xml b/ivy.xml index 088bbd3b..e8f34da1 100644 --- a/ivy.xml +++ b/ivy.xml @@ -21,6 +21,7 @@ + diff --git a/lib/jar.includes b/lib/jar.includes index 0fe7f773..65ccf620 100644 --- a/lib/jar.includes +++ b/lib/jar.includes @@ -4,6 +4,7 @@ ivy/jar/miglayout-swing.jar ivy/jar/glazedlists_java16.jar ivy/jar/controlsfx.jar ivy/jar/rsyntaxtextarea.jar +ivy/jar/autocomplete.jar ivy/jar/lanterna.jar ivy/jar/xz.jar ivy/jar/sevenzipjbinding.jar diff --git a/source/net/filebot/ui/rename/FormatExpressionTokenMaker.java b/source/net/filebot/ui/rename/FormatExpressionTokenMaker.java new file mode 100644 index 00000000..4fa102fc --- /dev/null +++ b/source/net/filebot/ui/rename/FormatExpressionTokenMaker.java @@ -0,0 +1,150 @@ +package net.filebot.ui.rename; + +import javax.swing.text.Segment; + +import org.fife.ui.rsyntaxtextarea.Token; +import org.fife.ui.rsyntaxtextarea.TokenImpl; +import org.fife.ui.rsyntaxtextarea.TokenMakerBase; +import org.fife.ui.rsyntaxtextarea.TokenTypes; +import org.fife.ui.rsyntaxtextarea.modes.GroovyTokenMaker; + +public class FormatExpressionTokenMaker extends TokenMakerBase { + + private static final GroovyExpressionTokenMaker groovyTokenMaker = new GroovyExpressionTokenMaker(); + + public static final int LANGUAGE_LITERAL = 0; + public static final int LANGUAGE_GROOVY = 10; + + @Override + public Token getTokenList(Segment segment, int initialTokenType, int startOffset) { + resetTokenList(); + groovyTokenMaker.reset(); + + int level = getInitialLevel(segment, initialTokenType, startOffset); + setLanguageIndex(level > 0 ? LANGUAGE_GROOVY : LANGUAGE_LITERAL); + + int start = 0; + int end = 0; + + // parse expressions and literals + for (int i = 0; i < segment.length(); i++) { + switch (segment.charAt(i)) { + case '{': + if (level <= 0) { + if (start != end) { + addToken(segment, segment.getBeginIndex() + start, segment.getBeginIndex() + end - 1, Token.MARKUP_CDATA, startOffset + start); + } + setLanguageIndex(LANGUAGE_GROOVY); + addToken(segment, segment.getBeginIndex() + i, segment.getBeginIndex() + i, Token.MARKUP_CDATA_DELIMITER, startOffset + i); + start = end = i + 1; + level = 0; + } else { + end++; + } + level++; + break; + case '}': + if (level == 1) { + if (start != end) { + Segment groovySegment = new Segment(segment.array, segment.getBeginIndex() + start, end - start); + addToken(groovyTokenMaker.getTokenList(groovySegment, initialTokenType, startOffset + start)); + } + addToken(segment, segment.getBeginIndex() + i, segment.getBeginIndex() + i, Token.MARKUP_CDATA_DELIMITER, startOffset + i); + setLanguageIndex(LANGUAGE_LITERAL); + start = end = i + 1; + } else { + end++; + } + level--; + break; + default: + end++; + break; + } + + } + + switch (getLanguageIndex()) { + case LANGUAGE_GROOVY: + if (start != end) { + Segment groovySegment = new Segment(segment.array, segment.getBeginIndex() + start, end - start); + addToken(groovyTokenMaker.getTokenList(groovySegment, initialTokenType, startOffset + start)); + } + if (firstToken == null) { + addToken(segment, segment.getBeginIndex() + start, segment.getBeginIndex() + end - 1, initialTokenType, startOffset + start); + } + break; + default: + if (start != end) { + addToken(segment, segment.getBeginIndex() + start, segment.getBeginIndex() + end - 1, Token.MARKUP_CDATA, startOffset + start); + } + addNullToken(); + break; + } + + return firstToken; + } + + protected int getInitialLevel(Segment segment, int initialTokenType, int startOffset) { + return initialTokenType == TokenTypes.NULL ? 0 : 1; + } + + protected void addToken(Token token) { + Token tail = token.getNextToken(); + + if (firstToken == null) { + firstToken = (TokenImpl) token; + currentToken = firstToken; + } else { + TokenImpl next = (TokenImpl) token; + currentToken.setNextToken(next); + previousToken = currentToken; + currentToken = next; + } + + currentToken.setLanguageIndex(getLanguageIndex()); + currentToken.setHyperlink(false); + + // new current token must be the tail + currentToken.setNextToken(null); + + if (tail != null && tail.getType() != TokenTypes.NULL) { + addToken(tail); + } + } + + @Override + public boolean getCurlyBracesDenoteCodeBlocks(int languageIndex) { + return true; + } + + @Override + public String[] getLineCommentStartAndEnd(int languageIndex) { + switch (languageIndex) { + case LANGUAGE_GROOVY: + return groovyTokenMaker.getLineCommentStartAndEnd(0); + default: + return null; + } + } + + @Override + public boolean getShouldIndentNextLineAfter(Token token) { + return groovyTokenMaker.getShouldIndentNextLineAfter(token); + } + + private static class GroovyExpressionTokenMaker extends GroovyTokenMaker { + + @Override + protected void resetTokenList() { + // reset list structure, but do not reset shared token objects + firstToken = currentToken = previousToken = null; + } + + protected void reset() { + // reset list structure and reset shared token objects + super.resetTokenList(); + } + } + +} diff --git a/source/net/filebot/ui/rename/FormatExpressionTokenMakerFactory.java b/source/net/filebot/ui/rename/FormatExpressionTokenMakerFactory.java new file mode 100644 index 00000000..5eeaa7d1 --- /dev/null +++ b/source/net/filebot/ui/rename/FormatExpressionTokenMakerFactory.java @@ -0,0 +1,22 @@ +package net.filebot.ui.rename; +import static java.util.Collections.*; + +import java.util.Set; + +import org.fife.ui.rsyntaxtextarea.TokenMakerFactory; + +public class FormatExpressionTokenMakerFactory extends TokenMakerFactory { + + public static final String SYNTAX_STYLE_GROOVY_FORMAT_EXPRESSION = "text/groovy-format-expression"; + + @Override + public FormatExpressionTokenMaker getTokenMakerImpl(String key) { + return new FormatExpressionTokenMaker(); + } + + @Override + public Set keySet() { + return singleton(SYNTAX_STYLE_GROOVY_FORMAT_EXPRESSION); + } + +}