/* * Copyright 2016 Nokia Solutions and Networks * Licensed under the Apache License, Version 2.0, * see license.txt file for details. */ package org.robotframework.ide.eclipse.main.plugin.refactoring; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.jface.text.Document; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.Position; import org.eclipse.text.edits.DeleteEdit; import org.eclipse.text.edits.ReplaceEdit; import org.eclipse.text.edits.TextEdit; import org.robotframework.ide.eclipse.main.plugin.refactoring.MatchingEngine.MatchAccess; import com.google.common.io.CharStreams; /** * @author Michal Anglart * */ class RedXmlEditsCollector { private final IPath pathBeforeRefactoring; private final Optional<IPath> pathAfterRefactoring; RedXmlEditsCollector(final IPath pathBeforeRefactoring, final Optional<IPath> pathAfterRefactoring) { this.pathBeforeRefactoring = pathBeforeRefactoring; this.pathAfterRefactoring = pathAfterRefactoring; } List<TextEdit> collectEditsInExcludedPaths(final String projectName, final IDocument redXmlDocument) { return collectEditsInExcludedPaths(projectName, new MatchesInDocumentEngine(redXmlDocument)); } List<TextEdit> collectEditsInExcludedPaths(final String projectName, final IFile redXmlFile) { try (BufferedReader fileReader = new BufferedReader(new InputStreamReader(redXmlFile.getContents()))) { final IDocument document = new Document(CharStreams.toString(fileReader)); return collectEditsInExcludedPaths(projectName, new MatchesInDocumentEngine(document)); } catch (IOException | CoreException e) { return new ArrayList<>(); } } private List<TextEdit> collectEditsInExcludedPaths(final String projectName, final MatchingEngine engine) { if (!projectName.equals(pathBeforeRefactoring.segment(0))) { // the change affected something from different project, so excluded paths in the // project of our red.xml files are not affected at all return new ArrayList<>(); } final String toMatch = "\\s*(<excludedPath\\s*path=\"([^\"]*)\"/>)\\s*"; final Pattern toMatchPattern = Pattern.compile(toMatch); final ExcludedPathsMatchesAccess matchesAccess = new ExcludedPathsMatchesAccess(toMatchPattern); engine.searchForMatches(toMatch, matchesAccess); return matchesAccess.getEdits(); } private final class ExcludedPathsMatchesAccess implements MatchAccess { private final Pattern toMatchPattern; private final List<TextEdit> edits; private ExcludedPathsMatchesAccess(final Pattern toMatchPattern) { this.toMatchPattern = toMatchPattern; this.edits = new ArrayList<>(); } public List<TextEdit> getEdits() { return edits; } @Override public void onMatch(final String matchingContent, final Position matchPosition) { final Matcher matcher = toMatchPattern.matcher(matchingContent); matcher.find(); final IPath potentiallyAffectedPath = Path.fromPortableString(matcher.group(2)); final IPath adjustedPathBeforeRefactoring = Changes .excapeXmlCharacters(pathBeforeRefactoring.removeFirstSegments(1)); if (pathAfterRefactoring.isPresent()) { final IPath adjustedPathAfterRefactoring = Changes .excapeXmlCharacters(pathAfterRefactoring.get().removeFirstSegments(1)); final Optional<IPath> transformedPath = Changes.transformAffectedPath(adjustedPathBeforeRefactoring, adjustedPathAfterRefactoring, potentiallyAffectedPath); if (transformedPath.isPresent()) { final String toInsert = "<excludedPath path=\"" + transformedPath.get().toPortableString() + "\"/>"; final int startShift = matcher.start(1); final int endShift = matchingContent.length() - matcher.end(1) + startShift; edits.add(new ReplaceEdit(matchPosition.getOffset() + startShift, matchPosition.getLength() - endShift, toInsert)); } } else if (adjustedPathBeforeRefactoring.isPrefixOf(potentiallyAffectedPath)) { edits.add(new DeleteEdit(matchPosition.getOffset(), matchPosition.getLength())); } } } }