/** * (c) 2011, Alejandro Serrano * Released under the terms of the EPL. */ package net.sf.eclipsefp.haskell.ui.internal.refactoring.participants; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import net.sf.eclipsefp.haskell.buildwrapper.BuildWrapperPlugin; import net.sf.eclipsefp.haskell.buildwrapper.types.SearchResultLocation; import net.sf.eclipsefp.haskell.buildwrapper.types.UsageResults; import net.sf.eclipsefp.haskell.buildwrapper.usage.UsageAPI; import net.sf.eclipsefp.haskell.core.cabalmodel.CabalSyntax; import net.sf.eclipsefp.haskell.core.cabalmodel.PackageDescription; import net.sf.eclipsefp.haskell.core.cabalmodel.PackageDescriptionLoader; import net.sf.eclipsefp.haskell.core.cabalmodel.PackageDescriptionStanza; import net.sf.eclipsefp.haskell.core.cabalmodel.RealValuePosition; import net.sf.eclipsefp.haskell.core.util.ResourceUtil; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.ui.editors.text.TextFileDocumentProvider; /** * Utilities and shared changes creation for participants. * @author Alejandro Serrano * @author JP Moresmau */ public class Util { public static Set<IPath> getPaths( final IProject project ) { HashSet<IPath> paths = new HashSet<>(); try { IFile cabalF = BuildWrapperPlugin.getCabalFile( project ); PackageDescription pd = PackageDescriptionLoader.load( cabalF ); List<PackageDescriptionStanza> lpds = pd.getStanzas(); for( PackageDescriptionStanza pds: lpds ) { String propList = pds.getProperties().get( CabalSyntax.FIELD_HS_SOURCE_DIRS.getCabalName().toLowerCase() ); propList = propList == null ? "" : propList; List<String> props = PackageDescriptionLoader.parseList( propList ); for (String prop : props) { IPath prefixPath = Path.fromPortableString( prop ); paths.add( prefixPath ); } } } catch (Exception e) { return new HashSet<>(); } return paths; } // public static Set<IPath> getStanzaPaths( final IProject project, // final IFile file ) { // HashSet<IPath> paths = new HashSet<IPath>(); // // try { // IFile cabalF = BuildWrapperPlugin.getCabalFile( project ); // PackageDescription pd = PackageDescriptionLoader.load( cabalF ); // List<PackageDescriptionStanza> lpds = pd.getStanzas(); // for( PackageDescriptionStanza pds: lpds ) { // String propList = pds.getProperties().get( // CabalSyntax.FIELD_HS_SOURCE_DIRS.getCabalName().toLowerCase() ); // propList = propList == null ? "" : propList; // List<String> props = PackageDescriptionLoader.parseList( propList ); // // // If the file is in one of these directories, we should change it // boolean shouldBeAdded = false; // for (String prop : props) { // IPath prefixPath = Path.fromPortableString( prop ); // if (prefixPath.isPrefixOf( file.getProjectRelativePath() )) { // shouldBeAdded = true; // } // } // // // If should be changed, add every directory in the stanza // if (shouldBeAdded) { // for (String prop : props) { // IPath prefixPath = Path.fromPortableString( prop ); // paths.add( prefixPath ); // } // } // } // } catch (Exception e) { // return new HashSet<IPath>(); // } // // return paths; // } // // public static String getModuleName( final IResource resource ) { // return getModuleName( resource.getProject(), // resource.getProjectRelativePath() ); // } // public static List<IResource> getHaskellFiles( final IProject project, // final IFile file ) { // final ArrayList<IResource> resources = new ArrayList<IResource>(); // final Collection<String> srcs=ResourceUtil.getSourceFolders( new IFile[]{file} ); // // //final Set<IPath> allowedPaths = getStanzaPaths( project, file ); // try { // project.accept( new IResourceVisitor() { // // @Override // public boolean visit( final IResource resource ) { // if( resource instanceof IFile && !( file.equals( resource ) ) // && FileUtil.hasHaskellExtension( resource )) { // // Check if we are in one of the allowed paths // for (String allowedPath : srcs) { // if (allowedPath.isPrefixOf( resource.getProjectRelativePath() )) { // resources.add( resource ); // break; // } // } // } // return true; // } // } ); // } catch( Exception e ) { // // Do nothing // } // return resources; // } // public static String getModuleName( final IProject project, // final IPath projectRelativePath ) { // String path = projectRelativePath.toPortableString(); // for( IPath prefix: getPaths( project ) ) { // String prefixPath = prefix.toPortableString(); // if( path.startsWith( prefixPath ) ) { // String filePath = path.substring( prefixPath.length() + 1 ); // if( filePath.endsWith( ".hs" ) ) { // return filePath.substring( 0, filePath.length() - 3 ).replace( '/', // '.' ); // } else if( filePath.endsWith( ".lhs" ) ) { // return filePath.substring( 0, filePath.length() - 4 ).replace( '/', // '.' ); // } // } // } // // return null; // } public static int getModuleNameOffset( final IResource resource,final String module ) { TextFileDocumentProvider provider = new TextFileDocumentProvider(); try { provider.connect( resource ); } catch( CoreException e ) { return -1; } int offset = -1; try { IDocument doc = provider.getDocument( resource ); /*int numberOfLines = doc.getNumberOfLines(); for( int i = 0; i < numberOfLines; i++ ) { IRegion region = doc.getLineInformation( i ); String text = doc.get( region.getOffset(), region.getLength() ); String[] words = text.split( " " ); if( words[ 0 ].equals( "module" ) ) { // We are in a module declaration String moduleName = words[ 1 ]; if( moduleName.length() == 0 ) { moduleName = words[ 2 ]; } int moduleNamePos = text.indexOf( moduleName ); offset = region.getOffset() + moduleNamePos; break; } }*/ UsageAPI api=BuildWrapperPlugin.getDefault().getUsageAPI(); if (api!=null){ UsageResults ur=api.getModuleDefinitions( null, module, resource.getProject(), true ); Map<IFile,Map<String,Collection<SearchResultLocation>>> m1=ur.getUsageInProject( resource.getProject() ); if (m1!=null){ Map<String,Collection<SearchResultLocation>> m=m1.get( resource ); if (m!=null){ Collection<SearchResultLocation> srls=m.get( "module "+module ); if (srls!=null){ for (SearchResultLocation srl:srls){ offset=srl.getStartOffset( doc ); return offset; } } } } } } catch( BadLocationException e ) { // This should not happen } finally { provider.disconnect( resource ); } return offset; } public static List<Integer> getImportModuleOffsets( final IResource resource, final String moduleName ) { TextFileDocumentProvider provider = new TextFileDocumentProvider(); ArrayList<Integer> offsets = new ArrayList<>(); try { provider.connect( resource ); } catch( CoreException e ) { return offsets; } try { IDocument doc = provider.getDocument( resource ); int numberOfLines = doc.getNumberOfLines(); for( int i = 0; i < numberOfLines; i++ ) { IRegion region = doc.getLineInformation( i ); String text = doc.get( region.getOffset(), region.getLength() ); String[] words = text.split( " " ); for( int j = 0; j < words.length; j++ ) { if( words[ j ].equals( "module" ) ) { try { String mname = words[ j + 1 ]; if( mname.length() == 0 ) { mname = words[ j + 2 ]; } if( mname.equals( moduleName ) ) { int modulePos = text.indexOf( mname ); offsets.add( region.getOffset() + modulePos ); } } catch( Exception e ) { // We are out of bounds } break; } else if( words[ j ].equals( "import" ) ) { try { String mname = words[ j + 1 ]; if( mname.length() == 0 ) { mname = words[ j + 2 ]; } if( mname.equals( "qualified" ) ) { mname = words[ j + 3 ]; if( mname.length() == 0 ) { mname = words[ j + 4 ]; } } if( mname.equals( moduleName ) ) { int modulePos = text.indexOf( mname ); offsets.add( region.getOffset() + modulePos ); } } catch( Exception e ) { // We are out of bounds } break; } } } } catch( BadLocationException e ) { // This should not happen } finally { provider.disconnect( resource ); } return offsets; } public static String newCabalFile( final IProject project, final IFile oldFile, final String newModuleName ) { TextFileDocumentProvider provider = new TextFileDocumentProvider(); String oldModuleName = ResourceUtil.getModuleName( oldFile ); IFile cabalF = BuildWrapperPlugin.getCabalFile( project ); PackageDescription pd = null; try { pd = PackageDescriptionLoader.load( cabalF ); provider.connect( cabalF ); } catch( Exception e ) { return null; } IDocument doc = provider.getDocument( cabalF ); try { //List<PackageDescriptionStanza> lpds = pd.getStanzas(); Set<PackageDescriptionStanza> lpds =ResourceUtil.getApplicableStanzas( new IFile[]{oldFile} ); for( PackageDescriptionStanza pds: lpds ) { // Should we change this stanza? // String srcList = pds.getProperties().get( // CabalSyntax.FIELD_HS_SOURCE_DIRS.getCabalName().toLowerCase() ); // srcList = srcList == null ? "" : srcList; // List<String> srcs = PackageDescriptionLoader.parseList( srcList ); // final Set<IPath> allowedPaths = getStanzaPaths( project, oldFile ); // boolean shouldBeChanged = false; // for (String src : srcs) { // IPath srcPath = Path.fromPortableString( src ); // if (allowedPaths.contains( srcPath )) { // shouldBeChanged = true; // break; // } // } // if (!shouldBeChanged) { // continue; // We should not // } // Modules sections CabalSyntax[] elements = new CabalSyntax[] { CabalSyntax.FIELD_EXPOSED_MODULES, CabalSyntax.FIELD_OTHER_MODULES }; for( CabalSyntax element: elements ) { pds = pd.getSameStanza( pds ); String propList = pds.getProperties().get( element.getCabalName().toLowerCase() ); propList = propList == null ? "" : propList; List<String> props = PackageDescriptionLoader.parseList( propList ); if( props.indexOf( oldModuleName ) != -1 ) { RealValuePosition rvp = pds.removeFromPropertyList( element, oldModuleName ); rvp.updateDocument( doc ); pd = PackageDescriptionLoader.load( doc.get() ); pds = pd.getSameStanza( pds ); rvp = pds.addToPropertyList( element, newModuleName ); rvp.updateDocument( doc ); pd = PackageDescriptionLoader.load( doc.get() ); pds = pd.getSameStanza( pds ); } } // Main-is section String oldMainName = oldModuleName.replace( '.', '/' ) + ".hs"; String newMainName = newModuleName.replace( '.', '/' ) + ".hs"; pds = pd.getSameStanza( pds ); String mainProp = pds.getProperties().get( CabalSyntax.FIELD_MAIN_IS.getCabalName().toLowerCase() ); mainProp = mainProp == null ? "" : mainProp; if( oldMainName.equals( mainProp ) ) { RealValuePosition rvp = pds.update( CabalSyntax.FIELD_MAIN_IS, newMainName ); rvp.updateDocument( doc ); pd = PackageDescriptionLoader.load( doc.get() ); pds = pd.getSameStanza( pds ); } } } catch( Exception e ) { // Do nothing } finally { provider.disconnect( cabalF ); } return doc.get(); } public static String newRemoveModuleCabalFile( final IProject project, final IFile oldFile ) { TextFileDocumentProvider provider = new TextFileDocumentProvider(); String oldModuleName = ResourceUtil.getModuleName( oldFile ); IFile cabalF = BuildWrapperPlugin.getCabalFile( project ); PackageDescription pd = null; try { pd = PackageDescriptionLoader.load( cabalF ); provider.connect( cabalF ); } catch( Exception e ) { return null; } IDocument doc = provider.getDocument( cabalF ); try { // List<PackageDescriptionStanza> lpds = pd.getStanzas(); Set<PackageDescriptionStanza> lpds =ResourceUtil.getApplicableStanzas( new IFile[]{oldFile} ); for( PackageDescriptionStanza pds: lpds ) { // // Should we change this stanza? // String srcList = pds.getProperties().get( // CabalSyntax.FIELD_HS_SOURCE_DIRS.getCabalName().toLowerCase() ); // srcList = srcList == null ? "" : srcList; // List<String> srcs = PackageDescriptionLoader.parseList( srcList ); // final Set<IPath> allowedPaths = getStanzaPaths( project, oldFile ); // boolean shouldBeChanged = false; // for (String src : srcs) { // IPath srcPath = Path.fromPortableString( src ); // if (allowedPaths.contains( srcPath )) { // shouldBeChanged = true; // break; // } // } // if (!shouldBeChanged) { // continue; // We should not // } // Modules sections CabalSyntax[] elements = new CabalSyntax[] { CabalSyntax.FIELD_EXPOSED_MODULES, CabalSyntax.FIELD_OTHER_MODULES }; for( CabalSyntax element: elements ) { pds = pd.getSameStanza( pds ); String propList = pds.getProperties().get( element.getCabalName().toLowerCase() ); propList = propList == null ? "" : propList; List<String> props = PackageDescriptionLoader.parseList( propList ); if( props.indexOf( oldModuleName ) != -1 ) { RealValuePosition rvp = pds.removeFromPropertyList( element, oldModuleName ); rvp.updateDocument( doc ); pd = PackageDescriptionLoader.load( doc.get() ); pds = pd.getSameStanza( pds ); } } // Main-is section String oldMainName = oldModuleName.replace( '.', '/' ) + ".hs"; pds = pd.getSameStanza( pds ); String mainProp = pds.getProperties().get( CabalSyntax.FIELD_MAIN_IS.getCabalName().toLowerCase() ); mainProp = mainProp == null ? "" : mainProp; if( oldMainName.equals( mainProp ) ) { RealValuePosition rvp = pds.update( CabalSyntax.FIELD_MAIN_IS, "" ); rvp.updateDocument( doc ); pd = PackageDescriptionLoader.load( doc.get() ); pds = pd.getSameStanza( pds ); } } } catch( Exception e ) { // Do nothing } finally { provider.disconnect( cabalF ); } return doc.get(); } public static String newSourceFolderCabalFile(final IProject project, final IPath oldPath, final IPath newPath) { TextFileDocumentProvider provider = new TextFileDocumentProvider(); IFile cabalF = BuildWrapperPlugin.getCabalFile( project ); PackageDescription pd = null; try { pd = PackageDescriptionLoader.load( cabalF ); provider.connect( cabalF ); } catch( Exception e ) { return null; } IDocument doc = provider.getDocument( cabalF ); try { List<PackageDescriptionStanza> lpds = pd.getStanzas(); for( PackageDescriptionStanza pds: lpds ) { // Should we change this stanza? String srcList = pds.getProperties().get( CabalSyntax.FIELD_HS_SOURCE_DIRS.getCabalName().toLowerCase() ); srcList = srcList == null ? "" : srcList; List<String> srcs = PackageDescriptionLoader.parseList( srcList ); for (String src : srcs) { IPath srcPath = Path.fromPortableString( src ); if (srcPath.equals( oldPath )) { RealValuePosition rvp = pds.removeFromPropertyList( CabalSyntax.FIELD_HS_SOURCE_DIRS, oldPath.toPortableString() ); rvp.updateDocument( doc ); pd = PackageDescriptionLoader.load( doc.get() ); pds = pd.getSameStanza( pds ); rvp = pds.addToPropertyList( CabalSyntax.FIELD_HS_SOURCE_DIRS, newPath.toPortableString() ); rvp.updateDocument( doc ); pd = PackageDescriptionLoader.load( doc.get() ); pds = pd.getSameStanza( pds ); break; } } } } catch( Exception e ) { // Do nothing } finally { provider.disconnect( cabalF ); } return doc.get(); } }