├── .gitignore ├── Default (Linux).sublime-keymap ├── Default (OSX).sublime-keymap ├── Default (Windows).sublime-keymap ├── Default.sublime-commands ├── Main.sublime-menu ├── README.md ├── SublimeFiles.sublime-settings ├── messages.json └── sublime_files.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | SublimeFiles.sublime-project 3 | SublimeFiles.sublime-workspace 4 | -------------------------------------------------------------------------------- /Default (Linux).sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "keys": ["ctrl+alt+n"], 4 | "command": "sublime_files", 5 | "args": {"command": "navigate"} 6 | } 7 | ] -------------------------------------------------------------------------------- /Default (OSX).sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "keys": ["ctrl+super+n"], 4 | "command": "sublime_files", 5 | "args": {"command": "navigate"} 6 | } 7 | ] -------------------------------------------------------------------------------- /Default (Windows).sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "keys": ["ctrl+alt+n"], 4 | "command": "sublime_files", 5 | "args": {"command": "navigate"} 6 | } 7 | ] -------------------------------------------------------------------------------- /Default.sublime-commands: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "caption": "Sublime Files: Open Navigator", 4 | "command": "sublime_files", 5 | "args": {"command": "navigate"} 6 | } 7 | ] 8 | -------------------------------------------------------------------------------- /Main.sublime-menu: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "caption": "Preferences", 4 | "mnemonic": "n", 5 | "id": "preferences", 6 | "children": 7 | [ 8 | { 9 | "caption": "Package Settings", 10 | "mnemonic": "P", 11 | "id": "package-settings", 12 | "children": 13 | [ 14 | { 15 | "caption": "Sublime Files", 16 | "children": 17 | [ 18 | { 19 | "command": "open_file", 20 | "args": {"file": "${packages}/SublimeFiles/SublimeFiles.sublime-settings"}, 21 | "caption": "Settings – Default" 22 | }, 23 | { 24 | "command": "open_file", 25 | "args": {"file": "${packages}/User/SublimeFiles.sublime-settings"}, 26 | "caption": "Settings – User" 27 | }, 28 | { 29 | "command": "open_file", 30 | "args": { 31 | "file": "${packages}/SublimeFiles/Default (Windows).sublime-keymap", 32 | "platform": "Windows" 33 | }, 34 | "caption": "Key Bindings – Default" 35 | }, 36 | { 37 | "command": "open_file", 38 | "args": { 39 | "file": "${packages}/SublimeFiles/Default (OSX).sublime-keymap", 40 | "platform": "OSX" 41 | }, 42 | "caption": "Key Bindings – Default" 43 | }, 44 | { 45 | "command": "open_file", 46 | "args": { 47 | "file": "${packages}/SublimeFiles/Default (Linux).sublime-keymap", 48 | "platform": "Linux" 49 | }, 50 | "caption": "Key Bindings – Default" 51 | }, 52 | { 53 | "command": "open_file", 54 | "args": { 55 | "file": "${packages}/User/Default (Windows).sublime-keymap", 56 | "platform": "Windows" 57 | }, 58 | "caption": "Key Bindings – User" 59 | }, 60 | { 61 | "command": "open_file", 62 | "args": { 63 | "file": "${packages}/User/Default (OSX).sublime-keymap", 64 | "platform": "OSX" 65 | }, 66 | "caption": "Key Bindings – User" 67 | }, 68 | { 69 | "command": "open_file", 70 | "args": { 71 | "file": "${packages}/User/Default (Linux).sublime-keymap", 72 | "platform": "Linux" 73 | }, 74 | "caption": "Key Bindings – User" 75 | }, 76 | { "caption": "-" } 77 | ] 78 | } 79 | ] 80 | } 81 | ] 82 | } 83 | ] 84 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Sublime Files 2 | ============= 3 | 4 | A keyboard driven file navigation/opening plugin for Sublime Text 2/3. 5 | 6 | ![Plugin in action](http://i.imgur.com/grlinzi.gif) 7 | 8 | Sublime Files works entirely through the command palette. By running the Sublime Files Navigator, you can "`cd`" around directories similar to how you would on a command line in order to open up files. New files will open up in new tabs. 9 | 10 | Because Sublime Files actually navigates the file system by changing directories, the navigator remembers and starts from last visited directory on subsequent uses. To open the navigator, you can either just invoke the *Command Palette...* command or use the keybinding: 11 | - OSX: `ctrl + cmd + n` 12 | - Windows/Linux: `ctrl + alt + n` 13 | 14 | Installation 15 | ------------ 16 | 17 | Sublime Files can be installed through Sublime Package Control. 18 | 19 | Usage 20 | ----- 21 | 22 | Sublime files an be activated with the *Command Palette...* command: *Sublime Files: Open Navigator*, or with the key command `ctrl + cmd + n` (or `ctrl + alt + n` for Windows / Linux). The first option will always show the current directory. Selecting another directory will navigate to that directory and selecting a file will open that file. 23 | 24 | There are a few notable options: 25 | 26 | - Selecting *Directory actions* will pop up a small list of actions that can be applied onto the current directory. Mainly, a user can create new files, add the directory to the current project, and open a terminal at the directory. 27 | - Selecting *~/* navigates to the home directory. 28 | - Selecting *../* navigates to the parent directory. 29 | - Selecting *To current view* navigates to the directory of the current file being edited. 30 | 31 | Configuration 32 | ------------- 33 | 34 | Default configuration is stored in `SublimeFiles.sublime-settings` accessible from _Preferences->Package Settings->Sublime Files->Settings - Default_. When changing any of the settings below it's suggested to use the user settings: _Preferences->Package Settings->Sublime Files->Settings - User_ as the file will remain untouched when updating plugin. 35 | 36 | __Ignore file types__ 37 | 38 | Sublime Files by default will ignore `*.pyc` files and `*.class` files. You can modify the list of ignored files by changing the `ignore_list`. For example: 39 | 40 | { 41 | "ignore_list": ["*.pyc", "*.class", "*.o"] 42 | } 43 | 44 | __Open Terminal__ 45 | 46 | For OS X/Linux systems, Sublime Files can open up a terminal at the current directory navigated to. In order for this feature to work properly, you will have to modify the `term_command`. As a default, it is set to open up Terminal.app for OS X systems. 47 | 48 | For example, Gnome Terminal and iTerm2 users respectively will want to change `term_command` to: 49 | 50 | { 51 | "term_command": "gnome-terminal --working-directory=" 52 | } 53 | 54 | and 55 | 56 | { 57 | "term_command" : "open -a iTerm\ 2 " 58 | } 59 | 60 | __Start directory__ 61 | 62 | If you _always_ want to start navigation from a given directory for example `~` just update the `start_directory` setting: 63 | 64 | { 65 | "start_directory": "~" 66 | } 67 | 68 | Default configuration comes with this setting turned off (set to `null`). 69 | -------------------------------------------------------------------------------- /SublimeFiles.sublime-settings: -------------------------------------------------------------------------------- 1 | { 2 | // The command to execute to open a terminal. 3 | // Program will append the directory to open to the end of term_command. 4 | "term_command": "open -a Terminal ", 5 | 6 | // List of Unix shell-style wildcard matches for file types to 7 | // ignore when listing files in the navigator. 8 | // By default, ignores *.pyc and *.class files. 9 | "ignore_list": ["*.pyc", "*.class"], 10 | 11 | // If provided, will always start navigation from given directory. 12 | // Use "~" to point to home directory, null to disable. 13 | "start_directory": null 14 | } 15 | -------------------------------------------------------------------------------- /messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "install": "README.md" 3 | } 4 | -------------------------------------------------------------------------------- /sublime_files.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import glob 4 | import shlex 5 | import sublime 6 | import sublime_plugin 7 | from fnmatch import fnmatch 8 | from subprocess import Popen 9 | 10 | bullet = u'\u2022' 11 | 12 | 13 | class SublimeFilesCommand(sublime_plugin.WindowCommand): 14 | 15 | def getcwd(self): 16 | try: 17 | if running_in_st3(): 18 | return os.getcwd() 19 | else: 20 | return os.getcwdu() 21 | except OSError: 22 | os.chdir(os.getenv(self.home)) 23 | return self.getcwd() 24 | 25 | def show_quick_panel(self, elements, on_selection, params): 26 | sublime.set_timeout(lambda: self.window.show_quick_panel(elements, on_selection, params), 10) 27 | 28 | def run(self, command): 29 | try: 30 | self.home 31 | except: 32 | self.current_dir = "" 33 | # first time starting up. ugly, but wosrks 34 | settings = sublime.load_settings('SublimeFiles.sublime-settings') 35 | if os.name == 'nt': 36 | self.home = 'USERPROFILE' 37 | else: 38 | self.home = 'HOME' 39 | self.project_root = None 40 | self.bookmark = None 41 | self.term_command = settings.get('term_command') 42 | self.ignore_list = settings.get('ignore_list') 43 | self.start_directory = settings.get('start_directory') 44 | if self.start_directory is not None: 45 | self.start_directory = os.path.abspath(os.path.expanduser(self.start_directory)) 46 | if not os.path.exists(self.start_directory): 47 | print ('SublimeFiles: "start_directory" points to invalid path, ignoring.') 48 | self.start_directory = None 49 | self.drives = [] # for windows machines 50 | 51 | if command == 'navigate': 52 | if self.start_directory is not None: 53 | os.chdir(self.start_directory) 54 | 55 | self.open_navigator() 56 | 57 | # function for showing panel for changing directories / opening files 58 | def open_navigator(self): 59 | if self.start_directory is None: 60 | self.check_project_root() 61 | self.current_dir = self.getcwd() 62 | self.dir_files = ['[' + self.getcwd() + ']', 63 | bullet + ' Directory actions', '..' + os.sep, '~' + os.sep] 64 | 65 | # annoying way to deal with windows 66 | if sublime.platform() == 'windows': 67 | if len(self.drives) == 0: 68 | for i in range(ord('A'), ord('Z') + 1): 69 | drive = chr(i) 70 | if (os.path.exists(drive + ':\\')): 71 | self.drives.append(drive + ':\\') 72 | self.dir_files += self.drives 73 | 74 | for element in os.listdir(self.getcwd()): 75 | ignore_element = False 76 | for ignore_pattern in self.ignore_list: 77 | if fnmatch(element, ignore_pattern): 78 | ignore_element = True 79 | break 80 | if not ignore_element: 81 | fullpath = os.path.join(self.getcwd(), element) 82 | if os.path.isdir(fullpath): 83 | self.dir_files.append(element + os.sep) 84 | else: 85 | self.dir_files.append(element) 86 | 87 | self.dir_files = self.dir_files[:4] + sorted(self.dir_files[4:], key=sort_files) 88 | 89 | if self.bookmark: 90 | self.dir_files.insert(2, bullet + ' To bookmark (' + self.bookmark + ')') 91 | if self.window.active_view() and self.window.active_view().file_name(): 92 | self.dir_files.insert(2, bullet + ' To current view') 93 | 94 | self.show_quick_panel(self.dir_files, self.handle_navigator_option, sublime.MONOSPACE_FONT) 95 | 96 | # checks if the user has opened up a folder, and if so automatically navigate to the root 97 | def check_project_root(self): 98 | folders = self.window.folders() 99 | if len(folders) > 0: 100 | # If not one yet present or if has changed 101 | if not self.project_root or self.project_root != folders[0]: 102 | self.project_root = folders[0] 103 | os.chdir(self.project_root) 104 | elif self.project_root: 105 | # if folders is empty now and we had a root, let's clear it out 106 | self.project_root = None 107 | 108 | # handles user's selection from open_navigator 109 | def handle_navigator_option(self, call_value): 110 | os.chdir(self.current_dir) 111 | if call_value != -1: 112 | option = self.dir_files[call_value] 113 | if call_value == 0: 114 | self.open_navigator() 115 | elif call_value == 1: 116 | self.open_directory_options() 117 | elif option == '~' + os.sep: 118 | os.chdir(os.getenv(self.home)) 119 | elif option == '..' + os.sep: 120 | os.chdir(os.path.pardir) 121 | elif sublime.platform() == 'windows' and option in self.drives: 122 | os.chdir(option) 123 | elif option == bullet + ' To current view': 124 | os.chdir(os.path.dirname(self.window.active_view().file_name())) 125 | elif option.startswith(bullet + ' To bookmark'): 126 | os.chdir(self.bookmark) 127 | else: 128 | fullpath = os.path.join(self.getcwd(), self.dir_files[call_value]) 129 | if os.path.isdir(fullpath): # navigate to directory 130 | os.chdir(self.dir_files[call_value]) 131 | else: # open file 132 | self.window.open_file(os.path.join(self.getcwd(), fullpath)) 133 | return 134 | self.open_navigator() 135 | 136 | # options for when a user selects current directory 137 | def open_directory_options(self): 138 | self.directory_options = [bullet + ' Add folder to project', bullet + ' Create new file', 139 | bullet + ' Create new directory', bullet + ' Set bookmark here', bullet + ' Navigate to specific directory', bullet + ' Back'] 140 | # terminal opening. only for osx/linux right now 141 | if os.name == 'posix' and self.term_command: 142 | self.directory_options.insert(0, bullet + ' Open terminal here') 143 | self.show_quick_panel(self.directory_options, self.handle_directory_option, sublime.MONOSPACE_FONT) 144 | 145 | # handle choice for when user selects option from current directory 146 | def handle_directory_option(self, call_value): 147 | if call_value != -1: 148 | selection = self.directory_options[call_value] 149 | if selection == bullet + ' Create new file': 150 | self.window.show_input_panel('File name: ', '', self.handle_new_file, None, None) 151 | elif selection == bullet + ' Back': 152 | self.open_navigator() 153 | elif selection == bullet + ' Set bookmark here': 154 | self.bookmark = self.getcwd() 155 | self.open_navigator() 156 | elif selection == bullet + ' Open terminal here': 157 | command = shlex.split(str(self.term_command)) 158 | command.append(self.getcwd()) 159 | try: 160 | Popen(command) 161 | except: 162 | sublime.error_message('Unable to open terminal') 163 | elif selection == bullet + ' Add folder to project': 164 | sublime_command_line(['-a', self.getcwd()]) 165 | elif selection == bullet + ' Create new directory': 166 | self.window.show_input_panel('Directory name: ', '', self.handle_new_directory, None, None) 167 | elif selection == bullet + ' Navigate to specific directory': 168 | self.window.show_input_panel("Navigate to: ", self.getcwd(), self.handle_cwd, None, None) 169 | 170 | def handle_new_file(self, file_name): 171 | if os.path.isfile(self.getcwd() + os.sep + file_name): 172 | sublime.error_message(file_name + ' already exists') 173 | return 174 | if os.path.isdir(self.getcwd() + os.sep + file_name): 175 | sublime.error_message(file_name + ' is already a directory') 176 | return 177 | FILE = open(self.getcwd() + os.sep + file_name, 'a') 178 | FILE.close() 179 | self.window.open_file(self.getcwd() + os.sep + file_name) 180 | 181 | def handle_new_directory(self, dir_name): 182 | if os.path.isfile(self.getcwd() + os.sep + dir_name): 183 | sublime.error_message(dir_name + ' is already a file') 184 | return 185 | if os.path.isdir(self.getcwd() + os.sep + dir_name): 186 | sublime.error_message(dir_name + ' already exists') 187 | return 188 | os.makedirs(self.getcwd() + os.sep + dir_name) 189 | 190 | def handle_cwd(self, new_dir): 191 | try: 192 | if new_dir[0] == "~": 193 | new_dir = os.getenv(self.home) + new_dir[1:] 194 | os.chdir(new_dir) 195 | except: 196 | sublime.error_message(new_dir + " does not exist") 197 | 198 | 199 | def running_in_st3(): 200 | return int(sublime.version()) >= 3000 201 | 202 | 203 | def sort_files(filename): 204 | total_weight = 0 205 | if filename[0] == '.': 206 | total_weight += 2 207 | if filename[-1] == os.sep: 208 | total_weight += 1 209 | return total_weight 210 | 211 | 212 | # hack to add folders to sidebar (stolen from wbond) 213 | def get_sublime_path(): 214 | if sublime.platform() == 'osx': 215 | if running_in_st3(): 216 | return '/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl' 217 | else: 218 | return '/Applications/Sublime Text 2.app/Contents/SharedSupport/bin/subl' 219 | elif sublime.platform() == 'linux': 220 | if running_in_st3(): 221 | return open('/proc/' + str(os.getppid()) + '/cmdline').read().split(chr(0))[0] 222 | else: 223 | return open('/proc/self/cmdline').read().split(chr(0))[0] 224 | else: 225 | if running_in_st3(): 226 | return os.path.join(sys.path[0], 'sublime_text.exe') 227 | else: 228 | return sys.executable 229 | 230 | 231 | def sublime_command_line(args): 232 | args.insert(0, get_sublime_path()) 233 | return Popen(args) 234 | --------------------------------------------------------------------------------