]> git.madduck.net Git - etc/vim.git/blob - plugin/black.vim

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

29b2992448739aa9fe4d2ed2e6960244ee69882f
[etc/vim.git] / plugin / black.vim
1 " black.vim
2 " Author: Łukasz Langa
3 " Created: Mon Mar 26 23:27:53 2018 -0700
4 " Requires: Vim Ver7.0+
5 " Version:  1.1
6 "
7 " Documentation:
8 "   This plugin formats Python files.
9 "
10 " History:
11 "  1.0:
12 "    - initial version
13 "  1.1:
14 "    - restore cursor/window position after formatting
15
16 if v:version < 700 || !has('python3')
17     echo "This script requires vim7.0+ with Python 3.6 support."
18     finish
19 endif
20
21 if exists("g:load_black")
22    finish
23 endif
24
25 let g:load_black = "py1.0"
26 if !exists("g:black_virtualenv")
27   let g:black_virtualenv = "~/.vim/black"
28 endif
29 if !exists("g:black_fast")
30   let g:black_fast = 0
31 endif
32 if !exists("g:black_linelength")
33   let g:black_linelength = 88
34 endif
35 if !exists("g:black_skip_string_normalization")
36   let g:black_skip_string_normalization = 0
37 endif
38
39 python3 << endpython3
40 import os
41 import sys
42 import vim
43
44 def _get_python_binary(exec_prefix):
45   try:
46     default = vim.eval("g:pymode_python").strip()
47   except vim.error:
48     default = ""
49   if default and os.path.exists(default):
50     return default
51   if sys.platform[:3] == "win":
52     return exec_prefix / 'python.exe'
53   return exec_prefix / 'bin' / 'python3'
54
55 def _get_pip(venv_path):
56   if sys.platform[:3] == "win":
57     return venv_path / 'Scripts' / 'pip.exe'
58   return venv_path / 'bin' / 'pip'
59
60 def _get_virtualenv_site_packages(venv_path, pyver):
61   if sys.platform[:3] == "win":
62     return venv_path / 'Lib' / 'site-packages'
63   return venv_path / 'lib' / f'python{pyver[0]}.{pyver[1]}' / 'site-packages'
64
65 def _initialize_black_env(upgrade=False):
66   pyver = sys.version_info[:2]
67   if pyver < (3, 6):
68     print("Sorry, Black requires Python 3.6+ to run.")
69     return False
70
71   from pathlib import Path
72   import subprocess
73   import venv
74   virtualenv_path = Path(vim.eval("g:black_virtualenv")).expanduser()
75   virtualenv_site_packages = str(_get_virtualenv_site_packages(virtualenv_path, pyver))
76   first_install = False
77   if not virtualenv_path.is_dir():
78     print('Please wait, one time setup for Black.')
79     _executable = sys.executable
80     try:
81       sys.executable = str(_get_python_binary(Path(sys.exec_prefix)))
82       print(f'Creating a virtualenv in {virtualenv_path}...')
83       print('(this path can be customized in .vimrc by setting g:black_virtualenv)')
84       venv.create(virtualenv_path, with_pip=True)
85     finally:
86       sys.executable = _executable
87     first_install = True
88   if first_install:
89     print('Installing Black with pip...')
90   if upgrade:
91     print('Upgrading Black with pip...')
92   if first_install or upgrade:
93     subprocess.run([str(_get_pip(virtualenv_path)), 'install', '-U', 'black'], stdout=subprocess.PIPE)
94     print('DONE! You are all set, thanks for waiting ✨ 🍰 ✨')
95   if first_install:
96     print('Pro-tip: to upgrade Black in the future, use the :BlackUpgrade command and restart Vim.\n')
97   if sys.path[0] != virtualenv_site_packages:
98     sys.path.insert(0, virtualenv_site_packages)
99   return True
100
101 if _initialize_black_env():
102   import black
103   import time
104
105 def Black():
106   start = time.time()
107   fast = bool(int(vim.eval("g:black_fast")))
108   mode = black.FileMode(
109     line_length=int(vim.eval("g:black_linelength")),
110     string_normalization=not bool(int(vim.eval("g:black_skip_string_normalization"))),
111     is_pyi=vim.current.buffer.name.endswith('.pyi'),
112   )
113   (cursor_line, cursor_column) = vim.current.window.cursor
114   cb = vim.current.buffer[:]
115   cb_bc = cb[0:cursor_line]
116   # Format all code before the cursor.
117   # Detect unclosed blocks, close them with pass.
118   last_line = cb_bc[-1]
119   if last_line.rstrip().endswith(":"):
120       cb_bc[-1] = last_line + " pass"
121   # Determine old:new cursor location mapping
122   buffer_str_before = '\n'.join(cb_bc)+'\n'
123   try:
124     new_buffer_str_before = black.format_file_contents(buffer_str_before, fast=fast, mode=mode)
125     new_cb = new_buffer_str_before.split('\n')[:-1]
126     new_cursor_line = len(new_cb)
127     new_cursor = (new_cursor_line, cursor_column)
128   except black.NothingChanged:
129     new_cursor_line = cursor_line
130     new_cursor = (new_cursor_line, cursor_column)
131   except Exception as exc:
132     print(exc)
133   # Now we know where the cursor should be
134   # when we format the entire buffer. Do it:
135   buffer_str = '\n'.join(cb) + '\n'
136   try:
137     new_buffer_str = black.format_file_contents(buffer_str, fast=fast, mode=mode)
138   except black.NothingChanged:
139     print(f'Already well formatted, good job. (took {time.time() - start:.4f}s)')
140   except Exception as exc:
141     print(exc)
142   else:
143     # Replace the buffer
144     new_cb = new_buffer_str.split('\n')[:-1]
145     vim.current.buffer[:] = new_cb
146     # Restore the cursor to its rightful place
147     try:
148       vim.current.window.cursor = new_cursor
149     except vim.error:
150       vim.current.window.cursor = (len(vim.current.buffer), 0)
151     print(f'Reformatted in {time.time() - start:.4f}s.')
152
153 def BlackUpgrade():
154   _initialize_black_env(upgrade=True)
155
156 def BlackVersion():
157   print(f'Black, version {black.__version__} on Python {sys.version}.')
158
159 endpython3
160
161 command! Black :py3 Black()
162 command! BlackUpgrade :py3 BlackUpgrade()
163 command! BlackVersion :py3 BlackVersion()