将PSI文件操作统一替换为virtualFile操作,避免部分文件未被idea托管导致读取写入失败问题。

This commit is contained in:
makejava 2020-07-14 17:08:38 +08:00
parent 8b580bc7dd
commit de4342a9d6
3 changed files with 165 additions and 151 deletions

View File

@ -2,20 +2,16 @@ package com.sjhy.plugin.entity;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.MessageDialogBuilder;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.testFramework.LightVirtualFile;
import com.intellij.util.ExceptionUtil;
import com.sjhy.plugin.constants.MsgValue;
import com.sjhy.plugin.tool.CompareFileUtils;
import com.sjhy.plugin.tool.FileUtils;
@ -25,7 +21,6 @@ import lombok.NonNull;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
/**
* 需要保存的文件
@ -63,6 +58,10 @@ public class SaveFile {
* 是否显示操作提示
*/
private boolean operateTitle;
/**
* 文件工具类
*/
private FileUtils fileUtils = FileUtils.getInstance();
/**
* 构建对象
@ -127,49 +126,10 @@ public class SaveFile {
return lowerCase ? path.toLowerCase() : path;
}
/**
* 通过Java文件方式写入
*/
private void writeByJavaFile() throws IOException {
// 判断目录是否存在
File dir = new File(path);
if (!dir.exists()) {
String msg = String.format("Directory %s Not Found, Confirm Create?", this.path);
if (this.operateTitle && !MessageDialogBuilder.yesNo(MsgValue.TITLE_INFO, msg).isYes()) {
return;
}
// 创建目录
if (!dir.mkdirs()) {
throw new IllegalStateException("目录创建失败:" + path);
}
} else if (dir.isFile()) {
throw new IllegalStateException("保存目录是一个文件:" + path);
}
// 判断文件是否存在
File file = new File(dir, fileName);
if (file.exists()) {
if (file.isDirectory()) {
throw new IllegalStateException("保存的文件是一个目录:" + file.getAbsolutePath());
}
// 提示覆盖文件
if (operateTitle) {
String msg = String.format("File %s Exists, Confirm Cover?", file.getAbsolutePath());
if (!MessageDialogBuilder.yesNo(MsgValue.TITLE_INFO, msg).isYes()) {
return;
}
}
// 直接覆盖文件
FileUtil.writeToFile(file, content);
} else {
// 直接创建文件
FileUtil.writeToFile(file, content);
}
}
/**
* 通过IDEA自带的Psi文件方式写入
*/
private void writeByPsiFile() {
public void write() {
// 判断目录是否存在
VirtualFile baseDir = ProjectUtils.getBaseDir(project);
if (baseDir == null) {
@ -177,8 +137,12 @@ public class SaveFile {
}
// 处理保存路径
String savePath = handlerPath(this.path, false);
// 删除保存路径的前面部分
savePath = savePath.substring(handlerPath(baseDir.getPath()).length());
if (isProjectFile()) {
// 删除保存路径的前面部分
savePath = savePath.substring(handlerPath(baseDir.getPath()).length());
} else {
baseDir = null;
}
// 删除开头与结尾的/符号
while (savePath.startsWith("/")) {
savePath = savePath.substring(1);
@ -187,13 +151,18 @@ public class SaveFile {
savePath = savePath.substring(0, savePath.length() - 1);
}
// 查找保存目录是否存在
VirtualFile saveDir = VfsUtil.findRelativeFile(baseDir, savePath.split("/"));
VirtualFile saveDir;
if (baseDir == null) {
saveDir = VfsUtil.findFileByIoFile(new File(savePath), false);
} else {
saveDir = VfsUtil.findRelativeFile(baseDir, savePath.split("/"));
}
// 提示创建目录
PsiDirectory directory = titleCreateDir(saveDir, baseDir, savePath);
VirtualFile directory = titleCreateDir(saveDir, baseDir, savePath);
if (directory == null) {
return;
}
PsiFile psiFile = directory.findFile(this.fileName);
VirtualFile psiFile = directory.findChild(this.fileName);
// 保存或覆盖
saveOrReplaceFile(psiFile, directory);
}
@ -204,49 +173,44 @@ public class SaveFile {
* @param saveDir 保存路径
* @return 是否放弃执行
*/
private PsiDirectory titleCreateDir(VirtualFile saveDir, VirtualFile baseDir, String savePath) {
PsiManager psiManager = PsiManager.getInstance(project);
if (saveDir == null) {
// 尝试创建目录
String msg = String.format("Directory %s Not Found, Confirm Create?", this.path);
if (this.operateTitle && !MessageDialogBuilder.yesNo(MsgValue.TITLE_INFO, msg).isYes()) {
return null;
}
// 创建目录
PsiDirectory dir = psiManager.findDirectory(baseDir);
for (String item : savePath.split("/")) {
if (dir == null) {
throw new IllegalStateException("目录创建失败:" + savePath);
}
PsiDirectory tmpDir = dir.findSubdirectory(item);
if (tmpDir == null) {
dir = dir.createSubdirectory(item);
} else {
dir = tmpDir;
}
}
return dir;
private VirtualFile titleCreateDir(VirtualFile saveDir, VirtualFile baseDir, String savePath) {
if (saveDir != null) {
return saveDir;
}
return psiManager.findDirectory(saveDir);
// 尝试创建目录
String msg = String.format("Directory %s Not Found, Confirm Create?", this.path);
if (this.operateTitle && !MessageDialogBuilder.yesNo(MsgValue.TITLE_INFO, msg).isYes()) {
return null;
}
try {
saveDir = VfsUtil.createDirectoryIfMissing(baseDir, savePath);
} catch (IOException e) {
Messages.showWarningDialog("目录创建失败" + savePath, MsgValue.TITLE_INFO);
return null;
}
return saveDir;
}
/**
* 保存或替换文件
*
* @param psiFile 文件
* @param file 文件
* @param directory 目录
*/
private void saveOrReplaceFile(PsiFile psiFile, PsiDirectory directory) {
private void saveOrReplaceFile(VirtualFile file, VirtualFile directory) {
PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(project);
Document document;
// 文件不存在直接创建
if (psiFile == null) {
psiFile = directory.createFile(this.fileName);
document = coverFile(psiFile);
if (file == null) {
file = fileUtils.createChildFile(project, directory, this.fileName);
if (file == null) {
return;
}
document = coverFile(file);
} else {
// 提示覆盖文件
if (operateTitle) {
String msg = String.format("File %s Exists, Select Operate Mode?", psiFile.getVirtualFile().getPath());
String msg = String.format("File %s Exists, Select Operate Mode?", file.getPath());
MessageDialogBuilder.YesNoCancel yesNoCancel = MessageDialogBuilder.yesNoCancel(MsgValue.TITLE_INFO, msg);
yesNoCancel.yesText("Cover");
yesNoCancel.noText("Compare");
@ -255,26 +219,26 @@ public class SaveFile {
switch (result) {
case Messages.YES:
// 覆盖文件
document = coverFile(psiFile);
document = coverFile(file);
break;
case Messages.NO:
// 对比代码时也格式化代码
String newText = content;
if (reformat) {
// 保留旧文件内容用新文件覆盖旧文件执行格式化然后再还原旧文件内容
String oldText = psiFile.getText();
Document tmpDoc = coverFile(psiFile);
String oldText = getFileText(file);
Document tmpDoc = coverFile(file);
// 格式化代码
FileUtils.getInstance().reformatFile(project, Collections.singletonList(psiFile));
FileUtils.getInstance().reformatFile(project, file);
// 提交文档改动并非VCS中的提交文件
psiDocumentManager.commitDocument(tmpDoc);
// 获取新的文件内容
newText = psiFile.getText();
newText = getFileText(file);
// 还原旧文件
coverFile(psiFile, oldText);
coverFile(file, oldText);
}
FileType fileType = FileTypeManager.getInstance().getFileTypeByFileName(fileName);
CompareFileUtils.showCompareWindow(project, psiFile.getVirtualFile(), new LightVirtualFile(fileName, fileType, newText));
CompareFileUtils.showCompareWindow(project, file, new LightVirtualFile(fileName, fileType, newText));
return;
case Messages.CANCEL:
default:
@ -282,50 +246,44 @@ public class SaveFile {
}
} else {
// 没有操作提示的情况下直接覆盖
document = coverFile(psiFile);
document = coverFile(file);
}
}
// 执行代码格式化操作
if (reformat) {
FileUtils.getInstance().reformatFile(project, Collections.singletonList(psiFile));
FileUtils.getInstance().reformatFile(project, file);
}
// 提交文档改动并非VCS中的提交文件
psiDocumentManager.commitDocument(document);
}
/**
* 覆盖文件
*
* @param psiFile 文件
* @return 覆盖后的文档对象
*/
private Document coverFile(PsiFile psiFile) {
return coverFile(psiFile, content);
}
/**
* 覆盖文件
*
* @param psiFile 文件
* @param text 文件内容
* @return 覆盖后的文档对象
*/
private Document coverFile(PsiFile psiFile, String text) {
return FileUtils.getInstance().writeFileContent(project, psiFile, fileName, text);
}
/**
* 写入文件
*/
public void write() {
if (isProjectFile()) {
writeByPsiFile();
} else {
try {
writeByJavaFile();
} catch (IOException e) {
ExceptionUtil.rethrow(e);
}
private String getFileText(VirtualFile file) {
FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
Document document = fileDocumentManager.getDocument(file);
if (document == null) {
throw new IllegalStateException("virtual file to document failure");
}
return document.getText();
}
/**
* 覆盖文件
*
* @param file 文件
* @return 覆盖后的文档对象
*/
private Document coverFile(VirtualFile file) {
return coverFile(file, content);
}
/**
* 覆盖文件
*
* @param file 文件
* @param text 文件内容
* @return 覆盖后的文档对象
*/
private Document coverFile(VirtualFile file, String text) {
return FileUtils.getInstance().writeFileContent(project, file, fileName, text);
}
}

View File

@ -5,14 +5,13 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.intellij.database.model.DasColumn;
import com.intellij.database.psi.DbTable;
import com.intellij.database.util.DasUtil;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.options.ShowSettingsUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.MessageDialogBuilder;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.util.ExceptionUtil;
import com.intellij.util.containers.JBIterable;
import com.sjhy.plugin.constants.MsgValue;
@ -352,20 +351,25 @@ public class TableInfoServiceImpl implements TableInfoService {
*/
private TableInfo read(TableInfo tableInfo) {
// 获取保存的目录
PsiDirectory easyCodeConfigDir = getEasyCodeConfigDirectory(project);
VirtualFile easyCodeConfigDir = getEasyCodeConfigDirectory(project);
if (easyCodeConfigDir == null) {
return null;
}
// 获取配置文件
String fileName = getConfigFileName(tableInfo.getObj());
PsiFile configJsonFile = easyCodeConfigDir.findFile(getConfigFileName(tableInfo.getObj()));
VirtualFile configJsonFile = easyCodeConfigDir.findChild(getConfigFileName(tableInfo.getObj()));
if (configJsonFile == null) {
return null;
}
Document document = FileDocumentManager.getInstance().getDocument(configJsonFile);
if (document == null) {
Messages.showInfoMessage(fileName + "转文档对象失败", MsgValue.TITLE_INFO);
return null;
}
// 读取并解析文件
String json = fileUtils.read(configJsonFile);
String json = document.getText();
if (StringUtils.isEmpty(json)) {
Messages.showInfoMessage(fileName + "配置文件文件为空,请尝试手动删除" + configJsonFile.getVirtualFile().getPath() + "文件!", MsgValue.TITLE_INFO);
Messages.showInfoMessage(fileName + "配置文件文件为空,请尝试手动删除" + configJsonFile.getPath() + "文件!", MsgValue.TITLE_INFO);
return null;
}
return parser(json, configJsonFile);
@ -377,28 +381,22 @@ public class TableInfoServiceImpl implements TableInfoService {
* @param project 项目
* @return EasyCodeConfig目录
*/
private PsiDirectory getEasyCodeConfigDirectory(Project project) {
private VirtualFile getEasyCodeConfigDirectory(Project project) {
VirtualFile baseDir = ProjectUtils.getBaseDir(project);
if (baseDir == null) {
Messages.showInfoMessage("无法获取项目路径", MsgValue.TITLE_INFO);
return null;
}
// 项目目录
PsiDirectory projectDirectory = PsiManager.getInstance(project).findDirectory(baseDir);
if (projectDirectory == null) {
Messages.showInfoMessage("项目路径转换失败", MsgValue.TITLE_INFO);
return null;
}
// 获取.idea路径
PsiDirectory ideaDir = projectDirectory.findSubdirectory(".idea");
VirtualFile ideaDir = baseDir.findChild(".idea");
if (ideaDir == null) {
Messages.showInfoMessage(".idea路径获取失败", MsgValue.TITLE_INFO);
return null;
}
// 查找或创建EasyCodeConfig路径
PsiDirectory easyCodeDir = ideaDir.findSubdirectory("EasyCodeConfig");
VirtualFile easyCodeDir = ideaDir.findChild("EasyCodeConfig");
if (easyCodeDir == null) {
easyCodeDir = ideaDir.createSubdirectory("EasyCodeConfig");
easyCodeDir = fileUtils.createChildDirectory(project, ideaDir, "EasyCodeConfig");
}
return easyCodeDir;
}
@ -420,11 +418,11 @@ public class TableInfoServiceImpl implements TableInfoService {
* @param str 原始JSON字符串
* @return 解析结果
*/
private TableInfo parser(String str, PsiFile originalFile) {
private TableInfo parser(String str, VirtualFile originalFile) {
try {
return objectMapper.readValue(str, TableInfo.class);
} catch (IOException e) {
Messages.showWarningDialog("读取配置失败JSON反序列化异常。请尝试手动删除" + originalFile.getVirtualFile().getPath() + "文件!", MsgValue.TITLE_INFO);
Messages.showWarningDialog("读取配置失败JSON反序列化异常。请尝试手动删除" + originalFile.getPath() + "文件!", MsgValue.TITLE_INFO);
ExceptionUtil.rethrow(e);
}
return null;

View File

@ -6,14 +6,23 @@ import com.intellij.codeInsight.actions.ReformatCodeProcessor;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.util.ExceptionUtil;
import lombok.NonNull;
import com.sjhy.plugin.constants.MsgValue;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
import java.util.List;
/**
@ -45,35 +54,84 @@ public class FileUtils {
}
/**
* 读取文件内容文本文件
* 创建子目录
*
* @param jsonFile JSON配置文件
* @return 文件内容
* @param project 文件对象
* @param parent 父级目录
* @param dirName 子目录
* @return 目录对象
*/
public String read(@NonNull PsiFile jsonFile) {
return jsonFile.getText();
public VirtualFile createChildDirectory(Project project, VirtualFile parent, String dirName) {
return WriteCommandAction.runWriteCommandAction(project, (Computable<VirtualFile>) () -> {
try {
return VfsUtil.createDirectoryIfMissing(parent, dirName);
} catch (IOException e) {
Messages.showWarningDialog("目录创建失败:" + dirName, MsgValue.TITLE_INFO);
return null;
}
});
}
/**
* 创建子文件
*
* @param project 项目对象
* @param parent 父级目录
* @param fileName 子文件名
* @return 文件对象
*/
public VirtualFile createChildFile(Project project, VirtualFile parent, String fileName) {
return WriteCommandAction.runWriteCommandAction(project, (Computable<VirtualFile>) () -> {
PsiManager psiManager = PsiManager.getInstance(project);
try {
PsiDirectory directory = psiManager.findDirectory(parent);
if (directory != null) {
PsiFile psiFile = directory.createFile(fileName);
return psiFile.getVirtualFile();
}
return parent.createChildData(new Object(), fileName);
} catch (IOException e) {
Messages.showWarningDialog("文件创建失败:" + fileName, MsgValue.TITLE_INFO);
return null;
}
});
}
/**
* 设置文件内容
*
* @param project 项目对象
* @param psiFile 文件
* @param file 文件
* @param text 文件内容
* @return 覆盖后的文档对象
*/
public Document writeFileContent(Project project, PsiFile psiFile, String fileName, String text) {
PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(project);
Document document = psiDocumentManager.getDocument(psiFile);
public Document writeFileContent(Project project, VirtualFile file, String fileName, String text) {
FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
Document document = fileDocumentManager.getDocument(file);
if (document == null) {
throw new IllegalStateException("获取文档对象失败fileName" + fileName);
}
WriteCommandAction.runWriteCommandAction(project, () -> document.setText(text));
PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(project);
// 提交改动并非VCS中的提交文件
psiDocumentManager.commitDocument(document);
return document;
}
/**
* 格式化虚拟文件
*
* @param project 项目对象
* @param virtualFile 虚拟文件
*/
public void reformatFile(Project project, VirtualFile virtualFile) {
PsiFile psiFile = PsiManager.getInstance(project).findFile(virtualFile);
if (psiFile == null) {
return;
}
reformatFile(project, Collections.singletonList(psiFile));
}
/**
* 执行格式化
*