]> Sergey Matveev's repositories - dotfiles.git/blobdiff - vim/.vim/autoload/defsplit.vim
Vim scripts refactoring
[dotfiles.git] / vim / .vim / autoload / defsplit.vim
diff --git a/vim/.vim/autoload/defsplit.vim b/vim/.vim/autoload/defsplit.vim
new file mode 100644 (file)
index 0000000..a159007
--- /dev/null
@@ -0,0 +1,92 @@
+" Python function call splitter
+" Maintainer: Sergey Matveev <stargrave@stargrave.org>
+" License: GNU General Public License version 3 of the License or later
+"
+" This plugin splits Python function call on several lines.
+"
+"   def foobar(self, foo: str, bar: Some[thing, too]) -> None:
+" to
+"   def foobar(
+"           self,
+"           foo: str,
+"           bar: Some[thing, too],
+"   ) -> None:
+"
+"   foo(bar, baz)[0]
+" to
+"   foo(
+"       bar,
+"       baz,
+"   )[0]
+"
+" You can un-split it using :Undefsplit command on the line where
+" splitting starts.
+"
+" :Defsplit has optional argument specifying how many opening round
+" parenthesis must be skipped.
+" :Defsplit 1 on foo(baz(baz(...))) produces
+"    foo(baz(
+"        baz(...),
+"    ))
+"
+" Also there is :Brsplit command behaving similarly, but it splits other
+" types of brackets: "{}", "[]".
+
+function! s:bracket_find(brs_allowable, line, offset)
+    let possible = []
+    for bracket in a:brs_allowable
+        let found = stridx(a:line, bracket, a:offset)
+        if found != -1 | let possible += [found] | endif
+    endfor
+    return min(possible)
+endfunction
+
+function! defsplit#do(brs_allowable, single_line_comma, ...) abort
+    if a:0 == 0 | let skip = 0 | else | let skip = str2nr(a:1) | endif
+    let shift = get(b:, "defsplit_shift", "    ")
+    let line = getline(".")
+    for i in range(len(line))
+        if line[i] != shift[0]
+            let prfx = strpart(line, 0, i)
+            if line[i : i+3] ==# "def " ||
+                \line[i : i+5] ==# "class " ||
+                \line[i : i+9] ==# "async def "
+                let shift .= shift
+            endif
+            break
+        endif
+    endfor
+    let brs = {"(": ")", "[": "]", "{": "}"}
+    let brfirst = s:bracket_find(a:brs_allowable, line, 0)
+    let brlast = strridx(line, brs[line[brfirst]])
+    while skip > 0
+        let brfirst = s:bracket_find(a:brs_allowable, line, brfirst + 1)
+        let brlast = strridx(line, brs[line[brfirst]], brlast - 1)
+        let skip -= 1
+    endwhile
+    let [curly, round, squar, outbuf] = [0, 0, 0, ""]
+    let ready = [strpart(line, 0, brfirst + 1)]
+    let trailing_comma = 1
+    for c in split(line[brfirst + 1 : brlast-1], '\zs')
+        if c ==# "*" | let trailing_comma = 0 | endif
+        if outbuf ==# "" && c ==# " " | continue | endif
+        let outbuf .= c
+        if c ==# "," && !curly && !round && !squar
+            let ready = add(ready, prfx . shift . outbuf)
+            let outbuf = ""
+        elseif c ==# "[" | let squar += 1
+        elseif c ==# "]" | let squar -= 1
+        elseif c ==# "(" | let round += 1
+        elseif c ==# ")" | let round -= 1
+        elseif c ==# "{" | let curly += 1
+        elseif c ==# "}" | let curly -= 1
+        endif
+    endfor
+    if trailing_comma && !(a:single_line_comma == v:true && len(ready) == 1)
+        let outbuf = outbuf . ","
+    endif
+    let ready = add(ready, prfx . shift . outbuf)
+    let ready = add(ready, prfx . strpart(line, brlast))
+    call append(line("."), ready)
+    normal "_dd
+endfunction