From 3df2f78c9e85c964a2175a870ac4d31218914776 Mon Sep 17 00:00:00 2001 From: Tako Schotanus Date: Wed, 18 Mar 2026 12:32:56 +0100 Subject: [PATCH] fix: minor Markup fixes and refactorings --- .../org/codejive/twinkle/fluent/Fluent.java | 4 +- .../org/codejive/twinkle/fluent/Markup.java | 13 ---- .../codejive/twinkle/fluent/MarkupParser.java | 7 ++ .../fluent/commands/TextualCommands.java | 8 +++ ...ltMarkup.java => DefaultMarkupParser.java} | 64 ++++++++----------- .../twinkle/fluent/impl/FluentImpl.java | 21 ++++-- ...rkup.java => TestDefaultMarkupParser.java} | 58 +++++++++-------- .../codejive/twinkle/fluent/TestFluent.java | 43 +++++++++++++ 8 files changed, 133 insertions(+), 85 deletions(-) delete mode 100644 twinkle-text/src/main/java/org/codejive/twinkle/fluent/Markup.java create mode 100644 twinkle-text/src/main/java/org/codejive/twinkle/fluent/MarkupParser.java rename twinkle-text/src/main/java/org/codejive/twinkle/fluent/impl/{DefaultMarkup.java => DefaultMarkupParser.java} (83%) rename twinkle-text/src/test/java/org/codejive/twinkle/fluent/{TestDefaultMarkup.java => TestDefaultMarkupParser.java} (89%) diff --git a/twinkle-text/src/main/java/org/codejive/twinkle/fluent/Fluent.java b/twinkle-text/src/main/java/org/codejive/twinkle/fluent/Fluent.java index a9defa7..74bfa4b 100644 --- a/twinkle-text/src/main/java/org/codejive/twinkle/fluent/Fluent.java +++ b/twinkle-text/src/main/java/org/codejive/twinkle/fluent/Fluent.java @@ -58,10 +58,10 @@ static Fluent of(Appendable appendable, Style startingStyle) { * Sets the Markup parser to use for parsing markup patterns in text. This is useful for * allowing users to define their own custom markup syntax. * - * @param markup the Markup parser to use + * @param markupParser the Markup parser to use * @return this Fluent instance for chaining */ - Fluent markupParser(Markup markup); + Fluent markupParser(MarkupParser markupParser); /** * Returns the current style combining the styles that have been applied since the creation of diff --git a/twinkle-text/src/main/java/org/codejive/twinkle/fluent/Markup.java b/twinkle-text/src/main/java/org/codejive/twinkle/fluent/Markup.java deleted file mode 100644 index edae91f..0000000 --- a/twinkle-text/src/main/java/org/codejive/twinkle/fluent/Markup.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.codejive.twinkle.fluent; - -/** An interface for possible markup parser implementations that can be used for the `Fluent` */ -public interface Markup { - - default String parse(String textWithMarkup) { - StringBuilder sb = new StringBuilder(); - parse(sb, textWithMarkup); - return sb.toString(); - } - - void parse(Appendable appendable, String textWithMarkup); -} diff --git a/twinkle-text/src/main/java/org/codejive/twinkle/fluent/MarkupParser.java b/twinkle-text/src/main/java/org/codejive/twinkle/fluent/MarkupParser.java new file mode 100644 index 0000000..ac64ed3 --- /dev/null +++ b/twinkle-text/src/main/java/org/codejive/twinkle/fluent/MarkupParser.java @@ -0,0 +1,7 @@ +package org.codejive.twinkle.fluent; + +/** An interface for possible markup parser implementations that can be used for the `Fluent` */ +public interface MarkupParser { + + void parse(Fluent fluent, String textWithMarkup); +} diff --git a/twinkle-text/src/main/java/org/codejive/twinkle/fluent/commands/TextualCommands.java b/twinkle-text/src/main/java/org/codejive/twinkle/fluent/commands/TextualCommands.java index 04a49e1..caf9024 100644 --- a/twinkle-text/src/main/java/org/codejive/twinkle/fluent/commands/TextualCommands.java +++ b/twinkle-text/src/main/java/org/codejive/twinkle/fluent/commands/TextualCommands.java @@ -27,6 +27,14 @@ default Fluent text(@NonNull Printable prt) { */ Fluent text(@NonNull Object obj, Object... args); + /** + * Writes the given string + * + * @param text the text to output + * @return this Fluent instance for chaining + */ + Fluent plain(@NonNull String text); + Fluent markup(@NonNull Object obj, Object... args); /** diff --git a/twinkle-text/src/main/java/org/codejive/twinkle/fluent/impl/DefaultMarkup.java b/twinkle-text/src/main/java/org/codejive/twinkle/fluent/impl/DefaultMarkupParser.java similarity index 83% rename from twinkle-text/src/main/java/org/codejive/twinkle/fluent/impl/DefaultMarkup.java rename to twinkle-text/src/main/java/org/codejive/twinkle/fluent/impl/DefaultMarkupParser.java index 759bb75..32e0cda 100644 --- a/twinkle-text/src/main/java/org/codejive/twinkle/fluent/impl/DefaultMarkup.java +++ b/twinkle-text/src/main/java/org/codejive/twinkle/fluent/impl/DefaultMarkupParser.java @@ -6,7 +6,8 @@ import java.util.regex.Pattern; import org.codejive.twinkle.ansi.Color; import org.codejive.twinkle.ansi.Hyperlink; -import org.codejive.twinkle.fluent.Markup; +import org.codejive.twinkle.fluent.Fluent; +import org.codejive.twinkle.fluent.MarkupParser; import org.codejive.twinkle.fluent.commands.ColorCommands; import org.codejive.twinkle.fluent.commands.NegatableCommands; @@ -16,46 +17,40 @@ * like `{red}` applying a red color. While others can have parameters, like `{~10,5}` moving the * cursor to column 10 and row 5. */ -public class DefaultMarkup implements Markup { - protected final FluentImpl fluent; - +public class DefaultMarkupParser implements MarkupParser { private static Map colors; private static final Pattern markupPattern = Pattern.compile("(? lastIndex) { - append(appendable, textWithMarkup.substring(lastIndex, matcher.start())); + append(fluent, textWithMarkup.substring(lastIndex, matcher.start())); } // Handle the markup content String markupContent = matcher.group(1); - handleMarkup(appendable, markupContent); + handleMarkup(fluent, markupContent); lastIndex = matcher.end(); } // Append any remaining text after the last markup if (lastIndex < textWithMarkup.length()) { - append(appendable, textWithMarkup.substring(lastIndex, textWithMarkup.length())); + append(fluent, textWithMarkup.substring(lastIndex, textWithMarkup.length())); } } - protected void handleMarkup(Appendable appendable, String markup) { - if (tryStyles(markup, fluent)) { + protected void handleMarkup(Fluent fluent, String markup) { + if (tryStyles(fluent, markup)) { return; } if (markup.startsWith("/") && markup.length() > 1) { String closeMarkup = markup.substring(1); - if (tryStyles(closeMarkup, fluent.not())) { + if (tryStyles(fluent.not(), closeMarkup)) { return; } } @@ -81,26 +76,20 @@ protected void handleMarkup(Appendable appendable, String markup) { return; } - if (tryPosition(markup)) { + if (tryPosition(fluent, markup)) { return; } - Hyperlink link = tryHyperlink(markup); - if (link != null) { - if (link == Hyperlink.END) { - fluent.lru(); - } else { - fluent.url(link.url, link.id); - } + if (tryHyperlink(fluent, markup)) { return; } - if (tryColors(markup)) { + if (tryColors(fluent, markup)) { return; } } - private boolean tryStyles(String markup, NegatableCommands fluentNeg) { + private boolean tryStyles(NegatableCommands fluentNeg, String markup) { switch (markup.toLowerCase()) { case "bold": case "b": @@ -135,7 +124,7 @@ private boolean tryStyles(String markup, NegatableCommands fluentNeg) { return false; } - private boolean tryPosition(String markup) { + private boolean tryPosition(Fluent fluent, String markup) { switch (markup.toLowerCase()) { case "mark": case "@": @@ -217,24 +206,27 @@ private int parsePos(String pos, int max) throws NumberFormatException { return Integer.parseInt(pos.trim()); } - private Hyperlink tryHyperlink(String markup) { + private boolean tryHyperlink(Fluent fluent, String markup) { if (markup.equals("/")) { - return Hyperlink.END; + fluent.lru(); + return true; } else if (markup.startsWith("http://") || markup.startsWith("https://")) { - return Hyperlink.of(markup); + Hyperlink link = Hyperlink.of(markup); + fluent.url(link.url, link.id); + return true; } - return null; + return false; } - private boolean tryColors(String markup) { + private boolean tryColors(Fluent fluent, String markup) { if (markup.startsWith("bg:")) { - return tryColors(markup.substring(3), fluent.bg()); + return tryColorsFgBg(fluent.bg(), markup.substring(3)); } else { - return tryColors(markup, fluent); + return tryColorsFgBg(fluent, markup); } } - private boolean tryColors(String markup, ColorCommands fluentColors) { + private boolean tryColorsFgBg(ColorCommands fluentColors, String markup) { // Try #RRGGBB format first Color color = tryRgbColor(markup); if (color == null) { @@ -289,9 +281,9 @@ private Color tryColorByName(String markup) { return colors.get(lmarkup); } - protected void append(Appendable appendable, String text) { + protected void append(Fluent fluent, String text) { try { - appendable.append(text); + fluent.plain(text); } catch (Exception e) { // We simply ignore errors } diff --git a/twinkle-text/src/main/java/org/codejive/twinkle/fluent/impl/FluentImpl.java b/twinkle-text/src/main/java/org/codejive/twinkle/fluent/impl/FluentImpl.java index 9113d35..72935bc 100644 --- a/twinkle-text/src/main/java/org/codejive/twinkle/fluent/impl/FluentImpl.java +++ b/twinkle-text/src/main/java/org/codejive/twinkle/fluent/impl/FluentImpl.java @@ -13,7 +13,7 @@ import org.codejive.twinkle.ansi.util.AnsiTricks; import org.codejive.twinkle.ansi.util.Printable; import org.codejive.twinkle.fluent.Fluent; -import org.codejive.twinkle.fluent.Markup; +import org.codejive.twinkle.fluent.MarkupParser; import org.codejive.twinkle.fluent.commands.ColorCommands; import org.codejive.twinkle.fluent.commands.LineCommands; import org.codejive.twinkle.fluent.commands.NegatableCommands; @@ -33,7 +33,7 @@ public class FluentImpl implements Fluent { protected final Style startingStyle; protected Style currentStyle; protected Deque