From 80217d8c900916ae8fa023478299ee0c9c78fbb2 Mon Sep 17 00:00:00 2001 From: Arnaud Roques Date: Tue, 13 Dec 2022 18:30:41 +0100 Subject: [PATCH] wip --- .../sourceforge/plantuml/PSystemBuilder.java | 3 +- .../sourceforge/plantuml/ScaleProtected.java | 8 +- .../sourceforge/plantuml/UmlDiagramType.java | 5 +- .../plantuml/command/CommandScale.java | 8 +- .../plantuml/core/DiagramType.java | 5 +- .../plantuml/creole/atom/AtomImg.java | 53 ++-- .../plantuml/ebnf/CharIterator.java | 2 +- .../plantuml/ebnf/CharIteratorImpl.java | 2 +- .../plantuml/ebnf/ETileAlternation.java | 1 + .../sourceforge/plantuml/ebnf/ETileBox.java | 8 + .../plantuml/ebnf/ETileConcatenation.java | 8 + .../plantuml/ebnf/EbnfExpression.java | 4 - .../plantuml/eggs/PSystemWelcome.java | 4 +- .../plantuml/hcl/HclDiagramFactory.java | 2 +- .../sourceforge/plantuml/hcl/HclParser.java | 1 + .../plantuml/jsondiagram/JsonDiagram.java | 10 +- .../jsondiagram/JsonDiagramFactory.java | 2 +- .../plantuml/jsondiagram/StyleExtractor.java | 44 ++- .../regex/CommandRegexfSingleLine.java | 72 +++++ .../plantuml/regex/PSystemRegex.java | 284 ++++++++++++++++++ .../plantuml/regex/PSystemRegexFactory.java | 69 +++++ .../sourceforge/plantuml/regex/ReToken.java | 61 ++++ .../plantuml/regex/ReTokenType.java | 65 ++++ .../plantuml/regex/RegexExpression.java | 223 ++++++++++++++ .../plantuml/regex/ShuntingYard.java | 108 +++++++ src/net/sourceforge/plantuml/style/SName.java | 1 + .../sourceforge/plantuml/svg/SvgGraphics.java | 7 +- .../sourceforge/plantuml/version/Version.java | 2 +- .../plantuml/wbs/CommandWBSLink.java | 34 ++- .../sourceforge/plantuml/wbs/WBSDiagram.java | 21 +- src/net/sourceforge/plantuml/wbs/WBSLink.java | 10 +- .../plantuml/yaml/YamlDiagramFactory.java | 2 +- stdlib/c4-abx.repx | Bin 9882 -> 11997 bytes stdlib/c4-dex.repx | Bin 301 -> 564 bytes 34 files changed, 1057 insertions(+), 72 deletions(-) create mode 100644 src/net/sourceforge/plantuml/regex/CommandRegexfSingleLine.java create mode 100644 src/net/sourceforge/plantuml/regex/PSystemRegex.java create mode 100644 src/net/sourceforge/plantuml/regex/PSystemRegexFactory.java create mode 100644 src/net/sourceforge/plantuml/regex/ReToken.java create mode 100644 src/net/sourceforge/plantuml/regex/ReTokenType.java create mode 100644 src/net/sourceforge/plantuml/regex/RegexExpression.java create mode 100644 src/net/sourceforge/plantuml/regex/ShuntingYard.java diff --git a/src/net/sourceforge/plantuml/PSystemBuilder.java b/src/net/sourceforge/plantuml/PSystemBuilder.java index 63280653e..c63aaab93 100644 --- a/src/net/sourceforge/plantuml/PSystemBuilder.java +++ b/src/net/sourceforge/plantuml/PSystemBuilder.java @@ -85,6 +85,7 @@ import net.sourceforge.plantuml.openiconic.PSystemListOpenIconicFactory; import net.sourceforge.plantuml.openiconic.PSystemOpenIconicFactory; import net.sourceforge.plantuml.oregon.PSystemOregonFactory; import net.sourceforge.plantuml.project.GanttDiagramFactory; +import net.sourceforge.plantuml.regex.PSystemRegexFactory; import net.sourceforge.plantuml.salt.PSystemSaltFactory2; import net.sourceforge.plantuml.security.SecurityProfile; import net.sourceforge.plantuml.security.SecurityUtils; @@ -212,7 +213,6 @@ public class PSystemBuilder { factories.add(new PSystemXearthFactory()); } factories.add(new GanttDiagramFactory(DiagramType.GANTT)); - // factories.add(new GanttDiagramFactory(DiagramType.UML)); GanttDiagramFactory.clearCache(); factories.add(new FlowDiagramFactory()); // factories.add(new PSystemTreeFactory(DiagramType.JUNGLE)); @@ -227,6 +227,7 @@ public class PSystemBuilder { factories.add(new YamlDiagramFactory()); factories.add(new HclDiagramFactory()); factories.add(new PSystemEbnfFactory()); + factories.add(new PSystemRegexFactory()); } private boolean isOk(Diagram ps) { diff --git a/src/net/sourceforge/plantuml/ScaleProtected.java b/src/net/sourceforge/plantuml/ScaleProtected.java index 6a30af096..7fc5b4469 100644 --- a/src/net/sourceforge/plantuml/ScaleProtected.java +++ b/src/net/sourceforge/plantuml/ScaleProtected.java @@ -41,12 +41,12 @@ abstract class ScaleProtected implements Scale { final public double getScale(double width, double height) { final double result = getScaleInternal(width, height); - if (result <= 0) { + if (result <= 0) return 1; - } - if (result > 4) { + + if (result > 4) return 4; - } + return result; } diff --git a/src/net/sourceforge/plantuml/UmlDiagramType.java b/src/net/sourceforge/plantuml/UmlDiagramType.java index 092916032..a5934810e 100644 --- a/src/net/sourceforge/plantuml/UmlDiagramType.java +++ b/src/net/sourceforge/plantuml/UmlDiagramType.java @@ -39,7 +39,7 @@ import net.sourceforge.plantuml.style.SName; public enum UmlDiagramType { SEQUENCE, STATE, CLASS, OBJECT, ACTIVITY, DESCRIPTION, COMPOSITE, FLOW, TIMING, BPM, NWDIAG, MINDMAP, WBS, WIRE, - HELP, GANTT, SALT, JSON, GIT, BOARD, YAML, HCL, EBNF; + HELP, GANTT, SALT, JSON, GIT, BOARD, YAML, HCL, EBNF, REGEX; public SName getStyleName() { if (this == SEQUENCE) @@ -93,6 +93,9 @@ public enum UmlDiagramType { if (this == EBNF) return SName.ebnf; + if (this == REGEX) + return SName.regex; + return SName.activityDiagram; } } diff --git a/src/net/sourceforge/plantuml/command/CommandScale.java b/src/net/sourceforge/plantuml/command/CommandScale.java index bf04fb1f5..0dd5a7399 100644 --- a/src/net/sourceforge/plantuml/command/CommandScale.java +++ b/src/net/sourceforge/plantuml/command/CommandScale.java @@ -67,14 +67,14 @@ public class CommandScale extends SingleLineCommand2 { @Override protected CommandExecutionResult executeArg(AbstractPSystem diagram, LineLocation location, RegexResult arg) { double scale = Double.parseDouble(arg.get("SCALE", 0)); - if (scale == 0) { + if (scale == 0) return CommandExecutionResult.error("Scale cannot be zero"); - } + if (arg.get("DIV", 0) != null) { final double div = Double.parseDouble(arg.get("DIV", 0)); - if (div == 0) { + if (div == 0) return CommandExecutionResult.error("Scale cannot be zero"); - } + scale /= div; } diagram.setScale(new ScaleSimple(scale)); diff --git a/src/net/sourceforge/plantuml/core/DiagramType.java b/src/net/sourceforge/plantuml/core/DiagramType.java index d9c7d7640..59ecd96f8 100644 --- a/src/net/sourceforge/plantuml/core/DiagramType.java +++ b/src/net/sourceforge/plantuml/core/DiagramType.java @@ -39,7 +39,7 @@ import net.sourceforge.plantuml.utils.StartUtils; public enum DiagramType { UML, BPM, DITAA, DOT, PROJECT, JCCKIT, SALT, FLOW, CREOLE, JUNGLE, CUTE, MATH, LATEX, DEFINITION, GANTT, NW, - MINDMAP, WBS, WIRE, JSON, GIT, BOARD, YAML, HCL, EBNF, UNKNOWN; + MINDMAP, WBS, WIRE, JSON, GIT, BOARD, YAML, HCL, EBNF, REGEX, UNKNOWN; static public DiagramType getTypeFromArobaseStart(String s) { s = s.toLowerCase(); @@ -121,6 +121,9 @@ public enum DiagramType { if (StartUtils.startsWithSymbolAnd("startebnf", s)) return EBNF; + if (StartUtils.startsWithSymbolAnd("startregex", s)) + return REGEX; + return UNKNOWN; } } diff --git a/src/net/sourceforge/plantuml/creole/atom/AtomImg.java b/src/net/sourceforge/plantuml/creole/atom/AtomImg.java index 028e9fb8b..89d555317 100644 --- a/src/net/sourceforge/plantuml/creole/atom/AtomImg.java +++ b/src/net/sourceforge/plantuml/creole/atom/AtomImg.java @@ -84,9 +84,9 @@ public class AtomImg extends AbstractAtom implements Atom { public static Atom createQrcode(String flash, double scale) { final FlashCodeUtils utils = FlashCodeFactory.getFlashCodeUtils(); BufferedImage im = utils.exportFlashcode(flash, Color.BLACK, Color.WHITE); - if (im == null) { + if (im == null) im = new BufferedImage(10, 10, BufferedImage.TYPE_INT_RGB); - } + return new AtomImg( new UImage(new PixelImage(im, AffineTransformType.TYPE_NEAREST_NEIGHBOR)).scale(scale).getImage(1), 1, null, null); @@ -120,38 +120,38 @@ public class AtomImg extends AbstractAtom implements Atom { try { // Check if valid URL if (src.startsWith("http:") || src.startsWith("https:")) { - if (src.endsWith(".svg")) + if (src.endsWith(".svg")) return buildSvgFromUrl(src, fc, SURL.create(src), scale, url); - + return buildRasterFromUrl(src, fc, SURL.create(src), scale, url); } final SFile f = FileSystem.getInstance().getFile(src); if (f.exists() == false) { - if (SecurityUtils.getSecurityProfile() == SecurityProfile.UNSECURE) + if (SecurityUtils.getSecurityProfile() == SecurityProfile.UNSECURE) return AtomTextUtils.createLegacy("(File not found: " + f.getPrintablePath() + ")", fc); - + return AtomTextUtils.createLegacy("(Cannot decode)", fc); } if (f.getName().endsWith(".svg")) { final String tmp = FileUtils.readSvg(f); - if (tmp == null) + if (tmp == null) return AtomTextUtils.createLegacy("(Cannot decode)", fc); - + return new AtomImgSvg(new TileImageSvg(tmp, scale)); } final BufferedImage read = f.readRasterImageFromFile(); if (read == null) { - if (SecurityUtils.getSecurityProfile() == SecurityProfile.UNSECURE) + if (SecurityUtils.getSecurityProfile() == SecurityProfile.UNSECURE) return AtomTextUtils.createLegacy("(Cannot decode: " + f.getPrintablePath() + ")", fc); - + return AtomTextUtils.createLegacy("(Cannot decode)", fc); } return new AtomImg(f.readRasterImageFromFile(), scale, url, src); } catch (IOException e) { Logme.error(e); - if (SecurityUtils.getSecurityProfile() == SecurityProfile.UNSECURE) + if (SecurityUtils.getSecurityProfile() == SecurityProfile.UNSECURE) return AtomTextUtils.createLegacy("ERROR " + e.toString(), fc); - + return AtomTextUtils.createLegacy("ERROR", fc); } } @@ -159,33 +159,33 @@ public class AtomImg extends AbstractAtom implements Atom { private static Atom buildRasterFromData(String source, final FontConfiguration fc, final byte[] data, double scale, Url url) throws IOException { final BufferedImage read = SImageIO.read(data); - if (read == null) { + if (read == null) return AtomTextUtils.createLegacy("(Cannot decode: " + source + ")", fc); - } + return new AtomImg(read, scale, url, null); } private static Atom buildRasterFromUrl(String text, final FontConfiguration fc, SURL source, double scale, Url url) throws IOException { - if (source == null) { + if (source == null) return AtomTextUtils.createLegacy("(Cannot decode: " + text + ")", fc); - } + final BufferedImage read = source.readRasterImageFromURL(); - if (read == null) { + if (read == null) return AtomTextUtils.createLegacy("(Cannot decode: " + text + ")", fc); - } + return new AtomImg(read, scale, url, "http"); } private static Atom buildSvgFromUrl(String text, final FontConfiguration fc, SURL source, double scale, Url url) throws IOException { - if (source == null) { + if (source == null) return AtomTextUtils.createLegacy("(Cannot decode SVG: " + text + ")", fc); - } + final byte[] read = source.getBytes(); - if (read == null) { + if (read == null) return AtomTextUtils.createLegacy("(Cannot decode SVG: " + text + ")", fc); - } + return new AtomImgSvg(new TileImageSvg(new String(read, UTF_8), scale)); } @@ -200,14 +200,15 @@ public class AtomImg extends AbstractAtom implements Atom { } public void drawU(UGraphic ug) { - if (url != null) { + if (url != null) ug.startUrl(url); - } + ug.draw(new UImage(new PixelImage(image, AffineTransformType.TYPE_BILINEAR)).withRawFileName(rawFileName) .scale(scale)); - if (url != null) { + + if (url != null) ug.closeUrl(); - } + } } diff --git a/src/net/sourceforge/plantuml/ebnf/CharIterator.java b/src/net/sourceforge/plantuml/ebnf/CharIterator.java index 8616f69c8..0c1b4cad4 100644 --- a/src/net/sourceforge/plantuml/ebnf/CharIterator.java +++ b/src/net/sourceforge/plantuml/ebnf/CharIterator.java @@ -35,7 +35,7 @@ */ package net.sourceforge.plantuml.ebnf; -interface CharIterator { +public interface CharIterator { char peek(int ahead); void next(); diff --git a/src/net/sourceforge/plantuml/ebnf/CharIteratorImpl.java b/src/net/sourceforge/plantuml/ebnf/CharIteratorImpl.java index 033cedd81..84049cbb1 100644 --- a/src/net/sourceforge/plantuml/ebnf/CharIteratorImpl.java +++ b/src/net/sourceforge/plantuml/ebnf/CharIteratorImpl.java @@ -37,7 +37,7 @@ package net.sourceforge.plantuml.ebnf; import net.sourceforge.plantuml.command.BlocLines; -class CharIteratorImpl implements CharIterator { +public class CharIteratorImpl implements CharIterator { final private BlocLines data; private int line = 0; diff --git a/src/net/sourceforge/plantuml/ebnf/ETileAlternation.java b/src/net/sourceforge/plantuml/ebnf/ETileAlternation.java index 9af35f688..a906143ff 100644 --- a/src/net/sourceforge/plantuml/ebnf/ETileAlternation.java +++ b/src/net/sourceforge/plantuml/ebnf/ETileAlternation.java @@ -42,6 +42,7 @@ import net.sourceforge.plantuml.awt.geom.XDimension2D; import net.sourceforge.plantuml.graphic.StringBounder; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.UTranslate; +import net.sourceforge.plantuml.ugraphic.color.HColor; public class ETileAlternation extends ETile { diff --git a/src/net/sourceforge/plantuml/ebnf/ETileBox.java b/src/net/sourceforge/plantuml/ebnf/ETileBox.java index c2f425004..d88ac8a39 100644 --- a/src/net/sourceforge/plantuml/ebnf/ETileBox.java +++ b/src/net/sourceforge/plantuml/ebnf/ETileBox.java @@ -68,6 +68,10 @@ public class ETileBox extends ETile { private String commentAbove; private String commentBelow; + public ETileBox mergeWith(ETileBox other) { + return new ETileBox(this.value + other.value, symbol, fc, style, colorSet, skinParam); + } + public ETileBox(String value, Symbol symbol, FontConfiguration fc, Style style, HColorSet colorSet, ISkinParam skinParam) { this.symbol = symbol; @@ -225,4 +229,8 @@ public class ETileBox extends ETile { return value; } + public final Symbol getSymbol() { + return symbol; + } + } diff --git a/src/net/sourceforge/plantuml/ebnf/ETileConcatenation.java b/src/net/sourceforge/plantuml/ebnf/ETileConcatenation.java index 25cb56300..78c0dbb54 100644 --- a/src/net/sourceforge/plantuml/ebnf/ETileConcatenation.java +++ b/src/net/sourceforge/plantuml/ebnf/ETileConcatenation.java @@ -52,6 +52,10 @@ public class ETileConcatenation extends ETile { tiles.add(0, tile); } + public void overideFirst(ETile tile) { + tiles.set(0, tile); + } + @Override public void drawU(UGraphic ug) { final StringBounder stringBounder = ug.getStringBounder(); @@ -104,4 +108,8 @@ public class ETileConcatenation extends ETile { return width; } + public ETile getFirst() { + return tiles.get(0); + } + } diff --git a/src/net/sourceforge/plantuml/ebnf/EbnfExpression.java b/src/net/sourceforge/plantuml/ebnf/EbnfExpression.java index 842916d4f..c63830d20 100644 --- a/src/net/sourceforge/plantuml/ebnf/EbnfExpression.java +++ b/src/net/sourceforge/plantuml/ebnf/EbnfExpression.java @@ -39,15 +39,11 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import net.sourceforge.plantuml.Direction; import net.sourceforge.plantuml.ISkinParam; import net.sourceforge.plantuml.activitydiagram3.ftile.vcompact.FloatingNote; -import net.sourceforge.plantuml.awt.geom.XDimension2D; -import net.sourceforge.plantuml.awt.geom.XPoint2D; import net.sourceforge.plantuml.cucadiagram.Display; import net.sourceforge.plantuml.graphic.FontConfiguration; import net.sourceforge.plantuml.graphic.HorizontalAlignment; -import net.sourceforge.plantuml.graphic.StringBounder; import net.sourceforge.plantuml.graphic.TextBlock; import net.sourceforge.plantuml.graphic.TextBlockUtils; import net.sourceforge.plantuml.style.PName; diff --git a/src/net/sourceforge/plantuml/eggs/PSystemWelcome.java b/src/net/sourceforge/plantuml/eggs/PSystemWelcome.java index e298035d0..fc2400703 100644 --- a/src/net/sourceforge/plantuml/eggs/PSystemWelcome.java +++ b/src/net/sourceforge/plantuml/eggs/PSystemWelcome.java @@ -85,9 +85,9 @@ public class PSystemWelcome extends PlainDiagram { } public TextBlockBackcolored getGraphicStrings() { - if (position != null) { + if (position != null) return GraphicStrings.createBlackOnWhite(strings, PSystemVersion.getPlantumlImage(), position); - } + return GraphicStrings.createBlackOnWhite(strings); } diff --git a/src/net/sourceforge/plantuml/hcl/HclDiagramFactory.java b/src/net/sourceforge/plantuml/hcl/HclDiagramFactory.java index eb71b1bbe..51075f19e 100644 --- a/src/net/sourceforge/plantuml/hcl/HclDiagramFactory.java +++ b/src/net/sourceforge/plantuml/hcl/HclDiagramFactory.java @@ -78,7 +78,7 @@ public class HclDiagramFactory extends PSystemAbstractFactory { } catch (Exception e) { Logme.error(e); } - final JsonDiagram result = new JsonDiagram(source, UmlDiagramType.HCL, data, highlighted); + final JsonDiagram result = new JsonDiagram(source, UmlDiagramType.HCL, data, highlighted, styleExtractor); // if (styleExtractor != null) { // styleExtractor.applyStyles(result.getSkinParam()); // final String title = styleExtractor.getTitle(); diff --git a/src/net/sourceforge/plantuml/hcl/HclParser.java b/src/net/sourceforge/plantuml/hcl/HclParser.java index 564f432fd..673b36aaf 100644 --- a/src/net/sourceforge/plantuml/hcl/HclParser.java +++ b/src/net/sourceforge/plantuml/hcl/HclParser.java @@ -49,6 +49,7 @@ import net.sourceforge.plantuml.json.JsonObject; import net.sourceforge.plantuml.json.JsonString; import net.sourceforge.plantuml.json.JsonValue; +// https://github.com/hashicorp/hcl public class HclParser { private final List terms = new ArrayList(); diff --git a/src/net/sourceforge/plantuml/jsondiagram/JsonDiagram.java b/src/net/sourceforge/plantuml/jsondiagram/JsonDiagram.java index 0835fe90d..ff025ecad 100644 --- a/src/net/sourceforge/plantuml/jsondiagram/JsonDiagram.java +++ b/src/net/sourceforge/plantuml/jsondiagram/JsonDiagram.java @@ -39,6 +39,7 @@ import java.io.OutputStream; import java.util.List; import net.sourceforge.plantuml.FileFormatOption; +import net.sourceforge.plantuml.ScaleSimple; import net.sourceforge.plantuml.TitledDiagram; import net.sourceforge.plantuml.UmlDiagramType; import net.sourceforge.plantuml.awt.geom.XDimension2D; @@ -60,14 +61,18 @@ import net.sourceforge.plantuml.ugraphic.MinMax; import net.sourceforge.plantuml.ugraphic.UFont; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.color.HColor; +import net.sourceforge.plantuml.ugraphic.hand.UGraphicHandwritten; public class JsonDiagram extends TitledDiagram { private final JsonValue root; private final List highlighted; + private final boolean handwritten; - public JsonDiagram(UmlSource source, UmlDiagramType type, JsonValue json, List highlighted) { + public JsonDiagram(UmlSource source, UmlDiagramType type, JsonValue json, List highlighted, + StyleExtractor styleExtractor) { super(source, type, null); + this.handwritten = styleExtractor.isHandwritten(); if (json != null && (json.isString() || json.isBoolean() || json.isNumber())) { this.root = new JsonArray(); ((JsonArray) this.root).add(json); @@ -75,6 +80,7 @@ public class JsonDiagram extends TitledDiagram { this.root = json; } this.highlighted = highlighted; + setScale(new ScaleSimple(styleExtractor.getScale())); } public DiagramDescription getDescription() { @@ -95,6 +101,8 @@ public class JsonDiagram extends TitledDiagram { } private void drawInternal(UGraphic ug) { + if (handwritten) + ug = new UGraphicHandwritten(ug); if (root == null) { final Display display = Display .getWithNewlines("Your data does not sound like " + getUmlDiagramType() + " data"); diff --git a/src/net/sourceforge/plantuml/jsondiagram/JsonDiagramFactory.java b/src/net/sourceforge/plantuml/jsondiagram/JsonDiagramFactory.java index a2d93ddf5..b24ead5ca 100644 --- a/src/net/sourceforge/plantuml/jsondiagram/JsonDiagramFactory.java +++ b/src/net/sourceforge/plantuml/jsondiagram/JsonDiagramFactory.java @@ -85,7 +85,7 @@ public class JsonDiagramFactory extends PSystemAbstractFactory { } catch (ParseException e) { json = null; } - final JsonDiagram result = new JsonDiagram(source, UmlDiagramType.JSON, json, highlighted); + final JsonDiagram result = new JsonDiagram(source, UmlDiagramType.JSON, json, highlighted, styleExtractor); if (styleExtractor != null) styleExtractor.applyStyles(result.getSkinParam()); diff --git a/src/net/sourceforge/plantuml/jsondiagram/StyleExtractor.java b/src/net/sourceforge/plantuml/jsondiagram/StyleExtractor.java index d31ae9c37..5a40cb272 100644 --- a/src/net/sourceforge/plantuml/jsondiagram/StyleExtractor.java +++ b/src/net/sourceforge/plantuml/jsondiagram/StyleExtractor.java @@ -51,27 +51,42 @@ public class StyleExtractor { private final List list = new ArrayList<>(); private final List style = new ArrayList<>(); private String title = null; + private boolean handwritten = false; + private double scale = 1; public StyleExtractor(Iterator data) { while (data.hasNext()) { StringLocated line = data.next(); - if (startStyle(line)) { + final String s = line.getString().trim(); + if (s.length() == 0) + continue; + if (startStyle(s)) { while (data.hasNext()) { style.add(line); if (endStyle(line)) break; line = data.next(); } - } else if (line.getString().trim().startsWith("!assume ")) { + } else if (list.size() >= 1 && s.startsWith("!assume ")) { // Ignore - } else if (line.getString().trim().startsWith("!pragma ")) { + } else if (list.size() >= 1 && s.startsWith("!pragma ")) { // Ignore - } else if (line.getString().trim().startsWith("hide ")) { + } else if (list.size() >= 1 && s.startsWith("hide ")) { // Ignore - } else if (line.getString().trim().startsWith("title ")) { - this.title = line.getString().trim().substring("title ".length()).trim(); - } else if (line.getString().trim().startsWith("skinparam ")) { - if (line.getString().trim().contains("{")) { + } else if (list.size() >= 1 && s.startsWith("scale ")) { + // Ignore + try { + final double v = Double.parseDouble(s.replaceAll("\\D", "")); + if (v > 0) + scale = v; + } catch (Exception e) { + } + } else if (list.size() >= 1 && s.startsWith("title ")) { + this.title = s.substring("title ".length()).trim(); + } else if (list.size() >= 1 && s.startsWith("skinparam ")) { + if (s.contains("handwritten") && s.contains("true")) + handwritten = true; + if (s.contains("{")) { while (data.hasNext()) { if (line.getString().trim().equals("}")) break; @@ -82,10 +97,11 @@ public class StyleExtractor { list.add(line.getString()); } } + } - private boolean startStyle(StringLocated line) { - return line.getString().trim().equals("