1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-02-03 10:50:05 +08:00
SpaceVim/bundle/splitjoin.vim/autoload/sj/elixir.vim

289 lines
7.4 KiB
VimL
Raw Normal View History

2024-06-27 18:10:36 +08:00
function! sj#elixir#SplitDoBlock()
let [function_name, function_start, function_end, function_type] =
\ sj#argparser#elixir#LocateFunction()
if function_start < 0
return 0
endif
let is_if = function_name == 'if' || function_name == 'unless'
let parser = sj#argparser#elixir#Construct(function_start, function_end, getline('.'))
call parser.Process()
let do_body = ''
let else_body = ''
let args = []
for arg in parser.args
if arg =~ '^do:' && do_body == ''
let do_body = substitute(arg, '^do:\s*', '', '')
elseif arg =~ '^else:' && is_if && else_body == ''
let else_body = substitute(arg, '^else:\s*', '', '')
else
call add(args, arg)
endif
endfor
if do_body == ''
return 0
endif
let line = getline('.')
if is_if && function_type == 'with_round_braces'
" skip the round brackets before the if-clause
let new_line = strpart(line, 0, function_start - 2) . ' ' . join(args, ', ')
else
let new_line = strpart(line, 0, function_start - 1) . join(args, ', ')
endif
if function_end > 0
if is_if && function_type == 'with_round_braces'
" skip the round brackets after the if-clause
let new_line .= strpart(line, function_end + 1)
else
let new_line .= strpart(line, function_end)
end
else
" we didn't detect an end, so it goes on to the end of the line
endif
if else_body != ''
let do_block = " do\n" . do_body . "\nelse\n" . else_body . "\nend"
else
let do_block = " do\n" . do_body . "\nend"
endif
call sj#ReplaceLines(line('.'), line('.'), new_line . do_block)
return 1
endfunction
function! sj#elixir#JoinDoBlock()
let do_pattern = '\s*do\s*\%(#.*\)\=$'
let def_lineno = line('.')
let def_line = getline(def_lineno)
if def_line !~ do_pattern
return 0
endif
let [function_name, function_start, function_end, function_type] =
\ sj#argparser#elixir#LocateFunction()
if function_start < 0
return 0
endif
let is_if = function_name == 'if' || function_name == 'unless'
let body_lineno = line('.') + 1
let body_line = getline(body_lineno)
if is_if && getline(line('.') + 2) =~ '^\s*else\>'
let else_lineno = line('.') + 2
let else_line = getline(else_lineno)
let else_body_lineno = line('.') + 3
let else_body_line = getline(else_body_lineno)
let end_lineno = line('.') + 4
let end_line = getline(end_lineno)
else
let else_line = ''
let end_lineno = line('.') + 2
let end_line = getline(end_lineno)
endif
if end_line !~ '^\s*end$'
return 0
endif
exe 'keeppatterns s/'.do_pattern.'//'
if function_end < 0
let function_end = col('$') - 1
endif
let args = sj#GetCols(function_start, function_end)
let joined_args = ', do: '.sj#Trim(body_line)
if else_line != ''
let joined_args .= ', else: '.sj#Trim(else_body_line)
endif
call sj#ReplaceCols(function_start, function_end, args . joined_args)
exe body_lineno.','.end_lineno.'delete _'
return 1
endfunction
function! sj#elixir#JoinCommaDelimitedItems()
if getline('.') !~ ',\s*$'
return 0
endif
let start_lineno = line('.')
let end_lineno = start_lineno
let lineno = nextnonblank(start_lineno + 1)
let line = getline(lineno)
while lineno <= line('$') && line =~ ',\s*$'
let end_lineno = lineno
let lineno = nextnonblank(lineno + 1)
let line = getline(lineno)
endwhile
let end_lineno = lineno
call cursor(start_lineno, 0)
exe "normal! V".(end_lineno - start_lineno)."jJ"
return 1
endfunction
function! sj#elixir#SplitArray()
let [from, to] = sj#LocateBracesAroundCursor('[', ']', [
\ 'elixirInterpolationDelimiter',
\ 'elixirString',
\ 'elixirStringDelimiter',
\ 'elixirSigilDelimiter',
\ ])
if from < 0
return 0
endif
let items = sj#ParseJsonObjectBody(from + 1, to - 1)
if len(items) == 0 || to - from < 2
return 1
endif
" substitute [1, 2, | tail]
let items[-1] = substitute(items[-1], "\\(|[^>].*\\)", "\n\\1", "")
let body = "[\n" . join(items, ",\n") . "\n]"
call sj#ReplaceMotion('Va[', body)
return 1
endfunction
function! sj#elixir#JoinArray()
normal! $
if getline('.')[col('.') - 1] != '['
return 0
endif
let body = sj#Trim(sj#GetMotion('Vi['))
" remove trailing comma
let body = substitute(body, ',\ze\_s*$', '', '')
let items = split(body, ",\s*\n")
if len(items) == 0
return 0
endif
" join isolated | tail on the last line
let items[-1] = substitute(items[-1], "[[:space:]]*\\(|[^>].*\\)", " \\1", "")
let body = join(sj#TrimList(items), ', ')
call sj#ReplaceMotion('Va[', '['.body.']')
return 1
endfunction
let s:pipe_pattern = '^\s*|>\s\+'
let s:atom_pattern = ':\k\+'
let s:module_pattern = '\k\%(\k\|\.\)*'
let s:function_pattern = '\k\+[?!]\='
let s:atom_or_module_pattern = '\%(' . s:atom_pattern . '\.\|' . s:module_pattern . '\.\)\='
function! sj#elixir#SplitPipe()
let line = getline('.')
call sj#PushCursor()
normal! 0f(
let [function_name, function_start, function_end, function_type] =
\ sj#argparser#elixir#LocateFunction()
call sj#PopCursor()
" We only support function calls that start at the beginning of the line
" (accounting for whitespace)
let prefix = strpart(line, 0, function_start - 1)
let prefix_pattern = '^\s*' . s:atom_or_module_pattern . function_name . '\((\|\s\+\)$'
if function_start < 0 || prefix !~ prefix_pattern
return 0
endif
let comment_pattern = '\s*\(#.*\)\=$'
if function_end < 0
let comment_start = match(line, comment_pattern)
if comment_start < 0
let rest = 'none'
else
let rest = strpart(line, comment_start)
let function_end = comment_start
endif
else
let rest = strpart(line, function_end + 1)
if rest !~ '^' . comment_pattern
return 0
endif
end
let parser = sj#argparser#elixir#Construct(function_start, function_end, line)
call parser.Process()
let args = parser.args
let function_call = sj#Trim(strpart(line, 0, function_start - 2))
let result = args[0] . "\n|> " . function_call . '(' . join(args[1:], ', ') . ')' . rest
call sj#ReplaceLines(line('.'), line('.'), result)
return 1
endfunction
function! sj#elixir#JoinPipe()
call sj#PushCursor()
let line = getline('.')
if line !~ s:pipe_pattern
normal! j
let line = getline('.')
endif
let line_num = line('.')
let prev_line = sj#Trim(getline(line_num - 1))
if line !~ s:pipe_pattern || prev_line =~ s:pipe_pattern
call sj#PopCursor()
return 0
endif
let empty_args_pattern = s:pipe_pattern . '\(' . s:atom_or_module_pattern . s:function_pattern . '\)()'
if line =~ empty_args_pattern
let function_name = substitute(line, empty_args_pattern, '\1', '')
let result = function_name . '(' . prev_line . ')'
call sj#PopCursor()
else
normal! f(l
let [function_name, function_start, function_end, function_type] =
\ sj#argparser#elixir#LocateFunction()
call sj#PopCursor()
if function_start < 0
return 0
endif
let parser = sj#argparser#elixir#Construct(function_start, function_end, line)
call parser.Process()
let args = parser.args
let function_call = substitute(strpart(line, 0, function_start - 2), '|>\s\+', '', '')
let result = function_call . '(' . prev_line . ', ' . join(args, ', ') . ')'
endif
call sj#ReplaceLines(line_num - 1, line_num, result)
return 1
endfunction