]> Sergey Matveev's repositories - dotfiles.git/blob - vim/.vim/plugin/defsplit.vim
7beb26bc11949cddc49ebac403d6cbde96d988b7
[dotfiles.git] / vim / .vim / plugin / defsplit.vim
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
4 "
5 " This plugin splits Python function call on several lines.
6 "
7 "   def foobar(self, foo: str, bar: Some[thing, too]) -> None:
8 " to
9 "   def foobar(
10 "           self,
11 "           foo: str,
12 "           bar: Some[thing, too],
13 "   ) -> None:
14 "
15 "   foo(bar, baz)[0]
16 " to
17 "   foo(
18 "       bar,
19 "       baz,
20 "   )[0]
21 "
22 " You can un-split it using :Undefsplit command on the line where
23 " splitting starts.
24 "
25 " :Defsplit has optional argument specifying how many opening round
26 " parenthesis must be skipped.
27 " :Defsplit 1 on foo(baz(baz(...))) produces
28 "    foo(baz(
29 "        baz(...),
30 "    ))
31 "
32 " Also there is :Brsplit command behaving similarly, but it splits other
33 " types of brackets: "{}", "[]".
34
35 if !exists("g:defsplit_shift") | let g:defsplit_shift = "    " | endif
36 if exists('*<SID>Defsplit') | finish | endif
37
38 function! s:bracket_find(brs_allowable, line, offset)
39     let possible = []
40     for bracket in a:brs_allowable
41         let found = stridx(a:line, bracket, a:offset)
42         if found != -1 | let possible += [found] | endif
43     endfor
44     return min(possible)
45 endfunction
46
47 function! s:Defsplit(brs_allowable, single_line_comma, ...)
48     if a:0 == 0 | let skip = 0 | else | let skip = str2nr(a:1) | endif
49     let shift = g:defsplit_shift
50     let line = getline(".")
51     for i in range(len(line))
52         if line[i] != g:defsplit_shift[0]
53             let prfx = strpart(line, 0, i)
54             if line[i : i+3] ==# "def " ||
55                 \line[i : i+5] ==# "class " ||
56                 \line[i : i+9] ==# "async def "
57                 let shift .= shift
58             endif
59             break
60         endif
61     endfor
62     let brs = {"(": ")", "[": "]", "{": "}"}
63     let brfirst = s:bracket_find(a:brs_allowable, line, 0)
64     let brlast = strridx(line, brs[line[brfirst]])
65     while skip > 0
66         let brfirst = s:bracket_find(a:brs_allowable, line, brfirst + 1)
67         let brlast = strridx(line, brs[line[brfirst]], brlast - 1)
68         let skip -= 1
69     endwhile
70     let [curly, round, squar, outbuf] = [0, 0, 0, ""]
71     let ready = [strpart(line, 0, brfirst + 1)]
72     let trailing_comma = 1
73     for c in split(line[brfirst + 1 : brlast-1], '\zs')
74         if c ==# "*" | let trailing_comma = 0 | endif
75         if outbuf ==# "" && c ==# " " | continue | endif
76         let outbuf .= c
77         if c ==# "," && !curly && !round && !squar
78             let ready = add(ready, prfx . shift . outbuf)
79             let outbuf = ""
80         elseif c ==# "[" | let squar += 1
81         elseif c ==# "]" | let squar -= 1
82         elseif c ==# "(" | let round += 1
83         elseif c ==# ")" | let round -= 1
84         elseif c ==# "{" | let curly += 1
85         elseif c ==# "}" | let curly -= 1
86         endif
87     endfor
88     if trailing_comma && !(a:single_line_comma == v:true && len(ready) == 1)
89         let outbuf = outbuf . ","
90     endif
91     let ready = add(ready, prfx . shift . outbuf)
92     let ready = add(ready, prfx . strpart(line, brlast))
93     call append(line("."), ready)
94     normal "_dd
95 endfunction
96
97 command! -nargs=? Defsplit call s:Defsplit(["("], v:false, <f-args>)
98 command! -nargs=? Brsplit call s:Defsplit(["(", "[", "{"], v:false, <f-args>)
99 command! -nargs=? Defsplits call s:Defsplit(["("], v:true, <f-args>)
100 command! -nargs=? Brsplits call s:Defsplit(["(", "[", "{"], v:true, <f-args>)
101
102 command! Undefsplit normal ^v%$J:keepp s/^\(.*\)\([([{]\) \(.*[^,]\),\?\([)\]}]\)\(.*\)$/\1\2\3\4\5<CR>:keepp s/, \?\([)\]}]\+\)$/\1/e<CR>:<CR>