基於Intellij 外掛開發指南

1004145468發表於2018-09-01

1. VFS 相關(VirtualFileSystem)

1.1 VFS作用:

  • 提供一個處理檔案的通用API,而不關心檔案的具體位置(無論檔案位於磁碟上、歸檔檔案中還是HTTP伺服器上)
  • 追蹤檔案變化,並且在檢測到檔案內容發生更改時能提供新舊兩個版本的檔案
  • 建立檔案在VFS和持久化儲存之間的關聯

1.2. VFS中獲取VirtualFile

  • 從本地IO檔案中獲取
File ioFile = new File("./io.java")
VritualFile virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(ioFile)
virtualFile.refresh(false, true)
複製程式碼
  • 利用FileChooser獲取
FileChooserDescriptor singleFileDescriptor = FileChooserDescriptorFactory.createSingleFileDescriptor();
VirtualFile virtualFile = FileChooser.chooseFile(singleFileDescriptor, project, null);
複製程式碼
  • 通過URL獲取
VirtualFileManager.getInstance().findFileByUrl("xxx");
VirtualFileManager.getInstance().refreshAndFindFileByUrl("xxx");
複製程式碼

1.3對VirtualFile進行讀寫操作

和Android一樣,Intellij Platform不允許直接在主執行緒進行實時的檔案寫入,需要通過一個非同步任務進行。

WriteCommandAction.runWriteCommandAction(project, new Runnable() {
     @Override
    public void run() {
    //   virtualFile.getInputStream() / virtualFile.getOutputStream()         
    }
 });
複製程式碼

1.4 在非同步任務結束後,切回UI執行緒進行UI更新

ApplicationManager.getApplication().invokeLater(new Runnable(){ 
 ...
})

複製程式碼

2. PSI相關(Program Structure Interface)

2.1 PSI介紹

PSI(Program Structure Interface)是Intellij Platform中一個非常重要的概念,在IDE所管理的Project中,每個目錄,Package,原始碼和資原始檔都會被抽象成相應的PSI物件。

2.2 常用子類

PsiDirectory、PsiJavaFile和XmlFile

2.3 建立目錄和檔案

//建立目錄
PsiDirectory baseDir = PsiDirectoryFactory.getInstance(project).createDirectory(project.getBaseDir());
//建立Java檔案
PsiJavaFile psiFile = (PsiJavaFile) PsiFileFactory.getInstance(project).createFileFromText("", StdFileTypes.JAVA, "");
//建立Xml檔案
XmlFile psiFile = (XmlFile) PsiFileFactory.getInstance(project).createFileFromText("", StdFileTypes.XML, "");
複製程式碼

2.4 讀寫檔案

和寫入VirtualFile一樣,讀寫操作都需要在WriteCommandAction非同步執行緒中進行。

2.5 Xml檔案寫入屬性

XmlDocument document = xmlFile.getDocument();
if (document != null && document.getRootTag() != null) {
XmlTag rootTag = document.getRootTag();
rootTag.getAttribute(attrName).setValue(attrValue);//set value for exists attr.      
rootTag.setAttribute(name,value);//add a new attr and setting value
}
複製程式碼

2.6 搜尋檔案

//  方法一:(全類名)
JavaPsiFacade.getInstance(mFile.getProject()).findClass(qualifiedName,GlobalSearchScope.alScope(mFile.getProject()));
//  方法二: (全類名)
FilenameIndex.getFilesByName()
//  方法三: (短類名)
PsiShortNamesCache.getInstance().getClassesByName()
複製程式碼

2.7 建立Class檔案類

PsiClass clazz = JavaDirectoryService.getInstance().createClass(subDir, className)
複製程式碼

2.8 修改Class內容

 // 建立Class元素生成器
 PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(mFile.getProject());
 // 利用生成器建立對應的元素(每種元素都對應兩種生成方式)
 elementFactory.createField() / elementFactory.createFieldFromText()
 elementFactory.createMethod() / elementFactory.createMethodFromText()  
 elementFactory.createClass() / elementFactory.createClassFromText()
      ... 
 //將元素新增到class中
 clazz.add(field)

複製程式碼

2.9 修改class的繼承關係

respClass.getExtendsList().add(getReferenceClass(elementFactory, BaseModelStr));
複製程式碼

3.0 修改元素(class field method)的修飾關鍵字(public static ... )

// 新增
respClass.getModifierList().add(elementFactory.createKeyword("public"));
// 刪除
reqClass.getModifierList().getFirstChild().delete();
複製程式碼

3. PSI 與 VFS的聯絡

// VirtualFile 轉 PsiFile
PsiManager.getInstance(project).findFile(virtualFile);

// PsiFile 轉 VirtualFile
VirtualFile virtualFile = psiFile.getVirtualFile();
複製程式碼

4 其他常用方法

// 格式化程式碼
CodeStyleManager.getInstance(project).reformat(psiClass);
// 用編輯器開啟指定檔案
FileEditorManager.getInstance(project).openTextEditor(new OpenFileDescriptor(project, virtualFile), true);

複製程式碼

5. 程式碼例項

github倉庫地址

相關文章