Allow line break shorthand tags

This commit is contained in:
ajp_anton
2026-06-18 14:39:44 +00:00
parent 5395635a62
commit 7144b130f7
3 changed files with 59 additions and 17 deletions
@@ -1,7 +1,5 @@
package se.ajpanton.statusbartweak.runtime.features.clock; package se.ajpanton.statusbartweak.runtime.features.clock;
import android.text.TextUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@@ -94,7 +92,7 @@ final class ClockMarkupSupport {
} }
static void applyParsedTag(StringBuilder out, TagState state, ParsedTag parsedTag) { static void applyParsedTag(StringBuilder out, TagState state, ParsedTag parsedTag) {
if (TextUtils.isEmpty(parsedTag.name)) { if (isEmpty(parsedTag.name)) {
return; return;
} }
if (parsedTag.selfClosing) { if (parsedTag.selfClosing) {
@@ -125,7 +123,7 @@ final class ClockMarkupSupport {
String literal, String literal,
TagCategory category TagCategory category
) { ) {
if (TextUtils.isEmpty(name) || TextUtils.isEmpty(literal)) { if (isEmpty(name) || isEmpty(literal)) {
return; return;
} }
if (category == TagCategory.FONT_COLOR) { if (category == TagCategory.FONT_COLOR) {
@@ -140,7 +138,7 @@ final class ClockMarkupSupport {
} }
private static void closeTag(StringBuilder out, TagState state, String name) { private static void closeTag(StringBuilder out, TagState state, String name) {
if (TextUtils.isEmpty(name)) { if (isEmpty(name)) {
return; return;
} }
String normalized = name.toLowerCase(Locale.ROOT); String normalized = name.toLowerCase(Locale.ROOT);
@@ -187,7 +185,7 @@ final class ClockMarkupSupport {
} }
static ParsedTag parseTagLiteral(String literal) { static ParsedTag parseTagLiteral(String literal) {
if (TextUtils.isEmpty(literal)) { if (isEmpty(literal)) {
return null; return null;
} }
String trimmed = literal.trim(); String trimmed = literal.trim();
@@ -232,7 +230,7 @@ final class ClockMarkupSupport {
} }
static List<Integer> findPipePositions(String markup) { static List<Integer> findPipePositions(String markup) {
if (TextUtils.isEmpty(markup)) { if (isEmpty(markup)) {
return Collections.emptyList(); return Collections.emptyList();
} }
ArrayList<Integer> positions = new ArrayList<>(); ArrayList<Integer> positions = new ArrayList<>();
@@ -262,7 +260,7 @@ final class ClockMarkupSupport {
} }
static boolean containsSecondsPattern(String pattern) { static boolean containsSecondsPattern(String pattern) {
if (TextUtils.isEmpty(pattern)) { if (isEmpty(pattern)) {
return false; return false;
} }
boolean insideTag = false; boolean insideTag = false;
@@ -300,4 +298,8 @@ final class ClockMarkupSupport {
} }
return false; return false;
} }
private static boolean isEmpty(CharSequence value) {
return value == null || value.length() == 0;
}
} }
@@ -1,7 +1,5 @@
package se.ajpanton.statusbartweak.runtime.features.clock; package se.ajpanton.statusbartweak.runtime.features.clock;
import android.text.TextUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@@ -42,6 +40,13 @@ final class ClockPatternParser {
rowMarkup = new StringBuilder(); rowMarkup = new StringBuilder();
ClockMarkupSupport.appendOpenTags(rowMarkup, carriedState); ClockMarkupSupport.appendOpenTags(rowMarkup, carriedState);
rowSyntaxError = false; rowSyntaxError = false;
if (!isEmpty(lineBreak.trailingShorthand)) {
try {
appendShorthandBlock(rowMarkup, rowState, lineBreak.trailingShorthand);
} catch (IllegalArgumentException e) {
rowSyntaxError = true;
}
}
gapBeforePx = lineBreak.gapBeforePx; gapBeforePx = lineBreak.gapBeforePx;
index = lineBreak.endIndex; index = lineBreak.endIndex;
continue; continue;
@@ -111,7 +116,7 @@ final class ClockPatternParser {
} }
private ClockParsedPattern.ClockParsedRow buildParsedRow(String markup, int gapBeforePx) { private ClockParsedPattern.ClockParsedRow buildParsedRow(String markup, int gapBeforePx) {
if (TextUtils.isEmpty(markup)) { if (isEmpty(markup)) {
return ClockParsedPattern.ClockParsedRow.plain("", gapBeforePx); return ClockParsedPattern.ClockParsedRow.plain("", gapBeforePx);
} }
List<Integer> pipePositions = ClockMarkupSupport.findPipePositions(markup); List<Integer> pipePositions = ClockMarkupSupport.findPipePositions(markup);
@@ -153,7 +158,7 @@ final class ClockPatternParser {
} }
ArrayList<String> tokens = tokenizeShorthand(trimmed); ArrayList<String> tokens = tokenizeShorthand(trimmed);
for (String token : tokens) { for (String token : tokens) {
if (TextUtils.isEmpty(token)) { if (isEmpty(token)) {
continue; continue;
} }
if ("/font".equalsIgnoreCase(token)) { if ("/font".equalsIgnoreCase(token)) {
@@ -260,6 +265,10 @@ final class ClockPatternParser {
&& value.endsWith(")"); && value.endsWith(")");
} }
private boolean isEmpty(CharSequence value) {
return value == null || value.length() == 0;
}
private void openClockColorTag( private void openClockColorTag(
StringBuilder out, StringBuilder out,
ClockMarkupSupport.TagState tagState, ClockMarkupSupport.TagState tagState,
@@ -281,7 +290,7 @@ final class ClockPatternParser {
private LineBreakToken tryParseLineBreak(String pattern, int index) { private LineBreakToken tryParseLineBreak(String pattern, int index) {
if (pattern.startsWith("\\n", index)) { if (pattern.startsWith("\\n", index)) {
return new LineBreakToken(index + 2, false, ROW_GAP_AUTO); return new LineBreakToken(index + 2, false, ROW_GAP_AUTO, "");
} }
if (pattern.charAt(index) != '{') { if (pattern.charAt(index) != '{') {
return null; return null;
@@ -296,10 +305,11 @@ final class ClockPatternParser {
resetPropagation = true; resetPropagation = true;
body = body.substring(1).trim(); body = body.substring(1).trim();
} }
if (!body.startsWith("\\n")) { ArrayList<String> tokens = tokenizeShorthand(body);
if (tokens.isEmpty() || !tokens.get(0).startsWith("\\n")) {
return null; return null;
} }
String gapText = body.substring(2).trim(); String gapText = tokens.get(0).substring(2).trim();
int gapBeforePx = ROW_GAP_AUTO; int gapBeforePx = ROW_GAP_AUTO;
if (!gapText.isEmpty()) { if (!gapText.isEmpty()) {
try { try {
@@ -308,18 +318,27 @@ final class ClockPatternParser {
throw new IllegalArgumentException("Invalid row gap", e); throw new IllegalArgumentException("Invalid row gap", e);
} }
} }
return new LineBreakToken(end + 1, resetPropagation, gapBeforePx); StringBuilder trailingShorthand = new StringBuilder();
for (int i = 1; i < tokens.size(); i++) {
if (trailingShorthand.length() > 0) {
trailingShorthand.append(' ');
}
trailingShorthand.append(tokens.get(i));
}
return new LineBreakToken(end + 1, resetPropagation, gapBeforePx, trailingShorthand.toString());
} }
private static final class LineBreakToken { private static final class LineBreakToken {
final int endIndex; final int endIndex;
final boolean resetPropagation; final boolean resetPropagation;
final int gapBeforePx; final int gapBeforePx;
final String trailingShorthand;
LineBreakToken(int endIndex, boolean resetPropagation, int gapBeforePx) { LineBreakToken(int endIndex, boolean resetPropagation, int gapBeforePx, String trailingShorthand) {
this.endIndex = endIndex; this.endIndex = endIndex;
this.resetPropagation = resetPropagation; this.resetPropagation = resetPropagation;
this.gapBeforePx = gapBeforePx; this.gapBeforePx = gapBeforePx;
this.trailingShorthand = trailingShorthand != null ? trailingShorthand : "";
} }
} }
} }
@@ -0,0 +1,21 @@
package se.ajpanton.statusbartweak.runtime.features.clock;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public final class ClockPatternParserTest {
private final ClockPatternParser parser = new ClockPatternParser();
@Test
public void lineBreakBlockAcceptsFollowingShorthandTags() {
ClockParsedPattern combined = parser.parse("HH{\\n30 big}mm");
ClockParsedPattern split = parser.parse("HH{\\n30}{big}mm");
assertEquals(split.rows.size(), combined.rows.size());
assertEquals(2, combined.rows.size());
assertEquals(split.rows.get(1).gapBeforePx, combined.rows.get(1).gapBeforePx);
assertEquals(30, combined.rows.get(1).gapBeforePx);
assertEquals(split.rows.get(1).markup, combined.rows.get(1).markup);
}
}