From 63a09e24c55eeb8b456760c2e853d01b5c9f4e32 Mon Sep 17 00:00:00 2001 From: Arnaud Roques Date: Sun, 21 May 2023 10:54:21 +0200 Subject: [PATCH] chore: Version 1.2023.8 --- gradle.properties | 2 +- .../activitydiagram3/ftile/Snake.java | 7 +- .../plantuml/activitydiagram3/ftile/Worm.java | 7 ++ .../ftile/vcompact/FtileWhile.java | 25 ++++-- .../plantuml/dot/GraphvizLinux.java | 16 ++-- .../plantuml/regexdiagram/PSystemRegex.java | 71 ++++++++-------- .../regexdiagram/RegexExpression.java | 83 +++++++++++++++++-- .../regexdiagram/RegexParsingException.java | 44 ++++++++++ .../sourceforge/plantuml/version/Version.java | 4 +- 9 files changed, 191 insertions(+), 68 deletions(-) create mode 100644 src/net/sourceforge/plantuml/regexdiagram/RegexParsingException.java diff --git a/gradle.properties b/gradle.properties index 494c5b2d6..98e9dffbc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ # Warning, "version" should be the same in gradle.properties and Version.java # Any idea anyone how to magically synchronize those :-) ? -version = 1.2023.8beta2 +version = 1.2023.8 org.gradle.workers.max = 3 \ No newline at end of file diff --git a/src/net/sourceforge/plantuml/activitydiagram3/ftile/Snake.java b/src/net/sourceforge/plantuml/activitydiagram3/ftile/Snake.java index c0cbc6f07..b25689ab8 100644 --- a/src/net/sourceforge/plantuml/activitydiagram3/ftile/Snake.java +++ b/src/net/sourceforge/plantuml/activitydiagram3/ftile/Snake.java @@ -141,9 +141,6 @@ public class Snake implements UShape { if (textBlock != null && textBlock != TextBlockUtils.EMPTY_TEXT_BLOCK) this.texts.add(new Text(textBlock, verticalAlignment, null)); - if (verticalAlignment != VerticalAlignment.CENTER) - throw new UnsupportedOperationException(); - return this; } @@ -264,8 +261,8 @@ public class Snake implements UShape { final boolean zigzag = worm.getDirectionsCode().startsWith("DLD") || worm.getDirectionsCode().startsWith("DRD"); double y = (pt1.getY() + pt2.getY()) / 2 - dim.getHeight() / 2; if (text.verticalAlignment == VerticalAlignment.BOTTOM) { - x = worm.getLast().getX(); - throw new AssertionError(); + x = worm.getMinX(); + y = worm.getMaxY(); } else if (text.verticalAlignment == VerticalAlignment.CENTER) { x = worm.getMinX(); y = (worm.getFirst().getY() + worm.getLast().getY() - 10) / 2 - dim.getHeight() / 2; diff --git a/src/net/sourceforge/plantuml/activitydiagram3/ftile/Worm.java b/src/net/sourceforge/plantuml/activitydiagram3/ftile/Worm.java index 9a6ca85c2..9fbc1f824 100644 --- a/src/net/sourceforge/plantuml/activitydiagram3/ftile/Worm.java +++ b/src/net/sourceforge/plantuml/activitydiagram3/ftile/Worm.java @@ -333,6 +333,13 @@ public class Worm implements Iterable { return result; } + public double getMaxY() { + double result = points.get(0).getY(); + for (XPoint2D pt : points) + result = Math.max(result, pt.getY()); + return result; + } + public Worm merge(Worm other, MergeStrategy merge) { if (Snake.same(this.getLast(), other.getFirst()) == false) throw new IllegalArgumentException(); diff --git a/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileWhile.java b/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileWhile.java index 109ff413b..4a4de30d4 100644 --- a/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileWhile.java +++ b/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileWhile.java @@ -67,6 +67,7 @@ import net.sourceforge.plantuml.klimt.drawing.UGraphic; import net.sourceforge.plantuml.klimt.font.FontConfiguration; import net.sourceforge.plantuml.klimt.font.StringBounder; import net.sourceforge.plantuml.klimt.geom.HorizontalAlignment; +import net.sourceforge.plantuml.klimt.geom.VerticalAlignment; import net.sourceforge.plantuml.klimt.geom.XDimension2D; import net.sourceforge.plantuml.klimt.geom.XPoint2D; import net.sourceforge.plantuml.klimt.shape.TextBlock; @@ -81,6 +82,7 @@ class FtileWhile extends AbstractFtile { private final Ftile diamond1; private final Ftile specialOut; private final Ftile backward; + private TextBlock back1; @Override public Collection getMyChildren() { @@ -141,8 +143,7 @@ class FtileWhile extends AbstractFtile { final FtileWhile result = new FtileWhile(whileBlock, diamond1, special, backward); final XDimension2D dim = whileBlock.calculateDimension(ftileFactory.getStringBounder()); - final TextBlock back1 = incoming1.getDisplay().create(fontArrow, HorizontalAlignment.LEFT, - ftileFactory.skinParam()); + result.back1 = incoming1.getDisplay().create(fontArrow, HorizontalAlignment.LEFT, ftileFactory.skinParam()); final List conns = new ArrayList<>(); if (dim.getWidth() == 0 || dim.getHeight() == 0) { @@ -150,11 +151,11 @@ class FtileWhile extends AbstractFtile { } else { conns.add(result.new ConnectionIn(whileBlock.getInLinkRendering().getRainbow(arrowColor))); if (backward == null) { - conns.add(result.new ConnectionBackSimple(incoming1.getRainbow(), back1)); + conns.add(result.new ConnectionBackSimple(incoming1.getRainbow(), result.back1)); } else { final TextBlock back2 = incoming2.getDisplay().create(fontArrow, HorizontalAlignment.LEFT, ftileFactory.skinParam()); - conns.add(result.new ConnectionBackBackward1(incoming1.getRainbow(), back1)); + conns.add(result.new ConnectionBackBackward1(incoming1.getRainbow(), result.back1)); conns.add(result.new ConnectionBackBackward2(incoming2.getRainbow(), back2)); } } @@ -257,7 +258,7 @@ class FtileWhile extends AbstractFtile { final double y2 = p2.getY() + dimDiamond1.getInY() + half; final Snake snake = Snake.create(skinParam(), endInlinkColor, skinParam().arrows().asToLeft()) - .emphasizeDirection(Direction.UP).withLabel(back, arrowHorizontalAlignment()); + .emphasizeDirection(Direction.UP).withLabel(back, VerticalAlignment.BOTTOM); snake.addPoint(x1, y1); final double y1bis = Math.max(y1, getBottom(stringBounder)) + Hexagon.hexagonHalfSize; snake.addPoint(x1, y1bis); @@ -350,7 +351,7 @@ class FtileWhile extends AbstractFtile { final double y2 = p2.getY(); final Snake snake = Snake.create(skinParam(), endInlinkColor, skinParam().arrows().asToUp()).withLabel(back, - arrowHorizontalAlignment()); + VerticalAlignment.BOTTOM); snake.addPoint(x1, y1); final double y1bis = Math.max(y1, getBottom(stringBounder)) + Hexagon.hexagonHalfSize; snake.addPoint(x1, y1bis); @@ -580,7 +581,7 @@ class FtileWhile extends AbstractFtile { assert false; } final FtileGeometry geo = geoDiamond1.appendBottom(geoWhile); - final double height = geo.getHeight() + 4 * Hexagon.hexagonHalfSize; + final double height = geo.getHeight() + 4 * Hexagon.hexagonHalfSize + getSuppHeightForLabel(stringBounder); final double dx = 2 * Hexagon.hexagonHalfSize; double backwardWidth = 0; if (backward != null) @@ -592,6 +593,12 @@ class FtileWhile extends AbstractFtile { } + private double getSuppHeightForLabel(StringBounder stringBounder) { + if (back1 != null) + return back1.calculateDimension(stringBounder).getHeight(); + return 0; + } + private double xDeltaBecauseSpecial(StringBounder stringBounder) { if (specialOut == null) return 0; @@ -616,8 +623,8 @@ class FtileWhile extends AbstractFtile { final FtileGeometry dimTotal = calculateDimension(stringBounder); final FtileGeometry dimWhile = whileBlock.calculateDimension(stringBounder); - final double y = dimDiamond1.getHeight() - + (dimTotal.getHeight() - dimDiamond1.getHeight() - dimWhile.getHeight()) / 2; + final double y = dimDiamond1.getHeight() + (dimTotal.getHeight() - dimDiamond1.getHeight() + - dimWhile.getHeight() - getSuppHeightForLabel(stringBounder)) / 2; final double x = dimTotal.getLeft() - dimWhile.getLeft(); return new UTranslate(x, y); diff --git a/src/net/sourceforge/plantuml/dot/GraphvizLinux.java b/src/net/sourceforge/plantuml/dot/GraphvizLinux.java index dfaeb46f8..a1db5a1bd 100644 --- a/src/net/sourceforge/plantuml/dot/GraphvizLinux.java +++ b/src/net/sourceforge/plantuml/dot/GraphvizLinux.java @@ -48,16 +48,12 @@ class GraphvizLinux extends AbstractGraphviz { @Override protected File specificDotExe() { - final File usrLocalBinDot = new File("/usr/local/bin/dot"); - if (usrLocalBinDot.exists()) { - return usrLocalBinDot; - } - final File usrBinDot = new File("/usr/bin/dot"); - if (usrBinDot.exists()) { - return usrBinDot; - } - final File optLocalBinDot = new File("/opt/local/bin/dot"); - return optLocalBinDot; + final File all[] = new File[] { new File("/usr/local/bin/dot"), new File("/usr/bin/dot"), + new File("/opt/homebrew/bin/dot") }; + for (File f : all) + if (f.exists()) + return f; + return new File("/opt/local/bin/dot"); } @Override diff --git a/src/net/sourceforge/plantuml/regexdiagram/PSystemRegex.java b/src/net/sourceforge/plantuml/regexdiagram/PSystemRegex.java index ab25d895e..af874516c 100644 --- a/src/net/sourceforge/plantuml/regexdiagram/PSystemRegex.java +++ b/src/net/sourceforge/plantuml/regexdiagram/PSystemRegex.java @@ -147,39 +147,44 @@ public class PSystemRegex extends TitledDiagram { } public CommandExecutionResult addBlocLines(BlocLines from) { - final CharInspector it = from.inspector(); - final List parsed1 = RegexExpression.parse(it); - // System.err.println("parsed1=" + parsed1); - final List parsed2 = addImplicitConcatenation(parsed1); - // System.err.println("parsed2=" + parsed2); - final ShuntingYard shuntingYard = new ShuntingYard(parsed2.iterator()); - final List result = shuntingYard.getOuputQueue(); - // System.err.println("result=" + result); - for (ReToken token : result) - if (token.getType() == ReTokenType.SIMPLE_CHAR) - push(token, Symbol.TERMINAL_STRING1); - else if (token.getType() == ReTokenType.ESCAPED_CHAR) - push(token, Symbol.TERMINAL_STRING1); - else if (token.getType() == ReTokenType.GROUP) - push(token, Symbol.SPECIAL_SEQUENCE); - else if (token.getType() == ReTokenType.CLASS) - push(token, Symbol.LITTERAL); - else if (token.getType() == ReTokenType.ANCHOR) - push(token, Symbol.LITTERAL); - else if (token.getType() == ReTokenType.CONCATENATION_IMPLICIT) - concatenation(); - else if (token.getType() == ReTokenType.ALTERNATIVE) - alternation(); - else if (token.getType() == ReTokenType.QUANTIFIER && token.getData().startsWith("*")) - repetitionZeroOrMore(false); - else if (token.getType() == ReTokenType.QUANTIFIER && token.getData().startsWith("+")) - repetitionOneOrMore(); - else if (token.getType() == ReTokenType.QUANTIFIER && token.getData().startsWith("?")) - optional(); - else if (token.getType() == ReTokenType.QUANTIFIER && token.getData().startsWith("{")) - repetitionOneOrMore(token.getData()); - else - throw new UnsupportedOperationException(token.toString()); + + try { + final CharInspector it = from.inspector(); + final List parsed1 = RegexExpression.parse(it); + // System.err.println("parsed1=" + parsed1); + final List parsed2 = addImplicitConcatenation(parsed1); + // System.err.println("parsed2=" + parsed2); + final ShuntingYard shuntingYard = new ShuntingYard(parsed2.iterator()); + final List result = shuntingYard.getOuputQueue(); + // System.err.println("result=" + result); + for (ReToken token : result) + if (token.getType() == ReTokenType.SIMPLE_CHAR) + push(token, Symbol.TERMINAL_STRING1); + else if (token.getType() == ReTokenType.ESCAPED_CHAR) + push(token, Symbol.TERMINAL_STRING1); + else if (token.getType() == ReTokenType.GROUP) + push(token, Symbol.SPECIAL_SEQUENCE); + else if (token.getType() == ReTokenType.CLASS) + push(token, Symbol.LITTERAL); + else if (token.getType() == ReTokenType.ANCHOR) + push(token, Symbol.LITTERAL); + else if (token.getType() == ReTokenType.CONCATENATION_IMPLICIT) + concatenation(); + else if (token.getType() == ReTokenType.ALTERNATIVE) + alternation(); + else if (token.getType() == ReTokenType.QUANTIFIER && token.getData().startsWith("*")) + repetitionZeroOrMore(false); + else if (token.getType() == ReTokenType.QUANTIFIER && token.getData().startsWith("+")) + repetitionOneOrMore(); + else if (token.getType() == ReTokenType.QUANTIFIER && token.getData().startsWith("?")) + optional(); + else if (token.getType() == ReTokenType.QUANTIFIER && token.getData().startsWith("{")) + repetitionOneOrMore(token.getData()); + else + throw new RegexParsingException(token.toString()); + } catch (RegexParsingException ex) { + return CommandExecutionResult.error("Error parsing: " + ex.getMessage()); + } return CommandExecutionResult.ok(); } diff --git a/src/net/sourceforge/plantuml/regexdiagram/RegexExpression.java b/src/net/sourceforge/plantuml/regexdiagram/RegexExpression.java index 90ef54ec3..77ab74334 100644 --- a/src/net/sourceforge/plantuml/regexdiagram/RegexExpression.java +++ b/src/net/sourceforge/plantuml/regexdiagram/RegexExpression.java @@ -41,9 +41,9 @@ import java.util.List; import net.sourceforge.plantuml.utils.CharInspector; public class RegexExpression { - // ::remove folder when __HAXE__ + // ::remove folder when __HAXE__ - public static List parse(CharInspector it) { + public static List parse(CharInspector it) throws RegexParsingException { final List result = new ArrayList<>(); while (true) { final char current = it.peek(0); @@ -72,6 +72,15 @@ public class RegexExpression { } else if (isStartQuantifier(it)) { final String s = readQuantifier(it); result.add(new ReToken(ReTokenType.QUANTIFIER, s)); + } else if (isStartOctalEscape(it)) { + final String s = readUnicodeOrOctalEscape(it, 4); + result.add(new ReToken(ReTokenType.CLASS, s)); + } else if (isStartUnicodeEscape(it)) { + final String s = readUnicodeOrOctalEscape(it, 5); + result.add(new ReToken(ReTokenType.CLASS, s)); + } else if (isStartUnicodeClass(it)) { + final String s = readUnicodeClass(it); + result.add(new ReToken(ReTokenType.CLASS, s)); } else if (isStartClass(it)) { final String s = readClass(it); result.add(new ReToken(ReTokenType.CLASS, s)); @@ -119,24 +128,28 @@ public class RegexExpression { return false; } - private static String readQuantifier(CharInspector it) { + private static String readQuantifier(CharInspector it) throws RegexParsingException { final char current0 = it.peek(0); it.jump(); - final StringBuilder result = new StringBuilder(); - result.append(current0); + final StringBuilder tmp = new StringBuilder(); + tmp.append(current0); if (current0 == '{') while (it.peek(0) != 0) { final char ch = it.peek(0); - result.append(ch); + tmp.append(ch); it.jump(); if (ch == '}') break; } if (it.peek(0) == '?') { - result.append('?'); + tmp.append('?'); it.jump(); } - return result.toString(); + // System.err.println("RESULT=" + tmp); + final String result = tmp.toString(); + if (result.startsWith("{") && result.matches("^\\{[0-9,]+\\}$") == false) + throw new RegexParsingException("Bad quantifier " + result); + return result; } private static boolean isEscapedChar(CharInspector it) { @@ -173,6 +186,40 @@ public class RegexExpression { return result.toString(); } + private static String readUnicodeClass(CharInspector it) throws RegexParsingException { + final char current0 = it.peek(0); + if (current0 != '\\') + throw new IllegalStateException(); + it.jump(); + final StringBuilder result = new StringBuilder(); + result.append(current0); + while (it.peek(0) != 0) { + final char ch = it.peek(0); + it.jump(); + result.append(ch); + if (ch == '}') + return result.toString(); + } + throw new RegexParsingException("Unexpected end of data"); + } + + private static String readUnicodeOrOctalEscape(CharInspector it, int nb) throws RegexParsingException { + final char current0 = it.peek(0); + if (current0 != '\\') + throw new IllegalStateException(); + it.jump(); + final StringBuilder result = new StringBuilder(); + result.append(current0); + for (int i = 0; i < nb; i++) { + final char ch = it.peek(0); + if (ch == 0) + throw new RegexParsingException("Unexpected end of data"); + result.append(ch); + it.jump(); + } + return result.toString(); + } + private static String readClass(CharInspector it) { final char current0 = it.peek(0); if (current0 == '.') { @@ -197,6 +244,26 @@ public class RegexExpression { return false; } + private static boolean isStartUnicodeClass(CharInspector it) { + if (it.peek(0) == '\\' && it.peek(1) == 'p' && it.peek(2) == '{') + return true; + if (it.peek(0) == '\\' && it.peek(1) == 'x' && it.peek(2) == '{') + return true; + return false; + } + + private static boolean isStartUnicodeEscape(CharInspector it) { + if (it.peek(0) == '\\' && it.peek(1) == 'u') + return true; + return false; + } + + private static boolean isStartOctalEscape(CharInspector it) { + if (it.peek(0) == '\\' && it.peek(1) == '0') + return true; + return false; + } + private static boolean isSimpleLetter(char ch) { if (ch == '\\' || ch == '.') return false; diff --git a/src/net/sourceforge/plantuml/regexdiagram/RegexParsingException.java b/src/net/sourceforge/plantuml/regexdiagram/RegexParsingException.java new file mode 100644 index 000000000..9fa035d0a --- /dev/null +++ b/src/net/sourceforge/plantuml/regexdiagram/RegexParsingException.java @@ -0,0 +1,44 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2024, Arnaud Roques + * + * Project Info: https://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * https://plantuml.com/patreon (only 1$ per month!) + * https://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.regexdiagram; + +public class RegexParsingException extends Exception { + + public RegexParsingException(String msg) { + super(msg); + } + +} diff --git a/src/net/sourceforge/plantuml/version/Version.java b/src/net/sourceforge/plantuml/version/Version.java index beaab2512..3c0fa9e9e 100644 --- a/src/net/sourceforge/plantuml/version/Version.java +++ b/src/net/sourceforge/plantuml/version/Version.java @@ -46,7 +46,7 @@ public class Version { // Warning, "version" should be the same in gradle.properties and Version.java // Any idea anyone how to magically synchronize those :-) ? - private static final String version = "1.2023.8beta2"; + private static final String version = "1.2023.8"; public static String versionString() { return version; @@ -80,7 +80,7 @@ public class Version { } public static long compileTime() { - return 1683912222767L; + return 1684658280620L; } public static String compileTimeString() {