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

时间:2013-03-29 22:03:03

标签: java tabs intellij-idea intellij-plugin

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

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

  1. 阅读打开的标签页(使用哪个文件和编辑器?)
  2. 将该信息持久存储为标签会话
  3. 打开所选会话的标签页并关闭所有其他会话
  4. 我查看了可用的操作:IdeActions.java - 似乎没有我要搜索的内容。但也许我正在寻找错误的地方。任何人都可以告诉我,我想要实现的目标是否可行并向我提供正确方向的指示?

    更新

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

    可在官方插件存储库中找到:Tab Session

    更新2

    以下是有关分割窗口的后续问题:Retrieving and setting split window settings

1 个答案:

答案 0 :(得分:24)

2017年更新

我停止支持此插件,因为IDEA已经支持该功能。您可以轻松保存和加载上下文,如下所示: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是规范路径的字符串数组):

    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 sources到任意文件夹:

    git clone git://git.jetbrains.org/idea/community.git idea
    
  4. Configure IDEA SDK and create plugin

  5. 插件结构

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

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

    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<SessionState> {
    
        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中有一个条目,如下所示:

    <project-components>
      <component>
        <implementation-class>my.package.SessionComponent</implementation-class>
      </component>
    </project-components>
    

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

    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

      <actions>
        <!-- Add your actions here -->
          <group id="MyPlugin.SampleMenu" text="_Sample Menu" description="Sample menu">
              <add-to-group group-id="MainMenu" anchor="last"  />
              <action id="MyPlugin.Save" class="my.package.Save" text="_Save" description="A test menu item" />
              <action id="MyPlugin.Load" class="my.package.Load" text="_Load" description="A test menu item" />
          </group>
      </actions>
    

    插件部署

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