]> git.madduck.net Git - etc/vim.git/blob - autoload/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:

[FIX] migrate-black.py: don't fail on binary files (#3266)
[etc/vim.git] / autoload / black.vim
1 python3 << EndPython3
2 import collections
3 import os
4 import sys
5 import vim
6
7 def strtobool(text):
8   if text.lower() in ['y', 'yes', 't', 'true', 'on', '1']:
9     return True
10   if text.lower() in ['n', 'no', 'f', 'false', 'off', '0']:
11     return False
12   raise ValueError(f"{text} is not convertable to boolean")
13
14 class Flag(collections.namedtuple("FlagBase", "name, cast")):
15   @property
16   def var_name(self):
17     return self.name.replace("-", "_")
18
19   @property
20   def vim_rc_name(self):
21     name = self.var_name
22     if name == "line_length":
23       name = name.replace("_", "")
24     return "g:black_" + name
25
26
27 FLAGS = [
28   Flag(name="line_length", cast=int),
29   Flag(name="fast", cast=strtobool),
30   Flag(name="skip_string_normalization", cast=strtobool),
31   Flag(name="quiet", cast=strtobool),
32   Flag(name="skip_magic_trailing_comma", cast=strtobool),
33   Flag(name="preview", cast=strtobool),
34 ]
35
36
37 def _get_python_binary(exec_prefix):
38   try:
39     default = vim.eval("g:pymode_python").strip()
40   except vim.error:
41     default = ""
42   if default and os.path.exists(default):
43     return default
44   if sys.platform[:3] == "win":
45     return exec_prefix / 'python.exe'
46   return exec_prefix / 'bin' / 'python3'
47
48 def _get_pip(venv_path):
49   if sys.platform[:3] == "win":
50     return venv_path / 'Scripts' / 'pip.exe'
51   return venv_path / 'bin' / 'pip'
52
53 def _get_virtualenv_site_packages(venv_path, pyver):
54   if sys.platform[:3] == "win":
55     return venv_path / 'Lib' / 'site-packages'
56   return venv_path / 'lib' / f'python{pyver[0]}.{pyver[1]}' / 'site-packages'
57
58 def _initialize_black_env(upgrade=False):
59   pyver = sys.version_info[:3]
60   if pyver < (3, 6, 2):
61     print("Sorry, Black requires Python 3.6.2+ to run.")
62     return False
63
64   from pathlib import Path
65   import subprocess
66   import venv
67   virtualenv_path = Path(vim.eval("g:black_virtualenv")).expanduser()
68   virtualenv_site_packages = str(_get_virtualenv_site_packages(virtualenv_path, pyver))
69   first_install = False
70   if not virtualenv_path.is_dir():
71     print('Please wait, one time setup for Black.')
72     _executable = sys.executable
73     _base_executable = getattr(sys, "_base_executable", _executable)
74     try:
75       executable = str(_get_python_binary(Path(sys.exec_prefix)))
76       sys.executable = executable
77       sys._base_executable = executable
78       print(f'Creating a virtualenv in {virtualenv_path}...')
79       print('(this path can be customized in .vimrc by setting g:black_virtualenv)')
80       venv.create(virtualenv_path, with_pip=True)
81     except Exception:
82       print('Encountered exception while creating virtualenv (see traceback below).')
83       print(f'Removing {virtualenv_path}...')
84       import shutil
85       shutil.rmtree(virtualenv_path)
86       raise
87     finally:
88       sys.executable = _executable
89       sys._base_executable = _base_executable
90     first_install = True
91   if first_install:
92     print('Installing Black with pip...')
93   if upgrade:
94     print('Upgrading Black with pip...')
95   if first_install or upgrade:
96     subprocess.run([str(_get_pip(virtualenv_path)), 'install', '-U', 'black'], stdout=subprocess.PIPE)
97     print('DONE! You are all set, thanks for waiting ✨ 🍰 ✨')
98   if first_install:
99     print('Pro-tip: to upgrade Black in the future, use the :BlackUpgrade command and restart Vim.\n')
100   if virtualenv_site_packages not in sys.path:
101     sys.path.insert(0, virtualenv_site_packages)
102   return True
103
104 if _initialize_black_env():
105   import black
106   import time
107
108 def get_target_version(tv):
109   if isinstance(tv, black.TargetVersion):
110     return tv
111   ret = None
112   try:
113     ret = black.TargetVersion[tv.upper()]
114   except KeyError:
115     print(f"WARNING: Target version {tv!r} not recognized by Black, using default target")
116   return ret
117
118 def Black(**kwargs):
119   """
120   kwargs allows you to override ``target_versions`` argument of
121   ``black.FileMode``.
122
123   ``target_version`` needs to be cleaned because ``black.FileMode``
124   expects the ``target_versions`` argument to be a set of TargetVersion enums.
125
126   Allow kwargs["target_version"] to be a string to allow
127   to type it more quickly.
128
129   Using also target_version instead of target_versions to remain
130   consistent to Black's documentation of the structure of pyproject.toml.
131   """
132   start = time.time()
133   configs = get_configs()
134
135   black_kwargs = {}
136   if "target_version" in kwargs:
137     target_version = kwargs["target_version"]
138
139     if not isinstance(target_version, (list, set)):
140       target_version = [target_version]
141     target_version = set(filter(lambda x: x, map(lambda tv: get_target_version(tv), target_version)))
142     black_kwargs["target_versions"] = target_version
143
144   mode = black.FileMode(
145     line_length=configs["line_length"],
146     string_normalization=not configs["skip_string_normalization"],
147     is_pyi=vim.current.buffer.name.endswith('.pyi'),
148     magic_trailing_comma=not configs["skip_magic_trailing_comma"],
149     preview=configs["preview"],
150     **black_kwargs,
151   )
152   quiet = configs["quiet"]
153
154   buffer_str = '\n'.join(vim.current.buffer) + '\n'
155   try:
156     new_buffer_str = black.format_file_contents(
157       buffer_str,
158       fast=configs["fast"],
159       mode=mode,
160     )
161   except black.NothingChanged:
162     if not quiet:
163       print(f'Black: already well formatted, good job. (took {time.time() - start:.4f}s)')
164   except Exception as exc:
165     print(f'Black: {exc}')
166   else:
167     current_buffer = vim.current.window.buffer
168     cursors = []
169     for i, tabpage in enumerate(vim.tabpages):
170       if tabpage.valid:
171         for j, window in enumerate(tabpage.windows):
172           if window.valid and window.buffer == current_buffer:
173             cursors.append((i, j, window.cursor))
174     vim.current.buffer[:] = new_buffer_str.split('\n')[:-1]
175     for i, j, cursor in cursors:
176       window = vim.tabpages[i].windows[j]
177       try:
178         window.cursor = cursor
179       except vim.error:
180         window.cursor = (len(window.buffer), 0)
181     if not quiet:
182       print(f'Black: reformatted in {time.time() - start:.4f}s.')
183
184 def get_configs():
185   filename = vim.eval("@%")
186   path_pyproject_toml = black.find_pyproject_toml((filename,))
187   if path_pyproject_toml:
188     toml_config = black.parse_pyproject_toml(path_pyproject_toml)
189   else:
190     toml_config = {}
191
192   return {
193     flag.var_name: toml_config.get(flag.name, flag.cast(vim.eval(flag.vim_rc_name)))
194     for flag in FLAGS
195   }
196
197
198 def BlackUpgrade():
199   _initialize_black_env(upgrade=True)
200
201 def BlackVersion():
202   print(f'Black, version {black.__version__} on Python {sys.version}.')
203
204 EndPython3
205
206 function black#Black(...)
207     let kwargs = {}
208     for arg in a:000
209         let arg_list = split(arg, '=')
210         let kwargs[arg_list[0]] = arg_list[1]
211     endfor
212 python3 << EOF
213 import vim
214 kwargs = vim.eval("kwargs")
215 EOF
216   :py3 Black(**kwargs)
217 endfunction
218
219 function black#BlackUpgrade()
220   :py3 BlackUpgrade()
221 endfunction
222
223 function black#BlackVersion()
224   :py3 BlackVersion()
225 endfunction