/* * Copyright 2016 Nokia Solutions and Networks * Licensed under the Apache License, Version 2.0, * see license.txt file for details. */ package org.rf.ide.core.testdata.model.presenter; import java.io.BufferedReader; import java.io.IOException; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; import org.rf.ide.core.testdata.model.FilePosition; import org.rf.ide.core.testdata.model.IDocumentationHolder; import org.rf.ide.core.testdata.text.read.recognizer.RobotToken; /** * @author wypych */ public class DocumentationServiceHandler { private final static Pattern LINE_CONTINUE = Pattern.compile("^\\n\\s*[...]\\s*$"); /** * Consolidate documentation text to one String for edit. The escaped characters will be * transformed to what will be shown in RF report output. * * @param documentation * @return */ public static String toShowConsolidated(final IDocumentationHolder documentation) { return consolidate(documentation, true); } /** * Consolidate documentation text to one String for edit. The escaped characters will be leave * as they are. * * @param documentation * @return */ public static String toEditConsolidated(final IDocumentationHolder documentation) { return consolidate(documentation, false); } private static String consolidate(final IDocumentationHolder documentation, final boolean shouldUnescapeTokens) { synchronized (documentation) { final StringBuilder text = new StringBuilder(); int currentLineNr = -1; boolean prevNewLine = false; final List<RobotToken> docText = documentation.getDocumentationText(); final int nrOfDocTokens = docText.size(); for (int tokId = 0; tokId < nrOfDocTokens; tokId++) { final RobotToken docPart = docText.get(tokId); final int tokenLineNr = docPart.getLineNumber(); final String tokenText = docPart.getText(); if (tokId == 0) { if (tokenText.trim().equals("...") || tokenText.trim().equals("\n...")) { currentLineNr = tokenLineNr; prevNewLine = true; continue; } else if (tokenLineNr == documentation.getBeginPosition().getLine()) { currentLineNr = tokenLineNr; } else { currentLineNr = documentation.getBeginPosition().getLine(); } } if (currentLineNr < tokenLineNr && tokenText.trim().isEmpty()) { continue; } else if (LINE_CONTINUE.matcher(tokenText).find() || tokenText.equals("\n...") || (currentLineNr < tokenLineNr && tokenText.trim().equals("..."))) { text.append("\n"); currentLineNr = tokenLineNr; prevNewLine = true; continue; } else if (currentLineNr != tokenLineNr && tokenLineNr != FilePosition.NOT_SET) { text.append("\n"); currentLineNr = tokenLineNr; } else if (tokId > 0 && text.length() > 0) { if (!prevNewLine && !tokenText.isEmpty()) { text.append(" "); } } prevNewLine = false; if (shouldUnescapeTokens) { text.append(unescape(tokenText)); } else { text.append(tokenText); } } return text.toString(); } } private static String unescape(final String text) { String newText = text; if (text != null) { StringBuilder unescape = new StringBuilder(""); int nrOfEscape = 0; char[] chars = text.toCharArray(); for (char c : chars) { if (c == '\\') { unescape.append(c); nrOfEscape++; } else { if (nrOfEscape > 0) { if (nrOfEscape == 1) { if (c == 'n') { c = '\n'; } else if (c == 't') { c = '\t'; } else if (c == 'r') { c = '\r'; } } unescape.setCharAt(unescape.length() - 1, c); } else { unescape.append(c); } nrOfEscape = 0; } } if (nrOfEscape > 0) { newText = unescape.substring(0, unescape.length() - 1); } else { newText = unescape.toString(); } } return newText; } /** * Updates documentation in model. * * @param documentation * @param newDocumentation */ public static void update(final IDocumentationHolder documentation, final String newDocumentation) { synchronized (documentation) { if (newDocumentation == null || newDocumentation.isEmpty()) { documentation.clearDocumentation(); return; } if (!toEditConsolidated(documentation).equals(newDocumentation)) { documentation.clearDocumentation(); final List<String> lines = splitToLines(newDocumentation); final int numberOfLines = lines.size(); if (numberOfLines > 0) { RobotToken tok = new RobotToken(); tok.setText(smartTrimmedRight(lines.get(0))); documentation.addDocumentationText(tok); for (int lineNr = 1; lineNr < numberOfLines; lineNr++) { RobotToken newLine = new RobotToken(); newLine.setText("\n..."); documentation.addDocumentationText(newLine); final String lineText = lines.get(lineNr); if (!lineText.isEmpty()) { RobotToken docPart = new RobotToken(); docPart.setText(smartTrimmedRight(lineText)); documentation.addDocumentationText(docPart); } } } } } } private static String smartTrimmedRight(final String current) { String t = current; final char[] cArray = current.toCharArray(); final int size = cArray.length; int toCut = 0; int escapeChars = 0; for (int i = size - 1; i >= 0; i--) { final char theChar = cArray[i]; if (theChar == ' ') { toCut++; } else if (theChar == '\\') { escapeChars++; } else { break; } } if (toCut > 0) { if (escapeChars == 1) { t = current.substring(0, size - (toCut - 1)); } else { t = current.substring(0, size - toCut); } } return t; } private static List<String> splitToLines(final String newDocumentation) { final List<String> lines = new ArrayList<>(); try (BufferedReader br = new BufferedReader(new StringReader(newDocumentation))) { String line = null; while ((line = br.readLine()) != null) { lines.add(line); } } catch (IOException e) { // shouldn't happen is not i/o but string } return lines; } }