IntelliJ IDEA plug-in development: saving groups of tabs, persistently persisting them, and reloading a set of tabs upon user request

Right now I’m moving on to writing the IntelliJ plugin. I want to be able to save / restore a set of tabs for switching between different tab sessions (comparable to browser plug-ins like Session Manager or Session Buddy ).

Therefore, I need basically three types of actions:

  • Read open tabs (which file and editor are you using?)
  • Save this information as tabs
  • Open the tabs of the selected session and close all others.

I looked at the available actions: IdeActions.java - it seems that I'm not looking for what I'm looking for. But maybe I'm looking the wrong way. Can someone tell me if what I am trying to achieve is possible and give me some pointers in the right direction?

Update

I have successfully created the plugin and it is available on Github: http://alp82.github.com/idea-tabsession/

It is available in the official plugin repository: session tab .

Update 2

The following is a question about broken windows: Getting and setting split window options

+20
java intellij-idea intellij-plugin tabs
Mar 29 '13 at 22:03
source share
1 answer

Update 2017

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

Update

The plugin is ready and ready and can be loaded into 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 buttons:

  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 the tabs, use the FileEditorManager singleton ( files , which is 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

The necessary conditions

Plugin structure

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

We need a configuration file for permanent storage. Create the mystorage.xml file in the src folder. Now it's time to create the necessary files:

SessionComponent.java (create it using the Add Project Component wizard to automatically create the necessary 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 a 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 file like this:

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

The component class offers all the necessary functions, but is never 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!

The last thing we need is a user interface to select these actions. Just 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

Basic functionality is ready. I will add support for several sessions and some other neat things before deploying this plugin and releasing it to the open source community. The link will be posted here when it is online.

+23
Mar 30 '13 at 13:19
source share



All Articles