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

Alp*_*Alp 20 java tabs intellij-idea intellij-plugin

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

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

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

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

更新

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

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

更新2

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

Alp*_*Alp 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);
    }
Run Code Online (Sandbox Code Playgroud)

要打开选项卡,请使用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);
    }
Run Code Online (Sandbox Code Playgroud)

答案很长

先决条件

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

    git clone git://git.jetbrains.org/idea/community.git idea
    
    Run Code Online (Sandbox Code Playgroud)
  4. 配置IDEA SDK并创建插件

插件结构

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

我们需要一个用于持久存储的配置文件.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();
    }

}
Run Code Online (Sandbox Code Playgroud)

我们还需要存储类:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

<project-components>
  <component>
    <implementation-class>my.package.SessionComponent</implementation-class>
  </component>
</project-components>
Run Code Online (Sandbox Code Playgroud)

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

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);
    }

}
Run Code Online (Sandbox Code Playgroud)

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);
    }

}
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

插件部署

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