├── .gitignore ├── Default (Linux).sublime-keymap ├── Default (OSX).sublime-keymap ├── Default (Windows).sublime-keymap ├── GotoWindow.py ├── GotoWindow.sublime-commands ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | -------------------------------------------------------------------------------- /Default (Linux).sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | { "keys": ["super+shift+o"], "command": "goto_window" } 3 | ] 4 | -------------------------------------------------------------------------------- /Default (OSX).sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | { "keys": ["super+shift+o"], "command": "goto_window" } 3 | ] 4 | -------------------------------------------------------------------------------- /Default (Windows).sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | { "keys": ["super+shift+o"], "command": "goto_window" } 3 | ] 4 | -------------------------------------------------------------------------------- /GotoWindow.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sublime 3 | import sublime_plugin 4 | import subprocess 5 | from subprocess import Popen, PIPE 6 | 7 | 8 | class GotoWindowCommand(sublime_plugin.WindowCommand): 9 | def run(self): 10 | self.mac_os_version = None 11 | 12 | if sublime.platform() == "osx": 13 | try: 14 | version = subprocess.check_output(['sw_vers', '-productVersion'], stderr=subprocess.STDOUT) 15 | except subprocess.CalledProcessError as e: 16 | pass 17 | else: 18 | version_string = "".join(chr(x) for x in version) 19 | self.mac_os_version = version_string.split('.') 20 | 21 | folders = self._get_folders() 22 | 23 | folders_alone = [x for (x, y) in folders] 24 | folders_for_list = [] 25 | for folder in folders_alone: 26 | folders_for_list.append([os.path.basename(folder), folder]) 27 | 28 | self.window.show_quick_panel(folders_for_list, self.on_done, 0) 29 | 30 | def on_done(self, selected_index): 31 | current_index = self._get_current_index() 32 | if selected_index == -1 or current_index == selected_index: 33 | return 34 | 35 | folders = self._get_folders() 36 | window_index = folders[selected_index][1] 37 | window_to_move_to = sublime.windows()[window_index] 38 | 39 | self.focus(window_to_move_to) 40 | 41 | # OS X and Linux require specific workarounds to activate a window 42 | # due to this bug: 43 | # https://github.com/SublimeTextIssues/Core/issues/444 44 | if sublime.platform() == 'osx': 45 | self._osx_focus() 46 | elif sublime.platform() == 'linux': 47 | self._linux_focus(window_to_move_to) 48 | 49 | def focus(self, window_to_move_to): 50 | active_view = window_to_move_to.active_view() 51 | active_group = window_to_move_to.active_group() 52 | 53 | # In Sublime Text 2 if a folder has no open files in it the active view 54 | # will return None. This tries to use the actives view and falls back 55 | # to using the active group 56 | 57 | # Calling focus then the command then focus again is needed to make this 58 | # work on Windows 59 | if active_view is not None: 60 | window_to_move_to.focus_view(active_view) 61 | window_to_move_to.run_command('focus_neighboring_group') 62 | window_to_move_to.focus_view(active_view) 63 | return 64 | 65 | if active_group is not None: 66 | window_to_move_to.focus_group(active_group) 67 | window_to_move_to.run_command('focus_neighboring_group') 68 | window_to_move_to.focus_group(active_group) 69 | 70 | def _osx_focus(self): 71 | name = 'Sublime Text' 72 | if int(sublime.version()) < 3000: 73 | name = 'Sublime Text 2' 74 | 75 | # This is some magic. I spent many many hours trying to find a 76 | # workaround for the Sublime Text bug. I found a bunch of ugly 77 | # solutions, but this was the simplest one I could figure out. 78 | # 79 | # Basically you have to activate an application that is not Sublime 80 | # then wait and then activate sublime. I picked "Dock" because it 81 | # is always running in the background so it won't screw up your 82 | # command+tab order. The delay of 1/60 of a second is the minimum 83 | # supported by Applescript. 84 | cmd = """ 85 | tell application "System Events" 86 | activate application "Dock" 87 | delay 1/60 88 | activate application "%s" 89 | end tell""" % name 90 | 91 | # For some reason the previous command stopped working on MacOS Big Sur 92 | # 11.1. This is a workaround where we try to switch to another 93 | # application other than "Dock". For whatever reason the delay no longer 94 | # seems to be necessary either. 95 | # 96 | # I will admit this makes no logical sense, and I have no idea what 97 | # even made me try to do this, but it works. 98 | # 99 | # See https://github.com/ccampbell/sublime-goto-window/issues/15 100 | if self.mac_os_version is not None and len( 101 | self.mac_os_version) > 0 and int(self.mac_os_version[0]) >= 11: 102 | 103 | cmd = """ 104 | tell application "System Events" 105 | activate application "System Events" 106 | activate application "%s" 107 | end tell""" % name 108 | 109 | Popen(['/usr/bin/osascript', "-e", cmd], stdout=PIPE, stderr=PIPE) 110 | 111 | # Focus a Sublime window using wmctrl. wmctrl takes the title of the window 112 | # that will be focused, or part of it. 113 | def _linux_focus(self, window_to_move_to): 114 | window_variables = window_to_move_to.extract_variables() 115 | 116 | if 'project_base_name' in window_variables: 117 | window_title = window_variables['project_base_name'] 118 | elif 'folder' in window_variables: 119 | window_title = os.path.basename(window_variables['folder']) 120 | 121 | try: 122 | Popen(["wmctrl", "-a", window_title + ") - Sublime Text"], 123 | stdout=PIPE, stderr=PIPE) 124 | except FileNotFoundError: 125 | msg = "`wmctrl` is required by GotoWindow but was not found on " \ 126 | "your system. Please install it and try again." 127 | sublime.error_message(msg) 128 | 129 | 130 | def _get_current_index(self): 131 | active_window = sublime.active_window() 132 | windows = sublime.windows() 133 | current_index = -1 134 | for i, folder in enumerate(self._get_folders()): 135 | if windows[folder[1]] == active_window: 136 | current_index = i 137 | break 138 | 139 | return current_index 140 | 141 | def _smart_path(self, name): 142 | home = os.getenv('HOME') 143 | if home is not None and name.startswith(home): 144 | name = name.replace(home, '~') 145 | 146 | return name 147 | 148 | def _get_display_name(self, window): 149 | # If we have a sublime-project file in the window then use that to 150 | # represent the window 151 | 152 | # Sublime Text 2 does not have this method 153 | if hasattr(window, 'project_file_name'): 154 | project_file_name = window.project_file_name() 155 | if project_file_name is not None: 156 | project_file_name = project_file_name.replace('.sublime-project', '') 157 | return project_file_name 158 | 159 | folders_in_window = window.folders() 160 | active_view = window.active_view() 161 | 162 | # Otherwise if there are no folders then use the active_view 163 | if len(folders_in_window) == 0 and active_view is not None: 164 | view_path = active_view.file_name() 165 | if view_path: 166 | return view_path 167 | 168 | view_name = active_view.name() 169 | if view_name: 170 | return view_name 171 | 172 | # Otherwise use the first folder we find 173 | for folder in window.folders(): 174 | return folder 175 | 176 | def _get_folders(self): 177 | folders = [] 178 | for i, window in enumerate(sublime.windows()): 179 | display_name = self._get_display_name(window) 180 | if display_name is not None: 181 | folders.append((self._smart_path(display_name), i)) 182 | 183 | return sorted(folders) 184 | -------------------------------------------------------------------------------- /GotoWindow.sublime-commands: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "caption": "GotoWindow: Switch Window", 4 | "command": "goto_window" 5 | } 6 | ] 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2021 Craig Campbell http://craig.is 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sublime Goto Window 2 | 3 | This package allows you to change between open windows in Sublime Text using a 4 | prompt. It is useful if you have a lot of windows open with different projects 5 | in them and you want to switch without having to press `command ~` over and over again. 6 | 7 | ## To Install 8 | 9 | If you are using Sublime Package Control you can press ``command+shift+p``. Then select ``Package Control: Install Package`` and choose ``GotoWindow``. 10 | 11 | Another option is running the following command (this is the OS X version): 12 | 13 | ``` 14 | cd ~/Library/Application\ Support/Sublime\ Text\ 3/Packages 15 | git clone git@github.com:ccampbell/sublime-goto-window.git GotoWindow 16 | ``` 17 | 18 | ### Linux dependencies 19 | 20 | This plugin depends on `wmctrl` being installed on your system. On Debian-based 21 | operating systems (such as Ubuntu), you can get it using `apt-get install wmctrl`. 22 | 23 | ## Usage 24 | 25 | The default keybinding is 26 | 27 | ``` 28 | super + shift + o 29 | ``` 30 | 31 | After that you will see a menu that looks like this containing all your open 32 | windows in Sublime Text: 33 | 34 | ![hyog](https://cloud.githubusercontent.com/assets/259316/9324668/72ee20e8-455a-11e5-9f0d-9b89d19764ea.png) 35 | 36 | Select an item and that's it! 37 | 38 | ## Note 39 | 40 | There is a bug that prevents this from actually working natively using Sublime 41 | Text APIs. See https://github.com/SublimeTextIssues/Core/issues/444 for more 42 | information. 43 | 44 | I haven't been able to test it on Windows, but there are workarounds in place 45 | that seem to work on OS X and Linux. 46 | --------------------------------------------------------------------------------