/* * 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.text.write.tables; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.TreeSet; import org.rf.ide.core.testdata.model.FilePosition; import org.rf.ide.core.testdata.model.RobotFile; import org.rf.ide.core.testdata.text.read.IRobotLineElement; import org.rf.ide.core.testdata.text.read.IRobotTokenType; import org.rf.ide.core.testdata.text.read.RobotLine; import org.rf.ide.core.testdata.text.read.RobotLine.PositionCheck; import org.rf.ide.core.testdata.text.read.recognizer.RobotToken; import org.rf.ide.core.testdata.text.read.recognizer.RobotTokenType; import org.rf.ide.core.testdata.text.read.separators.Separator; import org.rf.ide.core.testdata.text.write.DumperHelper; public class TableElementDumperHelper { public boolean isDirtyAnyDirtyInside(final List<RobotToken> elems) { boolean result = false; for (final RobotToken rt : elems) { if (rt.isDirty()) { result = true; break; } } return result; } public int getLastIndexNotEmptyIndex(final List<RobotToken> elems) { int index = -1; if (elems != null) { final int size = elems.size(); for (int elementIndex = 0; elementIndex < size; elementIndex++) { final RobotToken currentElement = elems.get(elementIndex); if (currentElement.isNotEmpty()) { index = elementIndex; } } } return index; } public Set<Integer> getLineEndPos(final RobotFile model, final List<? extends IRobotLineElement> elems) { final Set<Integer> lof = new TreeSet<>(); final int size = elems.size(); lof.addAll(getLineEndPosByComment(elems)); lof.addAll(getLineEndPosFromModel(model, elems)); lof.add(size - 1); return lof; } private Set<Integer> getLineEndPosByComment(final List<? extends IRobotLineElement> elems) { final Set<Integer> lof = new HashSet<>(); final int size = elems.size(); IRobotTokenType type = null; for (int index = 0; index < size; index++) { final IRobotLineElement el = elems.get(index); final boolean isComment = el.getTypes().contains(RobotTokenType.START_HASH_COMMENT) || el.getTypes().contains(RobotTokenType.COMMENT_CONTINUE); final RobotTokenType newType = isComment ? RobotTokenType.START_HASH_COMMENT : RobotTokenType.UNKNOWN; if (type == null) { type = newType; } else { if (type != newType && !isComment) { lof.add(index - 1); } type = newType; } } return lof; } private Set<Integer> getLineEndPosFromModel(final RobotFile model, final List<? extends IRobotLineElement> elems) { final Set<Integer> lof = new HashSet<>(); final int size = elems.size(); if (size > 1) { final IRobotLineElement prevElement = elems.get(0); for (int tokenId = 1; tokenId < size; tokenId++) { final IRobotLineElement currentElement = elems.get(tokenId); if (isLineContinuedInModel(model, elems, prevElement, currentElement)) { lof.add(tokenId - 1); } } } return lof; } private boolean isLineContinuedInModel(final RobotFile model, final List<? extends IRobotLineElement> elems, final IRobotLineElement prevElement, final IRobotLineElement currentElement) { boolean result = false; final int prevLineNumber = prevElement.getLineNumber(); final int curLineNumber = currentElement.getLineNumber(); if (prevLineNumber != FilePosition.NOT_SET && curLineNumber != FilePosition.NOT_SET && prevLineNumber + 1 == curLineNumber) { final RobotLine currentLine = model.getFileContent().get(curLineNumber - 1); final List<IRobotLineElement> lineElements = currentLine.getLineElements(); boolean wasLineContinue = false; for (final IRobotLineElement rle : lineElements) { if (rle instanceof RobotToken) { if (rle.getTypes().size() == 1 && rle.getTypes().contains(RobotTokenType.PREVIOUS_LINE_CONTINUE)) { wasLineContinue = true; continue; } else if (wasLineContinue) { if (rle == currentElement) { result = true; break; } else { if (elems.indexOf(rle) >= 0) { result = false; break; } } } else { break; } } } } return result; } public Optional<Integer> getFirstBrokenChainPosition(final List<? extends IRobotLineElement> elems, final boolean treatNewAsBrokenChain) { Optional<Integer> o = Optional.empty(); final int size = elems.size(); FilePosition pos = FilePosition.createNotSet(); for (int index = 0; index < size; index++) { final FilePosition current = elems.get(index).getFilePosition(); if (!current.isNotSet()) { if (!pos.isNotSet()) { if (pos.isBefore(current)) { pos = current; } else { o = Optional.of(index); break; } } } else { if (treatNewAsBrokenChain) { o = Optional.of(index); break; } } } return o; } public boolean dumpAsItIs(final DumperHelper dumpHelper, final RobotFile model, final IRobotLineElement startToken, final List<RobotToken> tokens, final List<RobotLine> lines) { final List<IRobotLineElement> dumps = new ArrayList<>(0); final int tokSize = tokens.size(); final int startOffset = startToken.getFilePosition().getOffset(); RobotLine lastLine = null; IRobotLineElement lastToken = startToken; int meatTokens = 0; int offset = startOffset; int currentSize = dumps.size(); boolean removeUpdated = false; if (offset == -1) { offset = tokens.get(0).getFilePosition().getOffset(); } if (isLastElementTheSameAsFirstInTokensToDump(lastToken, tokens) || isAssigmentAfterCurrentToken(tokens.get(0), lastToken)) { // dump token before this method meatTokens++; } while (meatTokens < tokSize) { final Optional<Integer> line = model.getRobotLineIndexBy(offset); if (!line.isPresent()) { removeUpdated = true; break; } lastLine = model.getFileContent().get(line.get()); final List<IRobotLineElement> lastToks = lastLine.getLineElements(); final int lastToksSize = lastToks.size(); int elementPositionInLine; if (offset != startOffset) { final Optional<Integer> elemPosInLine = lastLine.getElementPositionInLine(offset, PositionCheck.STARTS); if (elemPosInLine.isPresent()) { elementPositionInLine = elemPosInLine.get(); } else { elementPositionInLine = -1; } } else { final Optional<Integer> elemPosInLine = lastLine.getElementPositionInLine(lastToken); if (elemPosInLine.isPresent()) { elementPositionInLine = lastLine.getElementPositionInLine(lastToken).get() + 1; } else { elementPositionInLine = -1; } } currentSize = dumps.size(); removeUpdated = false; for (int i = elementPositionInLine; elementPositionInLine > -1 && i < lastToksSize; i++) { final IRobotLineElement e = lastToks.get(i); lastToken = e; if (e instanceof Separator) { dumps.add(e); } else { final RobotToken rt = (RobotToken) e; if (tokSize > meatTokens && rt == tokens.get(meatTokens)) { dumps.add(rt); meatTokens++; } else { if (rt.getTypes().contains(RobotTokenType.PRETTY_ALIGN_SPACE) || rt.getTypes().contains(RobotTokenType.ASSIGNMENT)) { dumps.add(rt); } else if (isContinue(dumpHelper, dumps, rt)) { dumps.add(rt); } else if (startToken == rt) { continue; } else { removeUpdated = true; return false; // break; } } } } if (removeUpdated) { final int dumpSize = dumps.size(); if (!dumps.isEmpty()) { for (int i = 0; i < dumpSize - currentSize; i++) { dumps.remove(dumps.size() - 1); } } meatTokens = tokSize; break; } else { lastToken = lastLine.getEndOfLine(); dumps.add(lastLine.getEndOfLine()); final IRobotLineElement end = dumps.get(dumps.size() - 1); offset = end.getStartOffset() + (end.getEndColumn() - end.getStartColumn()); } } if (lastLine != null && lastToken != null && !dumpHelper.isEndOfLine(lastToken)) { final List<IRobotLineElement> lineElements = lastLine.getLineElements(); final int size = lineElements.size(); final int tokPosInLine = lastLine.getElementPositionInLine(lastToken).get(); currentSize = dumps.size(); removeUpdated = false; for (int index = tokPosInLine + 1; index < size; index++) { final IRobotLineElement elem = lineElements.get(index); if (elem instanceof Separator) { dumps.add(elem); } else { removeUpdated = true; } } if (removeUpdated) { final int dumpSize = dumps.size(); if (!dumps.isEmpty()) { for (int i = 0; i < dumpSize - currentSize; i++) { dumps.remove(dumps.size() - 1); } } } else { if (lastLine.getEndOfLine() != lastToken) { dumps.add(lastLine.getEndOfLine()); } } } for (final IRobotLineElement rle : dumps) { dumpHelper.getDumpLineUpdater().updateLine(model, lines, rle); } return (dumps.size() > 0); } private boolean isAssigmentAfterCurrentToken(final IRobotLineElement prevToken, final IRobotLineElement currentToken) { return (!prevToken.getFilePosition().isNotSet() && prevToken.getFilePosition().getOffset() + prevToken.getText().length() == currentToken.getFilePosition().getOffset() && currentToken.getTypes().contains(RobotTokenType.ASSIGNMENT)); } private boolean isLastElementTheSameAsFirstInTokensToDump(final IRobotLineElement startToken, final List<RobotToken> tokens) { return (!tokens.isEmpty() && tokens.get(0) == startToken); } private boolean isContinue(final DumperHelper dumpHelper, final List<IRobotLineElement> dumps, final IRobotLineElement l) { boolean result = false; if (l.getTypes().contains(RobotTokenType.PREVIOUS_LINE_CONTINUE)) { if (dumps.isEmpty()) { result = true; } else { final int dumpsSize = dumps.size(); boolean sepsOnly = true; for (int dumpId = dumpsSize - 1; dumpId >= 0; dumpId--) { final IRobotLineElement rle = dumps.get(dumpId); if (rle instanceof Separator) { continue; } else if (dumpHelper.isEndOfLine(rle)) { break; } else { sepsOnly = false; break; } } result = sepsOnly; } } return result; } }