IntelliJ IDEA Plugin Development: Save groups of tabs, save them persistently and reload a set of tabs if requested by the user(IntelliJ IDEA 插件开发:保存选项卡组,持久保存并在用户请求时重新加载一组选项卡)
问题描述
我目前正在编写一个 IntelliJ 插件.我希望能够存储/恢复一组选项卡以在不同的选项卡会话之间切换(类似于 会话管理器 或 会话好友).
I am currently at the move to write an IntelliJ plugin. I want to be able to store/restore a set of tabs to switch between different tab sessions (comparable to browser plugins like Session Manager or Session Buddy).
因此我基本上需要三种类型的动作:
Therefore i need basically three types of actions:
- 读取打开的选项卡(使用哪个文件和编辑器?)
 - 将该信息永久存储为选项卡会话
 - 打开选定会话的标签并关闭所有其他标签
 
我查看了可用的操作:IdeActions.java - 似乎没有我正在寻找的东西.但也许我看错了地方.谁能告诉我我想要实现的目标是否可行,并给我一些正确方向的指点?
I looked at the available actions: IdeActions.java - it seems that there is not what i am searching for. But maybe i am looking at the wrong place. Can anyone tell me if what's i am trying to achieve is possible and give me some pointers in the right direction?
我成功创建了插件,它可以在 Github 上找到:http://alp82.github.com/idea-tabsession/
I succesfully created the plugin and it's available at Github: http://alp82.github.com/idea-tabsession/
它在官方插件库中可用:Tab Session.
It is available in the official plugin repository: Tab Session.
这是关于拆分窗口的后续问题:检索和设置拆分窗口设置
Here is a follow-up question regarding splitted windows: Retrieving and setting split window settings
推荐答案
2017年更新
我停止支持此插件,因为 IDEA 已经支持该功能.您可以轻松地保存和加载上下文,如下所示:https://github.com/alp82/idea-tabsession#discontinued
插件已准备就绪,可以在 IDEA -> 设置 -> 插件中下载.源代码位于:https://github.com/alp82/idea-tabsession
The plugin is up and ready and can be downloaded in IDEA -> Settings -> Plugins. Source code is available at: https://github.com/alp82/idea-tabsession
要读取当前打开的选项卡,请使用 EditorFactory 和 FileDocumentManager 单例:
To read which tabs are open right now, use the EditorFactory and FileDocumentManager Singletons:
    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 是规范路径的字符串数组):
To open tabs use the FileEditorManager singleton (files being a String Array of canonical paths):
    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);
    }
长答案
先决条件
- 激活插件开发、Groovy 和 UI Designer 插件
 - 新建项目 -> IntelliJ IDEA 插件
 签出 IDEA Community Edition 源代码到任何文件夹:
git clone git://git.jetbrains.org/idea/community.git idea
配置 IDEA SDK 和创建插件
插件结构
创建插件后,您需要编辑位于 META-INF 文件夹中的 plugin.xml.修改id、name和description.
我们需要一个用于持久存储的配置文件.在 src 文件夹中创建一个 mystorage.xml 文件.现在是时候创建所需的文件了:
We need a configuration file for persistant storage. Create a mystorage.xml file in your src folder. It's now time to create the needed files:
SessionComponent.java(使用Add Project Component向导创建它以自动创建所需的xml设置):
SessionComponent.java (create it with the Add Project Component wizard to automatically create the needed xml settings):
@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 中有一个像这样的条目:
The component class should have an entry in your plugin.xml like this one:
<project-components>
  <component>
    <implementation-class>my.package.SessionComponent</implementation-class>
  </component>
</project-components>
组件类提供了所有需要的功能,但从未使用过.因此,我们需要执行加载和保存操作:
The component class offers all needed functionality, but is never be used. Therefore, we need actions to perform loading and saving:
保存.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);
    }
}
加载.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>
插件部署
基本功能已准备就绪.在部署此插件并将其发布到开源社区之前,我将添加对多个会话和其他一些简洁内容的支持.链接将在此处发布,当它在线时.
Plugin Deployment
The basic functionality is ready. I will add support for multiple sessions and some other neat stuff before deploying this plugin and releasing it to the open-source community. Link will be posted here, when it's online.
这篇关于IntelliJ IDEA 插件开发:保存选项卡组,持久保存并在用户请求时重新加载一组选项卡的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:IntelliJ IDEA 插件开发:保存选项卡组,持久保存并
				
        
 
            
        - Eclipse 插件更新错误日志在哪里? 2022-01-01
 - Jersey REST 客户端:发布多部分数据 2022-01-01
 - 从 finally 块返回时 Java 的奇怪行为 2022-01-01
 - 将log4j 1.2配置转换为log4j 2配置 2022-01-01
 - Java包名称中单词分隔符的约定是什么? 2022-01-01
 - C++ 和 Java 进程之间的共享内存 2022-01-01
 - Spring Boot连接到使用仲裁器运行的MongoDB副本集 2022-01-01
 - Safepoint+stats 日志,输出 JDK12 中没有 vmop 操作 2022-01-01
 - value & 是什么意思?0xff 在 Java 中做什么? 2022-01-01
 - 如何使用WebFilter实现授权头检查 2022-01-01
 
						
						
						
						
						