Sublime Forum

Accessing Sublime state externally?

#1

In my usual mode of work, I will have 2-5 sublime windows open, each one with a different folder open in the side bar. In other words, I use sublime in the same was as pretty much everyone else.

Is there a way to get a list of running sublime instances and the folder that each one is opened on?

Is it possible to get this information from external to Sublime?

What I’m trying to achieve is this:

I’m almost always working on one of the same 5 projects. I want to create a keyboard shortcut that will pop up a dashboard that shows me these 5 projects.

Clicking on that project on the dashboard will either bring the appropriate Sublime window to the top, or it will start a new Sublime instance opened on the correct folder.

This dashboard needs to work, even when there are no instances of Sublime running. Which is why I’m asking if the information is accessible from external to Sublime.

Thanks for any advice.

I’m in Linux btw.

0 Likes

#2

What you’re referring to as instances are generally referred to as windows.

If you open the Sublime console with View > Show Console you can enter sublime.windows() to obtain a list of objects that represent all of the open windows, and for each window object in the list you can invoke it’s folders() method to get the list of folders that are open inside of it.

With that, you can obtain information something like the following (output is reformatted; it appears as one long line in the console output);

>>> [window.folders() for window in sublime.windows()]
[
  [], 
  [
    "/home/tmartin/local/src/hyperhelpcore", 
    "/home/tmartin/.config/sublime-text-3/Packages/HyperHelpAuthor", 
    "/home/tmartin/.config/sublime-text-3/Packages/SnAPI"
  ], 
  [
    "/home/tmartin/local/src/OverrideAudit"
  ]
]

As seen here, it’s possible to have any number of folders open inside of a window, including no folders at all. The output above represents a window with no folders open, one with three folders, and one with a single folder.

Note however that having this information doesn’t necessarily get you any closer to your goals, because knowing what folders are open in windows in Sublime doesn’t give you the information you need to switch to the appropriate window all on it’s own (but more on that near the bottom).

No. Also Yes. So probably.

There’s not a direct mechanism that’s in place for being able to do something like this, but depending on your needs you can make it happen. The subl command line helper allows you to invoke a plugin command from the command line, so if you create a plugin that does something like this you can get the output that way.

For example, given this simple plugin:

import sublime
import sublime_plugin


class WindowListToConsoleCommand(sublime_plugin.ApplicationCommand):
    def run(self, filename):
        with open(filename, "w") as handle:
            for window in sublime.windows():
                handle.write("%s\n" % window.folders())

You can do something like the following from the command line:

tmartin:dart:~> subl --background --command "window_list_to_console {\"filename\": \"/home/tmartin/sample.txt\"}"
tmartin:dart:~> cat /home/tmartin/sample.txt 
['/home/tmartin/local/src/hyperhelpcore', '/home/tmartin/.config/sublime-text-3/Packages/HyperHelpAuthor', '/home/tmartin/.config/sublime-text-3/Packages/SnAPI']
['/home/tmartin/local/src/OverrideAudit']
[]

The plugin has to write the output to a file because the stdout of plugins goes to the Sublime console and not to the terminal. You also want to make sure to pass a fully qualified file name to the command because the current working directory will be inferred by the plugin_host and is most likely not what you expect it to be otherwise. The plugin could also maybe some some error handling of some sort as well.

The above won’t work when Sublime isn’t running; the subl command passes the arguments you provide to the running copy of Sublime to interpret. If Sublime isn’t running, subl will start it for you. However in the case of subl starting Sublime, the command you provide will be ignored because plugins load asynchronously at startup, so the command won’t be available in time.

Moreso a potential failing of this would also be that asking for the information will start Sublime running if it’s not already, and it will jump to the foreground on start even if you use subl --background.

If Sublime isn’t running, then there’s more work involved. The list of windows that were open in Sublime before it was terminated is stored in the session file; on Linux that’s in ~/.config/sublime-text-3/Local/Session.sublime_session.

Parsing that as JSON you can get information on all of the windows that were open in the windows key. If you’re not using sublime-project files, then the object underlying each of the window keys has a key named folders that provides the information, for example:

"folders":
[
    {
        "path": "/home/tmartin/.config/sublime-text-3/Packages/User"
    }
],

If you’re using projects, then you instead need to use some combination of the project and workspace_name keys to obtain the information that you want:

"project": "hyperhelp.sublime-project",
"workspace_name": "/home/tmartin/local/src/hyperhelpcore/hyperhelp.sublime-workspace"

The project file contains the folders key, but as seen here it doesn’t contain any path information, so you would need to grab the path from the workspace_name key instead, since they tend to be stored in the same location.

With all of the above said, in order to activate the window you probably need more information than just the folders open to be able to target the window, so doing all of that may not even be necessary. For example, you can use wmctrl to easily find all of the Sublime windows directly from the terminal or a shell script:

tmartin:dart:~> wmctrl -l | grep "Sublime Text"
0x01200003  0 dart ~/local/src/OverrideAudit/src/events.py (OverrideAudit) - Sublime Text
0x01200016  0 dart ~/.config/sublime-text-3/Packages/User/untitled.py (User) - Sublime Text
0x01200024  0 dart ~/local/src/hyperhelpcore/all/hyperhelpcore/HyperHelp/events.py (untitled) - Sublime Text

The text in the () part is the name of the project or the last component of the path that is open in that window. For windows that don’t have a project or any folders open, the item in the brackets is the base name of the file (here (untitled) represents the fact that the plugin from above is in a file named untitled.py in that window).

Assuming you could use that to determine the folders that you care about, you can also use wmctrl to activate the window that you want after parsing the output above to determine what window you want. For example, to activate the first window:

tmartin:dart:~> wmctrl -ia 0x01200003

This of course doesn’t work if Sublime isn’t already running, though. In a case like that you’d need to parse the data as above to see if a window for the appropriate folder will appear when you start Sublime, and then follow that by starting Sublime and either activating the window or opening a new one, depending on what you found out.

Alternatively when Sublime’s not running you could launch it, then use wmctrl to see what windows are available, which is probably a lot less work overall.

Assuming you’re always using the same set of folders in different windows, the names of the windows should always have the same suffix such that you don’t need to introspect Sublime directly at all, I would think.

6 Likes

#3

Wow, what an incredible response! Thanks so much. I couldn’t have asked for a more comprehensive and well-written reply!

I clearly have a bit of work to do, but I’ll report back if/when I can get something up and running.

0 Likes