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