IntelliJ IDEA Plugin Development: Save groups of tabs, save them persistently and reload a set of tabs if requested by the user

前端 未结 1 940
野趣味
野趣味 2020-12-28 16:36

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 plug

相关标签:
1条回答
  • 2020-12-28 16:43

    Update 2017

    I discontinue support for this plugin because IDEA already supports that feature. You can save and load contexts easily as shown here: https://github.com/alp82/idea-tabsession#discontinued

    Update

    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

    Short Answer

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

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

    Long Answer

    Prerequisites

    1. Activate the Plugin Development, Groovy and UI Designer plugins
    2. New Project -> IntelliJ IDEA Plugin
    3. Checkout IDEA Community Edition sources to any folder:

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

    Plugin Structure

    After you have created your plugin you need to edit your plugin.xml located in the META-INF folder. Modify the id, name and description.

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

    We also need the storage class:

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

    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:

    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... Action!

    Last thing we need is the user interface to select those actions. Simply put this in your 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.

    0 讨论(0)
提交回复
热议问题