/******************************************************************************* * Copyright (c) 2009-2015 CWI * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * * Jurgen J. Vinju - Jurgen.Vinju@cwi.nl - CWI * * Arnold Lankamp - Arnold.Lankamp@cwi.nl *******************************************************************************/ package org.rascalmpl.eclipse.nature; import java.util.Collections; import java.util.HashSet; import java.util.Set; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceChangeEvent; import org.eclipse.core.resources.IResourceChangeListener; import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.resources.IResourceDeltaVisitor; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.rascalmpl.eclipse.IRascalResources; import org.rascalmpl.eclipse.util.ResourcesToModules; import org.rascalmpl.interpreter.Evaluator; import org.rascalmpl.uri.URIUtil; public class ModuleReloader{ private final RascalModuleChangeListener moduleChangeListener; private final RascalModuleUpdateListener resourceChangeListener; private boolean destroyed; public ModuleReloader(IProject project, Evaluator eval, IWarningHandler warnings) { super(); moduleChangeListener = new RascalModuleChangeListener(eval, project, warnings); resourceChangeListener = new RascalModuleUpdateListener(moduleChangeListener); ResourcesPlugin.getWorkspace().addResourceChangeListener(resourceChangeListener); } public void updateModules(IProgressMonitor monitor, IWarningHandler handler, Set<String> ignored){ moduleChangeListener.updateModules(monitor, handler, ignored); } public synchronized void destroy(){ if(destroyed) return; ResourcesPlugin.getWorkspace().removeResourceChangeListener(resourceChangeListener); destroyed = true; } protected void finalize(){ destroy(); } public static class RascalModuleUpdateListener implements IResourceChangeListener { private IModuleChangedListener interpreter; public RascalModuleUpdateListener(IModuleChangedListener interpreter) { this.interpreter = interpreter; } public void resourceChanged(IResourceChangeEvent event) { if(event.getDelta() == null) return; IResourceDelta[] deltas = event.getDelta().getAffectedChildren(); try { for (IResourceDelta d : deltas) { d.accept(new IResourceDeltaVisitor() { public boolean visit(IResourceDelta delta) throws CoreException { IResource resource = delta.getResource(); if (resource instanceof IFile) { IPath path = resource.getLocation(); if (path != null && path.getFileExtension() != null && path.getFileExtension().equals(IRascalResources.RASCAL_EXT)) { switch (delta.getKind()) { case IResourceDelta.OPEN: break; case IResourceDelta.ADDED: break; case IResourceDelta.CHANGED: if (delta.getFlags() != IResourceDelta.MARKERS) { // only if its not just the markers notify(path); } break; case IResourceDelta.REMOVED: break; } } return false; } return true; } private void notify(IPath path) { IFile file = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(path); String module = ResourcesToModules.moduleFromFile(file); if (module != null) { interpreter.moduleChanged(module); } } }); } } catch (CoreException e) { e.printStackTrace(); } } } private static class RascalModuleChangeListener implements IModuleChangedListener{ private final Set<String> dirtyModules = new HashSet<String>(); private final Evaluator eval; private final IWarningHandler warnings; public RascalModuleChangeListener(Evaluator eval, IProject project, IWarningHandler warnings) { super(); this.eval = eval; this.warnings = warnings; } public void moduleChanged(String name) { synchronized (dirtyModules) { dirtyModules.add(name); } } public void updateModules(IProgressMonitor monitor, IWarningHandler handler, Set<String> ignored) { synchronized (dirtyModules) { synchronized(eval){ Set<String> todo = new HashSet<>(); todo.addAll(dirtyModules); boolean changed = todo.removeAll(ignored); eval.reloadModules(new RascalMonitor(monitor, handler == null ? warnings : handler) , Collections.unmodifiableSet(todo), URIUtil.rootLocation("console")); dirtyModules.clear(); if (changed) { dirtyModules.addAll(ignored); } } } } } }