├── bower ├── __init__.py ├── utils │ ├── __init__.py │ ├── download.py │ ├── api.py │ └── cli.py ├── commands │ ├── __init__.py │ ├── discover.py │ ├── install_dependencies.py │ ├── bowerrc.py │ ├── download_package.py │ └── install.py └── exceptions │ ├── __init__.py │ └── non_clean_exit_error.py ├── .gitignore ├── Bower.sublime-settings ├── Default.sublime-commands ├── Bower.py ├── LICENCE └── README.md /bower/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /bower/utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /bower/commands/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /bower/exceptions/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | .DS_Store -------------------------------------------------------------------------------- /Bower.sublime-settings: -------------------------------------------------------------------------------- 1 | { 2 | "registry": "https://bower.herokuapp.com" 3 | } 4 | -------------------------------------------------------------------------------- /bower/commands/discover.py: -------------------------------------------------------------------------------- 1 | import sublime_plugin 2 | 3 | 4 | class DiscoverPackageCommand(sublime_plugin.WindowCommand): 5 | def run(self): 6 | self.window.run_command('open_url', {'url': 'http://bower.io/search/'}) 7 | -------------------------------------------------------------------------------- /bower/exceptions/non_clean_exit_error.py: -------------------------------------------------------------------------------- 1 | class NonCleanExitError(Exception): 2 | def __init__(self, returncode): 3 | self.returncode = returncode 4 | 5 | def __str__(self): 6 | return repr(self.returncode) 7 | -------------------------------------------------------------------------------- /Default.sublime-commands: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "caption": "Bower: Install", 4 | "command": "install", 5 | "args": {} 6 | }, 7 | { 8 | "caption": "Bower: Discover packages", 9 | "command": "discover_package", 10 | "args": {} 11 | }, 12 | { 13 | "caption": "Bower: Configure project", 14 | "command": "bowerrc", 15 | "args": {} 16 | }, 17 | { 18 | "caption": "Bower: Install dependencies", 19 | "command": "install_dependencies", 20 | "args": {} 21 | } 22 | ] 23 | -------------------------------------------------------------------------------- /bower/utils/download.py: -------------------------------------------------------------------------------- 1 | from threading import Thread 2 | 3 | try: 4 | # ST3 5 | from ..utils.cli import CLI 6 | except ImportError: 7 | # ST2 8 | from bower.utils.cli import CLI 9 | 10 | 11 | class Download(Thread): 12 | def __init__(self, pkg_name, cwd): 13 | self.pkg_name = pkg_name 14 | self.txt = None 15 | self.cwd = cwd 16 | 17 | # Defaults 18 | self.result = None 19 | Thread.__init__(self) 20 | 21 | def run(self): 22 | self.install_package() 23 | 24 | def install_package(self): 25 | command = ['install', self.pkg_name, '--save'] 26 | CLI().execute(command, cwd=self.cwd) 27 | -------------------------------------------------------------------------------- /bower/commands/install_dependencies.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | import sublime_plugin 3 | import json 4 | import os 5 | 6 | try: 7 | # ST3 8 | from ..utils.cli import CLI 9 | except ImportError: 10 | # ST2 11 | from bower.utils.cli import CLI 12 | 13 | class InstallDependenciesCommand(sublime_plugin.WindowCommand): 14 | def config_path(self): 15 | try: 16 | project_file_path = self.window.project_file_name() 17 | return os.path.dirname(project_file_path) 18 | except AttributeError: 19 | return self.window.folders()[0] 20 | 21 | def run(self): 22 | self.install_package() 23 | 24 | def install_package(self): 25 | command = ['install', '--save'] 26 | CLI().execute(command, cwd=self.config_path()) 27 | -------------------------------------------------------------------------------- /Bower.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | import sublime_plugin 3 | 4 | #Internal 5 | try: 6 | # ST3 7 | from .bower.commands.discover import DiscoverPackageCommand 8 | from .bower.commands.install import InstallCommand 9 | from .bower.commands.install_dependencies import InstallDependenciesCommand 10 | from .bower.commands.download_package import DownloadPackageCommand 11 | from .bower.commands.bowerrc import BowerrcCommand 12 | except (ImportError, ValueError): 13 | # ST2 14 | from bower.commands.discover import DiscoverPackageCommand 15 | from bower.commands.install import InstallCommand 16 | from bower.commands.install_dependencies import InstallDependenciesCommand 17 | from bower.commands.download_package import DownloadPackageCommand 18 | from bower.commands.bowerrc import BowerrcCommand 19 | -------------------------------------------------------------------------------- /bower/commands/bowerrc.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | import sublime_plugin 3 | import json 4 | import os 5 | 6 | 7 | class BowerrcCommand(sublime_plugin.WindowCommand): 8 | def project_path(self): 9 | try: 10 | project_file_path = self.window.project_file_name() 11 | return os.path.join(os.path.dirname(project_file_path), '.bowerrc') 12 | except AttributeError: 13 | return os.path.join(self.window.folders()[0], '.bowerrc') 14 | 15 | def run(self): 16 | try: 17 | bowerrc = self.project_path() 18 | 19 | if not os.path.exists(bowerrc): 20 | rc = json.dumps({'directory': 'components'}, indent=2) 21 | 22 | f = open(bowerrc, 'w+') 23 | f.write(rc) 24 | 25 | self.window.open_file(bowerrc) 26 | except IndexError: 27 | sublime.error_message('Oh Dear! I need a directory for file .bowerrc.') -------------------------------------------------------------------------------- /bower/utils/api.py: -------------------------------------------------------------------------------- 1 | import json 2 | import gzip 3 | import sublime 4 | 5 | try: 6 | # ST3 7 | import urllib.request as req 8 | except ImportError: 9 | # ST2 10 | import urllib2 as req 11 | 12 | try: 13 | # ST3 14 | from io import StringIO 15 | except ImportError: 16 | # ST2 17 | from StringIO import StringIO 18 | 19 | 20 | class API(): 21 | def get(self, endpoint, host, *args): 22 | if not host: 23 | host = 'https://bower.herokuapp.com' 24 | 25 | request = req.Request(host + '/' + endpoint) 26 | 27 | try: 28 | response = req.urlopen(request) 29 | except: 30 | sublime.error_message('Unable to connect to ' + host + '/' + endpoint + ". Check your internet connection.") 31 | 32 | responseText = response.read().decode('utf-8', 'replace') 33 | 34 | try: 35 | return json.loads(responseText) 36 | except: 37 | sublime.error_message('Oh Snap! It looks like theres an error with the Bower API.') -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | Copyright © 2013 Ben Schwarz 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /bower/utils/cli.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | import os 3 | import subprocess 4 | 5 | try: 6 | # ST3 7 | from ..exceptions.non_clean_exit_error import NonCleanExitError 8 | except ImportError: 9 | # ST2 10 | from bower.exceptions.non_clean_exit_error import NonCleanExitError 11 | 12 | if os.name == 'nt': 13 | LOCAL_PATH = ';' + os.getenv('APPDATA') + '\\npm' 14 | BINARY_NAME = 'bower.cmd' 15 | else: 16 | LOCAL_PATH = ':/usr/local/bin:/usr/local/sbin:/usr/local/share/npm/bin' 17 | BINARY_NAME = 'bower' 18 | 19 | os.environ['PATH'] += LOCAL_PATH 20 | 21 | 22 | class CLI(): 23 | def find_binary(self): 24 | for dir in os.environ['PATH'].split(os.pathsep): 25 | path = os.path.join(dir, BINARY_NAME) 26 | if os.path.exists(path): 27 | return path 28 | sublime.error_message(BINARY_NAME + ' could not be found in your $PATH. Check the installation guidelines - https://github.com/benschwarz/sublime-bower#installation') 29 | 30 | def execute(self, command, cwd): 31 | binary = self.find_binary() 32 | command.insert(0, binary) 33 | 34 | cflags = 0 35 | 36 | if os.name == 'nt': 37 | cflags = 0x08000000 # Avoid opening of a cmd on Windows 38 | 39 | proc = subprocess.Popen(command, cwd=cwd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, creationflags=cflags) 40 | 41 | output = proc.stdout.read() 42 | returncode = proc.wait() 43 | if returncode != 0: 44 | error = NonCleanExitError(returncode) 45 | error.output = output 46 | raise error 47 | return output 48 | -------------------------------------------------------------------------------- /bower/commands/download_package.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | import sublime_plugin 3 | 4 | try: 5 | # ST3 6 | from ..utils.download import Download 7 | 8 | except ImportError: 9 | # ST2 10 | from bower.utils.download import Download 11 | 12 | 13 | class DownloadPackageCommand(sublime_plugin.TextCommand): 14 | result = None 15 | pkg_name = None 16 | 17 | def run(self, edit, pkg_name, cwd): 18 | self.edit = edit 19 | self.pkg_name = pkg_name 20 | self.cwd = cwd 21 | 22 | threads = [] 23 | thread = Download(pkg_name, cwd) 24 | threads.append(thread) 25 | thread.start() 26 | self.handle_threads(edit, threads) 27 | 28 | def handle_threads(self, edit, threads, offset=0, i=0, dir=1): 29 | status = None 30 | next_threads = [] 31 | for thread in threads: 32 | status = thread.result 33 | if thread.is_alive(): 34 | next_threads.append(thread) 35 | continue 36 | if thread.result is False: 37 | continue 38 | 39 | threads = next_threads 40 | 41 | if len(threads): 42 | # This animates a little activity indicator in the status area 43 | before = i % 8 44 | after = (7) - before 45 | 46 | if not after: 47 | dir = -1 48 | if not before: 49 | dir = 1 50 | 51 | i += dir 52 | sublime.status_message(('Downloading %s [%s=%s]') % (self.pkg_name, ' ' * before, ' ' * after)) 53 | 54 | sublime.set_timeout(lambda: self.handle_threads(edit, threads, offset, i, dir), 100) 55 | return 56 | 57 | if status: 58 | sublime.status_message(('Bower: installed %s') % self.pkg_name) 59 | -------------------------------------------------------------------------------- /bower/commands/install.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | import sublime_plugin 3 | import json 4 | import os 5 | try: 6 | # ST3 7 | from ..utils.api import API 8 | except ImportError: 9 | # ST2 10 | from bower.utils.api import API 11 | 12 | 13 | class InstallCommand(sublime_plugin.WindowCommand): 14 | def get_config_path(self): 15 | try: 16 | project_file_path = self.window.project_file_name() 17 | return os.path.dirname(project_file_path) 18 | except AttributeError: 19 | return self.window.folders()[0] 20 | 21 | def run(self, *args, **kwargs): 22 | self.list_packages() 23 | 24 | def list_packages(self): 25 | self.fileList = [] 26 | registryUrl = self.get_registry_url() 27 | packages = API().get('packages', registryUrl) 28 | packages.reverse() 29 | 30 | for package in packages: 31 | self.fileList.append([package['name'], package['url']]) 32 | self.window.show_quick_panel(self.fileList, self.get_file) 33 | 34 | def get_file(self, index): 35 | if (index > -1): 36 | if not self.window.views(): 37 | self.window.new_file() 38 | 39 | name = self.fileList[index][0] 40 | cwd = self.get_config_path() 41 | self.window.run_command("download_package", {"pkg_name": name, "cwd": cwd}) 42 | 43 | def get_bower_config(self): 44 | path = os.path.join(self.get_config_path(), '.bowerrc') 45 | 46 | if not os.path.exists(path): 47 | return {} 48 | 49 | try: 50 | jsonData = open(path) 51 | return json.load(jsonData) 52 | except: 53 | sublime.error_message('Unable to parse .bowerrc configuration') 54 | 55 | def get_registry_url(self): 56 | config = self.get_bower_config() 57 | 58 | registry = config.get('registry') 59 | if not registry: 60 | return None 61 | if isinstance(registry, str): 62 | return registry 63 | if isinstance(registry, dict): 64 | searchRegistry = registry.get('search') 65 | if isinstance(searchRegistry, str): 66 | return searchRegistry 67 | if isinstance(searchRegistry, list): 68 | return searchRegistry[0] 69 | 70 | return None 71 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bower, for Sublime Text 2 | 3 | This is a plugin for Sublime text, it will allow you to install packages via [Twitter's Bower tool](http://twitter.github.com/bower/). 4 | 5 | Want to learn about the available packages? Check [Bower components](http://sindresorhus.com/bower-components/) 6 | 7 | ## How to use 8 | 9 | Run the command "Bower install" to get a list of packages from the canonical bower repository. 10 | Packages will be installed the current working directory. 11 | 12 | Want to know more about Bower, or this plugin in action? [Checkout my screencast.](http://germanforblack.com/post/46734908388/i-built-a-plugin-for-sublime-text-that-integrates) 13 | 14 | ## Installation 15 | 16 | * Install bower using NPM: `npm install bower -g` 17 | * Ensure that the bower binary is available in your path (type `bower` into your Terminal / Command prompt) 18 | * [Install msysgit](https://github.com/twitter/bower#a-note-for-windows-users) (Windows only) 19 | 20 | Sublime Package Control allows you to easily install or remove sublime-bower (and many other packages) from within the editor. It offers automatically updating packages as well so you no longer need to keep track of changes in sublime-bower. 21 | 22 | * Install Sublime Package Control (if you haven't done so already) from http://wbond.net/sublime_packages/package_control 23 | 24 | * Bring up the command palette (default ctrl+shift+p or cmd+shift+p) and start typing Package Control: Install Package then press return or click on that option to activate it. You will be presented with a new Quick Panel with the list of available packages. (Search for "Bower") 25 | 26 | Alternately, instead of using Package Control, you can manually install sublime-bower (be aware, you'll have to fetch updates yourself): 27 | 28 | On Mac OS X, in your Terminal: 29 | 30 | ```bash 31 | cd ~/Library/Application\ Support/Sublime\ Text\ 2/Packages 32 | git clone git://github.com/benschwarz/sublime-bower.git Bower 33 | ``` 34 | 35 | On Windows, inside a command prompt (cmd.exe): 36 | 37 | ```cmd 38 | cd "%APPDATA%\Sublime Text 2\Packages" 39 | git clone git://github.com/benschwarz/sublime-bower.git Bower 40 | ``` 41 | 42 | ## Platforms 43 | 44 | * Works on Sublime text 2 & 3 45 | * Works on Mac, Linux & Windows 46 | 47 | ## Contributing 48 | 49 | * Check the [issue list](https://github.com/benschwarz/sublime-bower/issues) to find something to help with 50 | * Add any implementation queries, ideas or psudeo code 51 | * Fork the project, work in a topic branch 52 | * Send a pull request 53 | * You the boss now, dawg 54 | 55 | ## Contributors 56 | * [@eonlepapillon](http://github.com/eonlepapillon) - ST3 support 57 | * [@moonpyk](http://github.com/moonpyk) - Windows support 58 | * [@sindresorhus](http://github.com/sindresorhus) - Bower support 59 | * [@jaredwy](http://github.com/jaredwy) - Incredible autocompletions… not in master (yet) 60 | 61 | ## Licence 62 | 63 | [Licenced MIT.](LICENCE) 64 | --------------------------------------------------------------------------------