修复部分设备上无法读取配置文件问题

This commit is contained in:
makejava 2020-07-11 15:11:28 +08:00
parent 414c4ca2c6
commit 8b580bc7dd
4 changed files with 329 additions and 126 deletions

View File

@ -1,18 +1,36 @@
package com.sjhy.plugin.entity;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
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.PsiFileFactory;
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;
import com.sjhy.plugin.tool.ProjectUtils;
import lombok.Data;
import lombok.NonNull;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
/**
* 需要保存的文件
* <p>
* 如果文件保存在项目路径下则使用idea提供的psi对象操作如果文件保存在非项目路径下则使用java原始IO流操作
*
* @author makejava
* @version 1.0.0
@ -30,21 +48,17 @@ public class SaveFile {
*/
private String path;
/**
* 虚拟文件
* 文件
*/
private VirtualFile virtualFile;
private String fileName;
/**
* 需要保存的文件
* 文件内容
*/
private PsiFile file;
private String content;
/**
* 是否需要重新格式化代码
*/
private boolean reformat;
/**
* 文件
*/
private PsiFile psiFile;
/**
* 是否显示操作提示
*/
@ -53,28 +67,265 @@ public class SaveFile {
/**
* 构建对象
*
* @param path 路径
* @param fileName 文件没
* @param reformat 是否重新格式化代码
* @param project 项目对象
* @param path 绝对路径
* @param fileName 文件名
* @param content 文件内容
* @param reformat 是否重新格式化代码
* @param operateTitle 操作提示
*/
public SaveFile(Project project, String path, String fileName, String content, boolean reformat, boolean operateTitle) {
public SaveFile(@NonNull Project project, @NonNull String path, @NonNull String fileName, String content, boolean reformat, boolean operateTitle) {
this.path = path;
this.project = project;
// 构建文件对象
PsiFileFactory psiFileFactory = PsiFileFactory.getInstance(project);
this.fileName = fileName;
LOG.assertTrue(content != null);
FileType fileType = FileTypeManager.getInstance().getFileTypeByFileName(fileName);
// 换行符统一使用\n
this.file = psiFileFactory.createFileFromText(fileName, fileType, content.replace("\r", ""));
this.virtualFile = new LightVirtualFile(fileName, fileType, content.replace("\r", ""));
this.content = content.replace("\r", "");
this.reformat = reformat;
this.operateTitle = operateTitle;
}
/**
* 文件是否为项目文件
*
* @return 是否为项目文件
*/
private boolean isProjectFile() {
VirtualFile baseDir = ProjectUtils.getBaseDir(project);
// 无法获取到项目基本目录可能是Default项目直接返回非项目文件
if (baseDir == null) {
return false;
}
// 路径对比判断项目路径是否为文件保存路径的子路径
String projectPath = handlerPath(baseDir.getPath());
String tmpFilePath = handlerPath(this.path);
return tmpFilePath.indexOf(projectPath) == 0;
}
/**
* 处理路径统一分割符并转小写
*
* @param path 路径
* @return 处理后的路径
*/
private String handlerPath(String path) {
return handlerPath(path, true);
}
/**
* 处理路径统一分割符并转小写
*
* @param path 路径
* @param lowerCase 是否转小写
* @return 处理后的路径
*/
private String handlerPath(String path, boolean lowerCase) {
// 统一分割符
path = path.replace("\\", "/");
// 避免重复分割符
path = path.replace("//", "/");
// 统一小写
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() {
// 判断目录是否存在
VirtualFile baseDir = ProjectUtils.getBaseDir(project);
if (baseDir == null) {
throw new IllegalStateException("项目基本路径不存在");
}
// 处理保存路径
String savePath = handlerPath(this.path, false);
// 删除保存路径的前面部分
savePath = savePath.substring(handlerPath(baseDir.getPath()).length());
// 删除开头与结尾的/符号
while (savePath.startsWith("/")) {
savePath = savePath.substring(1);
}
while (savePath.endsWith("/")) {
savePath = savePath.substring(0, savePath.length() - 1);
}
// 查找保存目录是否存在
VirtualFile saveDir = VfsUtil.findRelativeFile(baseDir, savePath.split("/"));
// 提示创建目录
PsiDirectory directory = titleCreateDir(saveDir, baseDir, savePath);
if (directory == null) {
return;
}
PsiFile psiFile = directory.findFile(this.fileName);
// 保存或覆盖
saveOrReplaceFile(psiFile, directory);
}
/**
* 提示创建目录
*
* @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;
}
return psiManager.findDirectory(saveDir);
}
/**
* 保存或替换文件
*
* @param psiFile 文件
* @param directory 目录
*/
private void saveOrReplaceFile(PsiFile psiFile, PsiDirectory directory) {
PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(project);
Document document;
// 文件不存在直接创建
if (psiFile == null) {
psiFile = directory.createFile(this.fileName);
document = coverFile(psiFile);
} else {
// 提示覆盖文件
if (operateTitle) {
String msg = String.format("File %s Exists, Select Operate Mode?", psiFile.getVirtualFile().getPath());
MessageDialogBuilder.YesNoCancel yesNoCancel = MessageDialogBuilder.yesNoCancel(MsgValue.TITLE_INFO, msg);
yesNoCancel.yesText("Cover");
yesNoCancel.noText("Compare");
yesNoCancel.cancelText("Cancel");
int result = yesNoCancel.show();
switch (result) {
case Messages.YES:
// 覆盖文件
document = coverFile(psiFile);
break;
case Messages.NO:
// 对比代码时也格式化代码
String newText = content;
if (reformat) {
// 保留旧文件内容用新文件覆盖旧文件执行格式化然后再还原旧文件内容
String oldText = psiFile.getText();
Document tmpDoc = coverFile(psiFile);
// 格式化代码
FileUtils.getInstance().reformatFile(project, Collections.singletonList(psiFile));
// 提交文档改动并非VCS中的提交文件
psiDocumentManager.commitDocument(tmpDoc);
// 获取新的文件内容
newText = psiFile.getText();
// 还原旧文件
coverFile(psiFile, oldText);
}
FileType fileType = FileTypeManager.getInstance().getFileTypeByFileName(fileName);
CompareFileUtils.showCompareWindow(project, psiFile.getVirtualFile(), new LightVirtualFile(fileName, fileType, newText));
return;
case Messages.CANCEL:
default:
return;
}
} else {
// 没有操作提示的情况下直接覆盖
document = coverFile(psiFile);
}
}
// 执行代码格式化操作
if (reformat) {
FileUtils.getInstance().reformatFile(project, Collections.singletonList(psiFile));
}
// 提交文档改动并非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() {
FileUtils.getInstance().write(this);
if (isProjectFile()) {
writeByPsiFile();
} else {
try {
writeByJavaFile();
} catch (IOException e) {
ExceptionUtil.rethrow(e);
}
}
}
}

View File

@ -7,7 +7,6 @@ import com.intellij.database.psi.DbTable;
import com.intellij.database.util.DasUtil;
import com.intellij.openapi.options.ShowSettingsUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectUtil;
import com.intellij.openapi.ui.MessageDialogBuilder;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.VirtualFile;
@ -379,7 +378,7 @@ public class TableInfoServiceImpl implements TableInfoService {
* @return EasyCodeConfig目录
*/
private PsiDirectory getEasyCodeConfigDirectory(Project project) {
VirtualFile baseDir = ProjectUtil.guessProjectDir(project);
VirtualFile baseDir = ProjectUtils.getBaseDir(project);
if (baseDir == null) {
Messages.showInfoMessage("无法获取项目路径", MsgValue.TITLE_INFO);
return null;

View File

@ -6,28 +6,14 @@ 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.MessageDialogBuilder;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.vfs.LocalFileSystem;
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.entity.SaveFile;
import lombok.NonNull;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
import java.util.List;
/**
@ -69,96 +55,23 @@ public class FileUtils {
}
/**
* 写入文件
* 设置文件内容
*
* @param saveFile 需要保存的文件对象
* @param project 项目对象
* @param psiFile 文件
* @param text 文件内容
* @return 覆盖后的文档对象
*/
public void write(SaveFile saveFile) {
// 校验目录是否存在
PsiManager psiManager = PsiManager.getInstance(saveFile.getProject());
PsiDirectory psiDirectory;
VirtualFile directory = LocalFileSystem.getInstance().findFileByPath(saveFile.getPath());
if (directory == null) {
// 尝试创建目录
if (saveFile.isOperateTitle() && !MessageDialogBuilder.yesNo(MsgValue.TITLE_INFO, "Directory " + saveFile.getPath() + " Not Found, Confirm Create?").isYes()) {
return;
}
psiDirectory = WriteCommandAction.runWriteCommandAction(saveFile.getProject(), (Computable<PsiDirectory>) () -> {
try {
VirtualFile dir = VfsUtil.createDirectoryIfMissing(saveFile.getPath());
LOG.assertTrue(dir != null);
// 重载文件防止发生IndexNotReadyException异常
FileDocumentManager.getInstance().reloadFiles(dir);
return psiManager.findDirectory(dir);
} catch (IOException e) {
LOG.error("path " + saveFile.getPath() + " error");
ExceptionUtil.rethrow(e);
return null;
}
});
} else {
psiDirectory = psiManager.findDirectory(directory);
public Document writeFileContent(Project project, PsiFile psiFile, String fileName, String text) {
PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(project);
Document document = psiDocumentManager.getDocument(psiFile);
if (document == null) {
throw new IllegalStateException("获取文档对象失败fileName" + fileName);
}
if (psiDirectory == null) {
return;
}
// 保存或替换文件
PsiFile oldFile = psiDirectory.findFile(saveFile.getFile().getName());
PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(saveFile.getProject());
FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
if (saveFile.isOperateTitle() && oldFile != null) {
MessageDialogBuilder.YesNoCancel yesNoCancel = MessageDialogBuilder.yesNoCancel(MsgValue.TITLE_INFO, "File " + saveFile.getFile().getName() + " Exists, Select Operate Mode?");
yesNoCancel.yesText("Cover");
yesNoCancel.noText("Compare");
yesNoCancel.cancelText("Cancel");
int result = yesNoCancel.show();
switch (result) {
case Messages.YES:
break;
case Messages.NO:
// 对比代码时也格式化代码
if (saveFile.isReformat()) {
// 保留旧文件内容用新文件覆盖旧文件执行格式化然后再还原旧文件内容
String oldText = oldFile.getText();
WriteCommandAction.runWriteCommandAction(saveFile.getProject(), () -> psiDocumentManager.getDocument(oldFile).setText(saveFile.getFile().getText()));
// 提交所有改动并非VCS中的提交文件
PsiDocumentManager.getInstance(saveFile.getProject()).commitAllDocuments();
reformatFile(saveFile.getProject(), Collections.singletonList(oldFile));
// 提交所有改动并非VCS中的提交文件
PsiDocumentManager.getInstance(saveFile.getProject()).commitAllDocuments();
String newText = oldFile.getText();
WriteCommandAction.runWriteCommandAction(saveFile.getProject(), () -> psiDocumentManager.getDocument(oldFile).setText(oldText));
// 提交所有改动并非VCS中的提交文件
PsiDocumentManager.getInstance(saveFile.getProject()).commitAllDocuments();
saveFile.setVirtualFile(new LightVirtualFile(saveFile.getFile().getName(), saveFile.getFile().getFileType(), newText));
}
CompareFileUtils.showCompareWindow(saveFile.getProject(), fileDocumentManager.getFile(psiDocumentManager.getDocument(oldFile)), saveFile.getVirtualFile());
return;
case Messages.CANCEL:
default:
return;
}
}
PsiDirectory finalPsiDirectory = psiDirectory;
PsiFile finalFile = WriteCommandAction.runWriteCommandAction(saveFile.getProject(), (Computable<PsiFile>) () -> {
if (oldFile == null) {
// 提交所有改动并非VCS中的提交文件
PsiDocumentManager.getInstance(saveFile.getProject()).commitAllDocuments();
return (PsiFile) finalPsiDirectory.add(saveFile.getFile());
} else {
// 对旧文件进行替换操作
Document document = psiDocumentManager.getDocument(oldFile);
LOG.assertTrue(document != null);
document.setText(saveFile.getFile().getText());
return oldFile;
}
});
// 判断是否需要进行代码格式化操作
if (saveFile.isReformat()) {
reformatFile(saveFile.getProject(), Collections.singletonList(finalFile));
}
// 提交所有改动并非VCS中的提交文件
PsiDocumentManager.getInstance(saveFile.getProject()).commitAllDocuments();
WriteCommandAction.runWriteCommandAction(project, () -> document.setText(text));
// 提交改动并非VCS中的提交文件
psiDocumentManager.commitDocument(document);
return document;
}
/**
@ -168,12 +81,10 @@ public class FileUtils {
* @param psiFileList 文件列表
*/
@SuppressWarnings("unchecked")
private void reformatFile(Project project, List<PsiFile> psiFileList) {
public void reformatFile(Project project, List<PsiFile> psiFileList) {
if (CollectionUtil.isEmpty(psiFileList)) {
return;
}
// 提交所有改动并非VCS中的提交文件
PsiDocumentManager.getInstance(project).commitAllDocuments();
// 尝试对文件进行格式化处理
AbstractLayoutCodeProcessor processor = new ReformatCodeProcessor(project, psiFileList.toArray(new PsiFile[0]), null, false);
// 优化导入

View File

@ -1,7 +1,12 @@
package com.sjhy.plugin.tool;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.WindowManager;
import java.awt.*;
@ -46,4 +51,41 @@ public class ProjectUtils {
//否则使用默认项目
return projectManager.getDefaultProject();
}
/**
* 进行旧版本兼容该方法已经存在 @see {@link com.intellij.openapi.project.ProjectUtil#guessProjectDir(Project)}
*
* @param project 项目对象
* @return 基本目录
*/
public static VirtualFile getBaseDir(Project project) {
if (project.isDefault()) {
return null;
}
Module[] modules = ModuleManager.getInstance(project).getModules();
Module module = null;
if (modules.length == 1) {
module = modules[0];
} else {
for (Module item : modules) {
if (item.getName().equals(project.getName())) {
module = item;
break;
}
}
}
if (module != null) {
ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module);
for (VirtualFile contentRoot : moduleRootManager.getContentRoots()) {
if (contentRoot.isDirectory() && contentRoot.getName().equals(module.getName())) {
return contentRoot;
}
}
}
String basePath = project.getBasePath();
if (basePath == null) {
throw new NullPointerException();
}
return LocalFileSystem.getInstance().findFileByPath(basePath);
}
}