IntelliJ IDEA插件开发:保存选项卡组,持久保存它们,并在用户请求时重新加载一组选项卡

我目前正在编写一个IntelliJ插件。 我希望能够存储/恢复一组选项卡以在不同的选项卡会话之间切换(与会话管理器或Session Buddy等浏览器插件相当)。

因此我基本上需要三种类型的动作:

  1. 阅读打开的标签(使用哪个文件和编辑器?)
  2. 将该信息持久存储为选项卡会话
  3. 打开所选会话的选项卡并关闭所有其他会话

我查看了可用的操作: IdeActions.java – 似乎没有我正在搜索的内容。 但也许我正在寻找错误的地方。 任何人都可以告诉我,我想要实现的目标是否可行,并给我一些正确方向的指示?

更新

我成功创建了插件,它可以在Github上找到: http : //alp82.github.com/idea-tabsession/

它可以在官方插件库中找到: Tab Session 。

更新2

以下是有关分割窗口的后续问题: 检索和设置分割窗口设置

2017年更新

我停止支持此插件,因为IDEA已经支持该function。 您可以轻松保存和加载上下文,如下所示: https : //github.com/alp82/idea-tabsession#discontinued

更新

该插件已准备就绪,可以在IDEA – >设置 – >插件中下载。 源代码位于: https : //github.com/alp82/idea-tabsession

简答

要阅读现在打开的选项卡,请使用EditorFactoryFileDocumentManager单例:

  Editor[] editors = EditorFactory.getInstance().getAllEditors(); FileDocumentManager fileDocManager = FileDocumentManager.getInstance(); for(Editor editor : editors) { VirtualFile vf = fileDocManager.getFile(editor.getDocument()); String path = vf.getCanonicalPath(); System.out.println("path = " + path); } 

要打开选项卡,请使用FileEditorManager单例( files是规范路径的String数组):

  FileEditorManager fileEditorManager = FileEditorManager.getInstance(project); for(String path : files) { System.out.println("path = " + path); VirtualFile vf = LocalFileSystem.getInstance().findFileByPath(path); fileEditorManager.openFile(vf, true, true); } 

答案很长

先决条件

  1. 激活插件开发,Groovy和UI Designer插件
  2. 新项目 – > IntelliJ IDEA插件
  3. Checkout IDEA Community Edition源到任何文件夹:

     git clone git://git.jetbrains.org/idea/community.git idea 
  4. 配置IDEA SDK并创建插件

插件结构

创建插件后,您需要编辑位于META-INF文件夹中的plugin.xml。 修改idnamedescription

我们需要一个用于持久存储的配置文件。 在src文件夹中创建mystorage.xml文件。 现在是时候创建所需的文件了:

SessionComponent.java(使用“ Add Project Component向导创建它以自动创建所需的xml设置):

 @State( name = "SessionComponent", storages = { @Storage(id = "default", file = StoragePathMacros.PROJECT_FILE), @Storage(id = "dir", file = StoragePathMacros.PROJECT_CONFIG_DIR + "/mystorage.xml", scheme = StorageScheme.DIRECTORY_BASED) } ) public class SessionComponent implements ProjectComponent, PersistentStateComponent { Project project; SessionState sessionState; public SessionComponent(Project project) { this.project = project; sessionState = new SessionState(); } public void initComponent() { // TODO: insert component initialization logic here } @Override public void loadState(SessionState sessionState) { System.out.println("load sessionState = " + sessionState); this.sessionState = sessionState; } public void projectOpened() { // called when project is opened } public void projectClosed() { // called when project is being closed } @Nullable @Override public SessionState getState() { System.out.println("save sessionState = " + sessionState); return sessionState; } public void disposeComponent() { // TODO: insert component disposal logic here } @NotNull public String getComponentName() { return "SessionComponent"; } public int saveCurrentTabs() { Editor[] editors = getOpenEditors(); FileEditorManager fileEditorManager = FileEditorManager.getInstance(project); VirtualFile[] selectedFiles = fileEditorManager.getSelectedFiles(); FileDocumentManager fileDocManager = FileDocumentManager.getInstance(); sessionState.files = new String[editors.length]; int i = 0; for(Editor editor : editors) { VirtualFile vf = fileDocManager.getFile(editor.getDocument()); String path = vf.getCanonicalPath(); System.out.println("path = " + path); if(path.equals(selectedFiles[0].getCanonicalPath())) { sessionState.focusedFile = path; } sessionState.files[i] = path; i++; } return editors.length; } public int loadSession() { closeCurrentTabs(); FileEditorManager fileEditorManager = FileEditorManager.getInstance(project); for(String path : sessionState.files) { System.out.println("path = " + path); VirtualFile vf = LocalFileSystem.getInstance().findFileByPath(path); fileEditorManager.openFile(vf, true, true); } return sessionState.files.length; } public void closeCurrentTabs() { Editor[] editors = getOpenEditors(); FileEditorManager fileEditorManager = FileEditorManager.getInstance(project); FileDocumentManager fileDocManager = FileDocumentManager.getInstance(); for(Editor editor : editors) { System.out.println("editor = " + editor); VirtualFile vf = fileDocManager.getFile(editor.getDocument()); fileEditorManager.closeFile(vf); } } public void showMessage(String htmlText) { StatusBar statusBar = WindowManager.getInstance().getStatusBar(project); JBPopupFactory.getInstance() .createHtmlTextBalloonBuilder(htmlText, MessageType.INFO, null) .setFadeoutTime(7500) .createBalloon() .show(RelativePoint.getCenterOf(statusBar.getComponent()), Balloon.Position.atRight); } private Editor[] getOpenEditors() { return EditorFactory.getInstance().getAllEditors(); } } 

我们还需要存储类:

 public class SessionState { public String[] files = new String[0]; public String focusedFile = ""; public String toString() { String result = ""; for (String file : files) { result += file + ", "; } result += "selected: " + focusedFile; return result; } } 

组件类应该在plugin.xml中有一个像这样的条目:

   my.package.SessionComponent   

组件类提供所有需要的function,但永远不会被使用。 因此,我们需要采取措施来执行加载和保存:

Save.java:

 public class Save extends AnAction { public Save() { super(); } public void actionPerformed(AnActionEvent event) { Project project = event.getData(PlatformDataKeys.PROJECT); SessionComponent sessionComponent = project.getComponent(SessionComponent.class); int tabCount = sessionComponent.saveCurrentTabs(); String htmlText = "Saved " + String.valueOf(tabCount) + " tabs"; sessionComponent.showMessage(htmlText); } } 

Load.java:

 public class Load extends AnAction { public Load() { super(); } public void actionPerformed(AnActionEvent event) { Project project = event.getData(PlatformDataKeys.PROJECT); SessionComponent sessionComponent = project.getComponent(SessionComponent.class); int tabCount = sessionComponent.loadSession(); String htmlText = "Loaded " + String.valueOf(tabCount) + " tabs"; sessionComponent.showMessage(htmlText); } } 

Aaand ……行动!

我们需要的最后一件事是用户界面来选择这些动作。 只需将它放在plugin.xml

          

插件部署

基本function已准备就绪。 在部署此插件并将其发布到开源社区之前,我将添加对多个会话和一些其他整洁内容的支持。 链接将在此处发布,当它在线时。