1 " Python function call splitter
2 " Maintainer: Sergey Matveev <stargrave@stargrave.org>
3 " License: GNU General Public License version 3 of the License or later
5 " This plugin splits Python function call on several lines.
7 " def foobar(self, foo: str, bar: Some[thing, too]) -> None:
12 " bar: Some[thing, too],
22 " You can un-split it using :Undefsplit command on the line where
25 " :Defsplit has optional argument specifying how many opening round
26 " parenthesis must be skipped.
27 " :Defsplit 1 on foo(baz(baz(...))) produces
32 " Also there is :Brsplit command behaving similarly, but it splits other
33 " types of brackets: "{}", "[]".
35 if exists("g:loaded_defsplit") | finish | endif
36 let g:loaded_defsplit = 1
37 if !exists("g:defsplit_shift") | let g:defsplit_shift = " " | endif
39 function! s:bracket_find(brs_allowable, line, offset)
41 for bracket in a:brs_allowable
42 let found = stridx(a:line, bracket, a:offset)
43 if found != -1 | let possible += [found] | endif
48 function! s:defsplit(brs_allowable, single_line_comma, ...)
49 if a:0 == 0 | let skip = 0 | else | let skip = str2nr(a:1) | endif
50 let shift = g:defsplit_shift
51 let line = getline(".")
52 for i in range(len(line))
53 if line[i] != g:defsplit_shift[0]
54 let prfx = strpart(line, 0, i)
55 if line[i : i+3] ==# "def " ||
56 \line[i : i+5] ==# "class " ||
57 \line[i : i+9] ==# "async def "
63 let brs = {"(": ")", "[": "]", "{": "}"}
64 let brfirst = s:bracket_find(a:brs_allowable, line, 0)
65 let brlast = strridx(line, brs[line[brfirst]])
67 let brfirst = s:bracket_find(a:brs_allowable, line, brfirst + 1)
68 let brlast = strridx(line, brs[line[brfirst]], brlast - 1)
71 let [curly, round, squar, outbuf] = [0, 0, 0, ""]
72 let ready = [strpart(line, 0, brfirst + 1)]
73 let trailing_comma = 1
74 for c in split(line[brfirst + 1 : brlast-1], '\zs')
75 if c ==# "*" | let trailing_comma = 0 | endif
76 if outbuf ==# "" && c ==# " " | continue | endif
78 if c ==# "," && !curly && !round && !squar
79 let ready = add(ready, prfx . shift . outbuf)
81 elseif c ==# "[" | let squar += 1
82 elseif c ==# "]" | let squar -= 1
83 elseif c ==# "(" | let round += 1
84 elseif c ==# ")" | let round -= 1
85 elseif c ==# "{" | let curly += 1
86 elseif c ==# "}" | let curly -= 1
89 if trailing_comma && !(a:single_line_comma == v:true && len(ready) == 1)
90 let outbuf = outbuf . ","
92 let ready = add(ready, prfx . shift . outbuf)
93 let ready = add(ready, prfx . strpart(line, brlast))
94 call append(line("."), ready)
98 command! -nargs=? Defsplit call s:defsplit(["("], v:false, <f-args>)
99 command! -nargs=? Brsplit call s:defsplit(["(", "[", "{"], v:false, <f-args>)
100 command! -nargs=? Defsplits call s:defsplit(["("], v:true, <f-args>)
101 command! -nargs=? Brsplits call s:defsplit(["(", "[", "{"], v:true, <f-args>)
103 command! Undefsplit normal ^v%$J:keepp s/^\(.*\)\([([{]\) \(.*[^,]\),\?\([)\]}]\)\(.*\)$/\1\2\3\4\5<CR>:keepp s/, \?\([)\]}]\+\)$/\1/e<CR>:<CR>