From: Łukasz Langa Date: Tue, 27 Mar 2018 09:31:51 +0000 (-0700) Subject: First stab at the Vim plugin! X-Git-Url: https://git.madduck.net/etc/vim.git/commitdiff_plain/10bb45c35e8e08215ad9a060aca33be91a98b864 First stab at the Vim plugin! --- diff --git a/README.md b/README.md index 182e264..ac4caa1 100644 --- a/README.md +++ b/README.md @@ -263,8 +263,61 @@ keep it. ## Editor integration -* Visual Studio Code: [joslarson.black-vscode](https://marketplace.visualstudio.com/items?itemName=joslarson.black-vscode) -* Emacs: [proofit404/blacken](https://github.com/proofit404/blacken) +### Emacs + +Use [proofit404/blacken](https://github.com/proofit404/blacken). + + +### Vim + +Commands and shortcuts: + +* `,=` or `:Black` to format the entire file (ranges not supported); +* `:BlackUpgrade` to upgrade *Black* inside the virtualenv; +* `:BlackVersion` to get the current version of *Black* inside the + virtualenv. + +Configuration: +* `g:black_fast` (defaults to `0`) +* `g:black_linelength` (defaults to `88`) +* `g:black_virtualenv` (defaults to `~/.vim/black`) + +To install, copy the plugin from [vim/plugin/black.vim](https://github.com/ambv/black/tree/master/vim/plugin/black.vim). +Let me know if this requires any changes to work with Vim 8's builtin +`packadd`, or Pathogen, or Vundle, and so on. + +This plugin **requires Vim 7.0+ built with Python 3.6+ support**. It +needs Python 3.6 to be able to run *Black* inside the Vim process which +is much faster than calling an external command. + +On first run, the plugin creates its own virtualenv using the right +Python version and automatically installs *Black*. You can upgrade it later +by calling `:BlackUpgrade` and restarting Vim. + +If you need to do anything special to make your virtualenv work and +install *Black* (for example you want to run a version from master), just +create a virtualenv manually and point `g:black_virtualenv` to it. +The plugin will use it. + +**How to get Vim with Python 3.6?** +On Ubuntu 17.10 Vim comes with Python 3.6 by default. +On macOS with HomeBrew run: `brew install vim --with-python3`. +When building Vim from source, use: +`./configure --enable-python3interp=yes`. There's many guides online how +to do this. + + +### Visual Studio Code + +Use [joslarson.black-vscode](https://marketplace.visualstudio.com/items?itemName=joslarson.black-vscode). + + +### Other editors + +Atom/Nuclide integration is planned by the author, others will +require external contributions. + +Patches welcome! ✨ 🍰 ✨ Any tool that can pipe code through *Black* using its stdio mode (just [use `-` as the file name](http://www.tldp.org/LDP/abs/html/special-chars.html#DASHREF2)). @@ -272,10 +325,7 @@ The formatted code will be returned on stdout (unless `--check` was passed). *Black* will still emit messages on stderr but that shouldn't affect your use case. -Vim and Atom/Nuclide integration is planned by the author, others will -require external contributions. - -Patches welcome! ✨ 🍰 ✨ +This can be used for example with PyCharm's [File Watchers](https://www.jetbrains.com/help/pycharm/file-watchers.html). ## Testimonials diff --git a/vim/plugin/black.vim b/vim/plugin/black.vim new file mode 100644 index 0000000..d0afdef --- /dev/null +++ b/vim/plugin/black.vim @@ -0,0 +1,108 @@ +" black.vim +" Author: Łukasz Langa +" Created: Mon Mar 26 23:27:53 2018 -0700 +" Requires: Vim Ver7.0+ +" Version: 1.0 +" +" Documentation: +" This plugin formats Python files. +" +" History: +" 1.0: +" - initial version + +if v:version < 700 || !has('python3') + echo "This script requires vim7.0+ with Python 3.6 support." + finish +endif + +if exists("g:load_black") + finish +endif + +let g:load_black = "py1.0" +if !exists("g:black_virtualenv") + let g:black_virtualenv = "~/.vim/black" +endif +if !exists("g:black_fast") + let g:black_fast = 0 +endif +if !exists("g:black_linelength") + let g:black_linelength = 88 +endif + +python3 << endpython3 +import sys +import vim + +def _initialize_black_env(upgrade=False): + pyver = sys.version_info[:2] + if pyver < (3, 6): + print("Sorry, Black requires Python 3.6+ to run.") + return False + + from pathlib import Path + import subprocess + import venv + virtualenv_path = Path(vim.eval("g:black_virtualenv")).expanduser() + virtualenv_site_packages = str( + virtualenv_path / 'lib' / f'python{pyver[0]}.{pyver[1]}' / 'site-packages' + ) + first_install = False + if not virtualenv_path.is_dir(): + print('Please wait, one time setup for Black.') + _executable = sys.executable + try: + sys.executable = str(Path(sys.exec_prefix) / 'bin' / 'python3') + print(f'Creating a virtualenv in {virtualenv_path}...') + print('(this path can be customized in .vimrc by setting g:black_virtualenv)') + venv.create(virtualenv_path, with_pip=True) + finally: + sys.executable = _executable + first_install = True + if first_install: + print('Installing Black with pip...') + if upgrade: + print('Upgrading Black with pip...') + if first_install or upgrade: + subprocess.run([str(virtualenv_path / 'bin' / 'pip'), 'install', '-U', 'black']) + print('DONE! You are all set, thanks for waiting ✨ 🍰 ✨') + if first_install: + print('Pro-tip: to upgrade Black in the future, use the :BlackUpgrade command and restart Vim.\n') + if sys.path[0] != virtualenv_site_packages: + sys.path.insert(0, virtualenv_site_packages) + return True + +if _initialize_black_env(): + import black + import time + +def Black(): + start = time.time() + fast = bool(int(vim.eval("g:black_fast"))) + line_length = int(vim.eval("g:black_linelength")) + buffer_str = '\n'.join(vim.current.buffer) + '\n' + try: + new_buffer_str = black.format_file_contents(buffer_str, line_length=line_length, fast=fast) + except black.NothingChanged: + print(f'Already well formatted, good job. (took {time.time() - start:.4f}s)') + except Exception as exc: + print(exc) + else: + vim.current.buffer[:] = new_buffer_str.split('\n')[:-1] + print(f'Reformatted in {time.time() - start:.4f}s.') + +def BlackUpgrade(): + _initialize_black_env(upgrade=True) + +def BlackVersion(): + print(f'Black, version {black.__version__} on Python {sys.version}.') + +endpython3 + +command! Black :py3 Black() +command! BlackUpgrade :py3 BlackUpgrade() +command! BlackVersion :py3 BlackVersion() + +nmap ,= :Black +vmap ,= :Black