package com.redhat.ceylon.eclipse.code.imports; import static com.redhat.ceylon.eclipse.code.editor.Navigation.gotoLocation; import static com.redhat.ceylon.eclipse.util.EditorUtil.getDocument; import static com.redhat.ceylon.eclipse.util.EditorUtil.performChange; import static com.redhat.ceylon.eclipse.java2ceylon.Java2CeylonProxies.utilJ2C; import static com.redhat.ceylon.eclipse.util.Nodes.getImportedName; import static java.lang.Character.isWhitespace; import static java.util.Collections.singletonMap; import java.util.Collections; import java.util.List; import java.util.Map; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.ltk.core.refactoring.TextFileChange; import org.eclipse.text.edits.DeleteEdit; import org.eclipse.text.edits.InsertEdit; import org.eclipse.text.edits.MultiTextEdit; import com.redhat.ceylon.common.Backend; import com.redhat.ceylon.common.Backends; import com.redhat.ceylon.compiler.typechecker.tree.Tree; import com.redhat.ceylon.ide.common.model.ProjectSourceFile; import com.redhat.ceylon.ide.common.modulesearch.ModuleNode; import com.redhat.ceylon.ide.common.modulesearch.ModuleVersionNode; import com.redhat.ceylon.ide.common.typechecker.ProjectPhasedUnit; import com.redhat.ceylon.model.typechecker.model.Module; import com.redhat.ceylon.model.typechecker.model.Unit; @Deprecated public class ModuleImportUtil { private static final List<ModuleVersionNode> NO_MODULE_VERSIONS = Collections.<ModuleVersionNode>emptyList(); public static void exportModuleImports(IProject project, Module target, String moduleName) { ProjectPhasedUnit<IProject,IResource,IFolder,IFile> unit = getDescriptorPhasedUnit(project, target); exportModuleImports(unit.getResourceFile(), unit.getCompilationUnit(), moduleName); } public static void removeModuleImports(IProject project, Module target, List<String> moduleNames) { if (moduleNames.isEmpty()) return; ProjectPhasedUnit<IProject,IResource,IFolder,IFile> unit = getDescriptorPhasedUnit(project, target); removeModuleImports(unit.getResourceFile(), unit.getCompilationUnit(), moduleNames); } public static void exportModuleImports(IFile file, Tree.CompilationUnit cu, String moduleName) { TextFileChange textFileChange = new TextFileChange("Export Module Imports", file); textFileChange.setEdit(new MultiTextEdit()); InsertEdit edit = createExportEdit(cu, moduleName); if (edit!=null) { textFileChange.addEdit(edit); } performChange(textFileChange); } public static void removeModuleImports(IFile file, Tree.CompilationUnit cu, List<String> moduleNames) { TextFileChange textFileChange = new TextFileChange("Remove Module Imports", file); textFileChange.setEdit(new MultiTextEdit()); for (String moduleName: moduleNames) { DeleteEdit edit = createRemoveEdit(cu, moduleName); if (edit!=null) { textFileChange.addEdit(edit); } } performChange(textFileChange); } public static void addModuleImport( IProject project, Module target, String moduleName, String moduleVersion) { ModuleVersionNode versionNode = new ModuleVersionNode( new ModuleNode(moduleName, NO_MODULE_VERSIONS), moduleVersion); int offset = addModuleImports(project, target, singletonMap(moduleName, versionNode)); ProjectPhasedUnit unit = getDescriptorPhasedUnit(project, target); gotoLocation(unit.getUnit(), offset + moduleName.length() + utilJ2C().indents() .getDefaultIndent() .length() + 10, moduleVersion.length()); } public static void makeModuleImportShared( IProject project, Module target, String[] moduleNames) { ProjectPhasedUnit<IProject,IResource,IFolder,IFile> unit = getDescriptorPhasedUnit(project, target); TextFileChange textFileChange = new TextFileChange("Make Module Import Shared", unit.getResourceFile()); textFileChange.setEdit(new MultiTextEdit()); Tree.CompilationUnit compilationUnit = unit.getCompilationUnit(); IDocument doc = getDocument(textFileChange); for (String moduleName: moduleNames) { Tree.ModuleDescriptor moduleDescriptor = compilationUnit.getModuleDescriptors() .get(0); List<Tree.ImportModule> importModules = moduleDescriptor.getImportModuleList() .getImportModules(); for (Tree.ImportModule im: importModules) { String importedName = getImportedName(im); if (importedName!=null && importedName.equals(moduleName)) { if (!removeSharedAnnotation(textFileChange, doc, im.getAnnotationList())) { textFileChange.addEdit( new InsertEdit(im.getStartIndex(), "shared ")); } } } } performChange(textFileChange); } public static boolean removeSharedAnnotation( TextFileChange textFileChange, IDocument doc, Tree.AnnotationList al) { boolean result = false; for (Tree.Annotation a: al.getAnnotations()) { Tree.BaseMemberExpression bme = (Tree.BaseMemberExpression) a.getPrimary(); if (bme.getDeclaration() .getName().equals("shared")) { int stop = a.getEndIndex(); int start = a.getStartIndex(); try { while (isWhitespace(doc.getChar(stop))) { stop++; } } catch (BadLocationException e) { e.printStackTrace(); } textFileChange.addEdit( new DeleteEdit(start, stop-start)); result = true; } } return result; } public static int addModuleImports( IProject project, Module target, Map<String,ModuleVersionNode> moduleNamesAndVersions) { if (moduleNamesAndVersions.isEmpty()) return 0; ProjectPhasedUnit<IProject,IResource,IFolder,IFile> unit = getDescriptorPhasedUnit(project, target); return addModuleImports(unit.getResourceFile(), unit.getCompilationUnit(), project, moduleNamesAndVersions); } public static int addModuleImports(IFile file, Tree.CompilationUnit cu, IProject project, Map<String, ModuleVersionNode> moduleNamesAndVersions) { TextFileChange textFileChange = new TextFileChange("Add Module Imports", file); textFileChange.setEdit(new MultiTextEdit()); for (Map.Entry<String, ModuleVersionNode> entry: moduleNamesAndVersions.entrySet()) { Backends nativeBackend; String name = entry.getKey(); String version = entry.getValue().getVersion(); /*if (CeylonBuilder.compileToJava(project) && CeylonBuilder.compileToJs(project)) {*/ nativeBackend = entry.getValue().getNativeBackend(); /*} else { nativeBackend = null; }*/ Module module = cu.getUnit().getPackage().getModule(); Backends moduleBackends = module.getNativeBackends(); if (moduleBackends!=null && moduleBackends.equals(nativeBackend)) { nativeBackend = null; } InsertEdit edit = createAddEdit(cu, nativeBackend, name, version, getDocument(textFileChange)); if (edit!=null) { textFileChange.addEdit(edit); } } performChange(textFileChange); return textFileChange.getEdit().getOffset(); } private static ProjectPhasedUnit<IProject,IResource,IFolder,IFile> getDescriptorPhasedUnit(IProject project, Module module) { Unit unit = module.getUnit(); if (unit instanceof ProjectSourceFile) { ProjectSourceFile<IProject,IResource,IFolder,IFile> ceylonUnit = (ProjectSourceFile<IProject,IResource,IFolder,IFile>) unit; return ceylonUnit.getPhasedUnit(); } return null; } private static InsertEdit createAddEdit( Tree.CompilationUnit unit, Backends backend, String moduleName, String moduleVersion, IDocument doc) { Tree.ImportModuleList iml = getImportList(unit); if (iml==null) return null; int offset; if (iml.getImportModules().isEmpty()) { offset = iml.getStartIndex() + 1; } else { offset = iml.getImportModules() .get(iml.getImportModules().size() - 1) .getEndIndex(); } String newline = utilJ2C().indents() .getDefaultLineDelimiter(doc); StringBuilder importModule = new StringBuilder(); appendImportStatement(importModule, false, backend, moduleName, moduleVersion, newline); if (iml.getEndToken().getLine()==iml.getToken().getLine()) { importModule.append(newline); } return new InsertEdit(offset, importModule.toString()); } public static void appendImportStatement( StringBuilder importModule, boolean shared, Backends backend, String moduleName, String moduleVersion, String newline) { importModule.append(newline) .append(utilJ2C().indents().getDefaultIndent()); if (shared) { importModule.append("shared "); } if (backend!=null) { appendNative(importModule, backend); importModule.append(' '); } importModule.append("import "); if (!moduleName.matches("^[a-z_]\\w*(\\.[a-z_]\\w*)*$")) { importModule.append('"') .append(moduleName) .append('"'); } else { importModule.append(moduleName); } importModule.append(" \"") .append(moduleVersion) .append("\";"); } public static void appendNative( StringBuilder builder, Backends backends) { builder.append("native("); appendNativeBackends(builder, backends); builder.append(")"); } public static void appendNativeBackends( StringBuilder builder, Backends backends) { boolean first = true; for (Backend backend: backends) { if (first) { first = false; } else { builder.append(", "); } builder.append('"') .append(backend.nativeAnnotation) .append('"'); } } private static DeleteEdit createRemoveEdit( Tree.CompilationUnit unit, String moduleName) { Tree.ImportModuleList iml = getImportList(unit); if (iml==null) return null; Tree.ImportModule prev = null; for (Tree.ImportModule im: iml.getImportModules()) { String ip = getImportedName(im); if (ip!=null && ip.equals(moduleName)) { int startOffset = im.getStartIndex(); int length = im.getDistance(); //TODO: handle whitespace for first import in list if (prev!=null) { int endOffset = prev.getEndIndex(); length += startOffset-endOffset; startOffset = endOffset; } return new DeleteEdit(startOffset, length); } prev = im; } return null; } private static InsertEdit createExportEdit( Tree.CompilationUnit unit, String moduleName) { Tree.ImportModuleList iml = getImportList(unit); if (iml==null) return null; for (Tree.ImportModule im: iml.getImportModules()) { String ip = getImportedName(im); if (ip!=null && ip.equals(moduleName)) { int startOffset = im.getStartIndex(); return new InsertEdit(startOffset, "shared "); } } return null; } private static Tree.ImportModuleList getImportList( Tree.CompilationUnit unit) { List<Tree.ModuleDescriptor> moduleDescriptors = unit.getModuleDescriptors(); if (!moduleDescriptors.isEmpty()) { Tree.ModuleDescriptor moduleDescriptor = moduleDescriptors.get(0); return moduleDescriptor.getImportModuleList(); } else { return null; } } }