<commit_before>package bndtools.refactor;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceProxy;
import org.eclipse.core.resources.IResourceProxyVisitor;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.internal.corext.refactoring.rename.RenamePackageProcessor;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.CompositeChange;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.core.refactoring.TextChange;
import org.eclipse.ltk.core.refactoring.TextFileChange;
import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
import org.eclipse.ltk.core.refactoring.participants.RenameArguments;
import org.eclipse.ltk.core.refactoring.participants.RenameParticipant;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.ReplaceEdit;
import org.eclipse.text.edits.TextEdit;

import bndtools.Plugin;
import bndtools.utils.FileUtils;

public class PkgRenameParticipant extends RenameParticipant {
    private IPackageFragment pkgFragment;
    private String changeTitle = null;

    @Override
    protected boolean initialize(Object element) {
        this.pkgFragment = (IPackageFragment) element;
        RenameArguments args = getArguments();

        StringBuilder sb = new StringBuilder(256);
        sb.append("Bndtools: rename package '");
        sb.append(pkgFragment.getElementName());
        sb.append("' ");
        if (((RenamePackageProcessor) this.getProcessor()).getRenameSubpackages())
            sb.append("and subpackages ");
        sb.append("to '");
        sb.append(args.getNewName());
        sb.append("'");
        changeTitle = sb.toString();

        return true;
    }

    @Override
    public String getName() {
        return "Bndtools Package Rename Participant";
    }

    @Override
    public RefactoringStatus checkConditions(IProgressMonitor pm, CheckConditionsContext context) throws OperationCanceledException {
        return new RefactoringStatus();
    }

    private static final String grammarSeparator = "[\\s,\"';]";

    @Override
    public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
        final Map<IFile, TextChange> fileChanges = new HashMap<IFile, TextChange>();

        IResourceProxyVisitor visitor = new IResourceProxyVisitor() {
            public boolean visit(IResourceProxy proxy) throws CoreException {
                if ((proxy.getType() == IResource.FOLDER) || (proxy.getType() == IResource.PROJECT)) {
                    return true;
                }

                if (!((proxy.getType() == IResource.FILE) && proxy.getName().toLowerCase().endsWith(".bnd"))) {
                    return false;
                }

                /* we're dealing with a *.bnd file */

                /* get the proxied file */
                IFile resource = (IFile) proxy.requestResource();

                /* read the file as a single string */
                String bndFileText = null;
                try {
                    bndFileText = FileUtils.readFully(resource).get();
                } catch (Exception e) {
                    String str = "Could not read file " + proxy.getName();
                    Plugin.logError(str, e);
                    throw new OperationCanceledException(str);
                }

                /*
                 * get the previous change for this file if it exists, or
                 * otherwise create a new change for it
                 */
                TextChange fileChange = getTextChange(resource);
                TextEdit rootEdit = null;
                if (fileChange == null) {
                    fileChange = new TextFileChange(proxy.getName(), resource);
                    rootEdit = new MultiTextEdit();
                    fileChange.setEdit(rootEdit);
                    fileChanges.put(resource, fileChange);
                } else {
                    rootEdit = fileChange.getEdit();
                }

                final String oldName = pkgFragment.getElementName();
                final String newName = getArguments().getNewName();
                final Pattern pattern = Pattern.compile(
                /* match start boundary */"(^|" + grammarSeparator + ")" +
                /* match itself / package name */"(" + Pattern.quote(oldName) + ")" +
                /* match end boundary */"(" + grammarSeparator + "|" + Pattern.quote(".*") + "|" + Pattern.quote("\\") + "|$)");

                /* see if there are matches, if not: return */
                Matcher matcher = pattern.matcher(bndFileText);
                if (!matcher.find()) {
                    return false;
                }

                /* find all matches to replace and add them to the root edit */
                matcher.reset();
                while (matcher.find()) {
                    rootEdit.addChild(new ReplaceEdit(matcher.start(2), matcher.group(2).length(), newName));
                }

                return false;
            }
        };

        /* determine which projects have to be visited */
        Set<IProject> projectsToVisit = new HashSet<IProject>();
        projectsToVisit.add(pkgFragment.getResource().getProject());
        for (IProject projectToVisit : pkgFragment.getResource().getProject().getReferencingProjects()) {
            projectsToVisit.add(projectToVisit);
        }
        for (IProject projectToVisit : pkgFragment.getResource().getProject().getReferencedProjects()) {
            projectsToVisit.add(projectToVisit);
        }

        /* visit the projects */
        for (IProject projectToVisit : projectsToVisit) {
            projectToVisit.accept(visitor, IContainer.NONE);
        }
<commit_msg>PkgRenameParticipant: convert to a shared participant (more efficient)<commit_after>package bndtools.refactor;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceProxy;
import org.eclipse.core.resources.IResourceProxyVisitor;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.internal.corext.refactoring.rename.RenamePackageProcessor;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.CompositeChange;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.core.refactoring.TextChange;
import org.eclipse.ltk.core.refactoring.TextFileChange;
import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
import org.eclipse.ltk.core.refactoring.participants.ISharableParticipant;
import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments;
import org.eclipse.ltk.core.refactoring.participants.RenameArguments;
import org.eclipse.ltk.core.refactoring.participants.RenameParticipant;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.ReplaceEdit;
import org.eclipse.text.edits.TextEdit;

import bndtools.Plugin;
import bndtools.utils.FileUtils;

public class PkgRenameParticipant extends RenameParticipant implements ISharableParticipant {
    private Map<IPackageFragment, RenameArguments> pkgFragments = new HashMap<IPackageFragment, RenameArguments>();
    private String changeTitle = null;

    @Override
    protected boolean initialize(Object element) {
        IPackageFragment pkgFragment = (IPackageFragment) element;
        RenameArguments args = getArguments();
        pkgFragments.put(pkgFragment, args);

        StringBuilder sb = new StringBuilder(256);
        sb.append("Bndtools: rename package '");
        sb.append(pkgFragment.getElementName());
        sb.append("' ");
        if (((RenamePackageProcessor) this.getProcessor()).getRenameSubpackages())
            sb.append("and subpackages ");
        sb.append("to '");
        sb.append(args.getNewName());
        sb.append("'");
        changeTitle = sb.toString();

        return true;
    }

    public void addElement(Object element, RefactoringArguments arguments) {
        this.pkgFragments.put((IPackageFragment) element, (RenameArguments) arguments);
    }

    @Override
    public String getName() {
        return "Bndtools Package Rename Participant";
    }

    @Override
    public RefactoringStatus checkConditions(IProgressMonitor pm, CheckConditionsContext context) throws OperationCanceledException {
        return new RefactoringStatus();
    }

    private static final String grammarSeparator = "[\\s,\"';]";

    @Override
    public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
        final Map<IFile, TextChange> fileChanges = new HashMap<IFile, TextChange>();

        IResourceProxyVisitor visitor = new IResourceProxyVisitor() {
            public boolean visit(IResourceProxy proxy) throws CoreException {
                if ((proxy.getType() == IResource.FOLDER) || (proxy.getType() == IResource.PROJECT)) {
                    return true;
                }

                if (!((proxy.getType() == IResource.FILE) && proxy.getName().toLowerCase().endsWith(".bnd"))) {
                    return false;
                }

                /* we're dealing with a *.bnd file */

                /* get the proxied file */
                IFile resource = (IFile) proxy.requestResource();

                /* read the file as a single string */
                String bndFileText = null;
                try {
                    bndFileText = FileUtils.readFully(resource).get();
                } catch (Exception e) {
                    String str = "Could not read file " + proxy.getName();
                    Plugin.logError(str, e);
                    throw new OperationCanceledException(str);
                }

                /*
                 * get the previous change for this file if it exists, or
                 * otherwise create a new change for it, but do not store it
                 * yet: wait until we know if there are actually changes in the
                 * file
                 */
                TextChange fileChange = getTextChange(resource);
                final boolean fileChangeIsNew = (fileChange == null);
                if (fileChange == null) {
                    fileChange = new TextFileChange(proxy.getName(), resource);
                    fileChange.setEdit(new MultiTextEdit());
                }
                TextEdit rootEdit = fileChange.getEdit();

                /* loop over all renames to perform */
                for (Map.Entry<IPackageFragment, RenameArguments> entry : pkgFragments.entrySet()) {
                    IPackageFragment pkgFragment = entry.getKey();
                    RenameArguments arguments = entry.getValue();

                    final String oldName = pkgFragment.getElementName();
                    final String newName = arguments.getNewName();
                    final Pattern pattern = Pattern.compile(
                    /* match start boundary */"(^|" + grammarSeparator + ")" +
                    /* match itself / package name */"(" + Pattern.quote(oldName) + ")" +
                    /* match end boundary */"(" + grammarSeparator + "|" + Pattern.quote(".*") + "|" + Pattern.quote("\\") + "|$)");

                    /* see if there are matches, if not: return */
                    Matcher matcher = pattern.matcher(bndFileText);
                    if (!matcher.find()) {
                        continue;
                    }

                    /* find all matches to replace and add them to the root edit */
                    matcher.reset();
                    while (matcher.find()) {
                        rootEdit.addChild(new ReplaceEdit(matcher.start(2), matcher.group(2).length(), newName));
                    }
                }

                /*
                 * only store the changes when no changes were stored before for
                 * this file and when there are actually changes.
                 */
                if (fileChangeIsNew && rootEdit.hasChildren()) {
                    fileChanges.put(resource, fileChange);
                }

                return false;
            }
        };

        /* determine which projects have to be visited */
        Set<IProject> projectsToVisit = new HashSet<IProject>();
        for (IPackageFragment pkgFragment : pkgFragments.keySet()) {
            projectsToVisit.add(pkgFragment.getResource().getProject());
            for (IProject projectToVisit : pkgFragment.getResource().getProject().getReferencingProjects()) {
                projectsToVisit.add(projectToVisit);
            }
            for (IProject projectToVisit : pkgFragment.getResource().getProject().getReferencedProjects()) {
                projectsToVisit.add(projectToVisit);
            }
        }

        /* visit the projects */
        for (IProject projectToVisit : projectsToVisit) {
            projectToVisit.accept(visitor, IContainer.NONE);
        }

{'fraction_non_alphanumeric': 0.1028987597346409, 'fraction_numerical': 0.0007210845111047015, 'mean_word_length': 2.300571156592099, 'pattern_counts': {'":': 0, '<': 14, '<?xml version=': 0, '>': 14, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5655907', 'n_tokens_mistral': 3672, 'n_tokens_neox': 3470, 'n_words': 784}