|
| 1 | +# This file is a minimal swift-format vim-integration. To install: |
| 2 | +# - Change 'binary' if swift-format is not on the path (see below). |
| 3 | +# - Add to your .vimrc: |
| 4 | +# |
| 5 | +# map <C-I> :pyf <path-to-this-file>/swift-format.py<cr> |
| 6 | +# imap <C-I> <c-o>:pyf <path-to-this-file>/swift-format.py<cr> |
| 7 | +# |
| 8 | +# The first line enables swift-format for NORMAL and VISUAL mode, the second |
| 9 | +# line adds support for INSERT mode. Change "C-I" to another binding if you |
| 10 | +# need swift-format on a different key (C-I stands for Ctrl+i). |
| 11 | +# |
| 12 | +# With this integration you can press the bound key and swift-format will |
| 13 | +# format the current line in NORMAL and INSERT mode or the selected region in |
| 14 | +# VISUAL mode. The line or region is extended to the next bigger syntactic |
| 15 | +# entity. |
| 16 | +# |
| 17 | +# You can also pass in the variable "l:lines" to choose the range for |
| 18 | +# formatting. This variable can either contain "<start line>:<end line> or |
| 19 | +# "all" to format the full file. So, to format the full file, write a function |
| 20 | +# like: |
| 21 | +# |
| 22 | +# :function FormatFile() |
| 23 | +# : let l:lines="all" |
| 24 | +# : pyf <path-to-this-file>/swift-format.py |
| 25 | +# :endfunction |
| 26 | +# |
| 27 | +# It operates on the current, potentially unsaved buffer and does not create or |
| 28 | +# save any files. To revert a formatting, just undo. |
| 29 | + |
| 30 | +from __future__ import print_function |
| 31 | + |
| 32 | +import difflib |
| 33 | +import platform |
| 34 | +import subprocess |
| 35 | +import sys |
| 36 | +import vim |
| 37 | + |
| 38 | +binary = 'swift-format' |
| 39 | +if vim.eval('exists("g:swift_format_path")') == "1": |
| 40 | + binary = vim.eval('g:swift_format_path') |
| 41 | + |
| 42 | + |
| 43 | +def get_buffer(encoding): |
| 44 | + if platform.python_version_tuple()[0] == "3": |
| 45 | + return vim.current.buffer |
| 46 | + return [line.decode(encoding) for line in vim.current.buffer] |
| 47 | + |
| 48 | + |
| 49 | +def main(argc, argv): |
| 50 | + encoding = vim.eval("&encoding") |
| 51 | + buf = get_buffer(encoding) |
| 52 | + |
| 53 | + if vim.eval('exists("l:lines")') == '1': |
| 54 | + lines = vim.eval('l:lines') |
| 55 | + else: |
| 56 | + lines = '%s:%s' % (vim.current.range.start + 1, |
| 57 | + vim.current.range.end + 1) |
| 58 | + |
| 59 | + cursor = int(vim.eval('line2byte(line(".")) + col(".")')) - 2 |
| 60 | + if cursor < 0: |
| 61 | + print("Couldn't determine cursor position. Is your file empty?") |
| 62 | + return |
| 63 | + |
| 64 | + # avoid the cmd prompt on windows |
| 65 | + SI = None |
| 66 | + if sys.platform.startswith('win32'): |
| 67 | + SI = subprocess.STARTUPINFO() |
| 68 | + SI.dwFlags |= subprocess.STARTF_USESHOWWINDOW |
| 69 | + SI.wShowWindow = subprocess.SW_HIDE |
| 70 | + |
| 71 | + command = [binary] |
| 72 | + if lines != 'all': |
| 73 | + command.extend(['-line-range', lines]) |
| 74 | + |
| 75 | + p = subprocess.Popen(command, |
| 76 | + stdout=subprocess.PIPE, stderr=subprocess.PIPE, |
| 77 | + stdin=subprocess.PIPE, startupinfo=SI) |
| 78 | + stdout, stderr = p.communicate(input='\n'.join(buf).encode(encoding)) |
| 79 | + |
| 80 | + if stderr: |
| 81 | + print(stderr) |
| 82 | + |
| 83 | + if not stdout: |
| 84 | + print('No output from swift-format (crashed?).') |
| 85 | + return |
| 86 | + |
| 87 | + lines = stdout.decode(encoding).split('\n') |
| 88 | + sequence = difflib.SequenceMatcher(None, buf, lines) |
| 89 | + for op in reversed(sequence.get_opcodes()): |
| 90 | + if op[0] is not 'equal': |
| 91 | + vim.current.buffer[op[1]:op[2]] = lines[op[3]:op[4]] |
| 92 | + |
| 93 | +if __name__ == '__main__': |
| 94 | + main(len(sys.argv), sys.argv) |
0 commit comments