package com.haskforce.refactoring;
import com.haskforce.psi.*;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.rename.RenamePsiElementProcessor;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
/**
* The rename processor plays a role in renaming files when you rename the module or vice versa.
* The key is that it's necessary to define a direction of the rename. This means that you OR rename the module
* when a file rename is detected OR rename the file when a module rename is detected.
*
* We have chosen to make the rename of a file trigger the rename of a module.
*
* To make sure that we can also go the other way round, so renaming the file when you rename the module, the function
* substituteElementToRename exists. This will intercept any renames to the module and launch a file rename instead.
* Which will in turn rename the module (as we defined the direction fo the rename like that).
*/
public class HaskellRenamePsiElementProcessor extends RenamePsiElementProcessor {
@Nullable
@Override
public PsiElement substituteElementToRename(PsiElement element, Editor editor) {
/**
* If element to rename is a module or an import -> equivalent to a rename of the file
*/
HaskellModuledecl haskellModuledecl = PsiTreeUtil.getParentOfType(element, HaskellModuledecl.class);
if (haskellModuledecl != null){
List<HaskellConid> conidList = haskellModuledecl.getQconid().getConidList();
if(conidList.size() > 0){
HaskellConid haskellConid = conidList.get(conidList.size()-1);
if(element.equals(haskellConid)){
return element.getContainingFile();
}
}
}
HaskellImpdecl haskellImpdecl = PsiTreeUtil.getParentOfType(element, HaskellImpdecl.class);
if(haskellImpdecl != null){
/**
* TODO
* This might also be something to move to the HaskellImpdecl
*/
List<HaskellQconid> qconidList = haskellImpdecl.getQconidList();
if(qconidList.size() >0){
HaskellQconid haskellQconid = qconidList.get(0);
List<HaskellConid> conidList = haskellQconid.getConidList();
if(conidList.size() > 0){
HaskellConid haskellConid = conidList.get(conidList.size() - 1);
if(element.equals(haskellConid)){
return element.getContainingFile();
}
}
}
}
return super.substituteElementToRename(element, editor);
}
@Override
public void prepareRenaming(PsiElement element, String newName, Map<PsiElement, String> allRenames) {
if (element instanceof HaskellFile){
HaskellModuledecl haskellModuledecl = PsiTreeUtil.getChildOfType(element, HaskellModuledecl.class);
if (haskellModuledecl != null){
/**
* TODO duplication (also in substituteElementToRename for example), move this to the
* HaskellModuledecl element itself !?
*/
List<HaskellConid> conidList = haskellModuledecl.getQconid().getConidList();
if (conidList.size() >0){
HaskellConid haskellConid = conidList.get(conidList.size()-1);
String newModuleName = createCorrectModuleName(newName);
String newFileName = createCorrectFileName(newName);
allRenames.put(haskellConid, newModuleName);
allRenames.put(element,newFileName);
}
}
}
super.prepareRenaming(element, newName, allRenames);
}
private String createCorrectModuleName(String newName) {
if (StringUtils.endsWith(newName,".hs")){
return StringUtils.removeEnd(newName,".hs");
} else {
return newName;
}
}
private String createCorrectFileName(String newName) {
if (StringUtils.endsWith(newName,".hs")){
return newName;
} else {
return newName + ".hs";
}
}
@Override
public boolean canProcessElement(PsiElement psiElement) {
return (psiElement instanceof HaskellNamedElement || psiElement instanceof HaskellFile);
}
}