1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-02-03 07:50:05 +08:00
SpaceVim/bundle/splitjoin.vim/autoload/sj/rust.vim
2024-06-27 18:10:36 +08:00

936 lines
24 KiB
VimL

let s:skip_syntax = sj#SkipSyntax(['String', 'Comment'])
let s:eol_pattern = '\s*\%(//.*\)\=$'
" TODO (2023-02-25) running substitute() on semicolons won't work well for
" strings. Need a generic solution, sj#DelimiterOffsets(
function! sj#rust#SplitMatchExpression()
if !sj#SearchUnderCursor('\<match .* {')
return 0
endif
call sj#JumpBracketsTill('{', {'opening': '([<"''', 'closing': ')]>"'''})
let [from, to] = sj#LocateBracesAroundCursor('{', '}')
if from < 0 && to < 0
return 0
endif
let parser = sj#argparser#rust_struct#Construct(from + 1, to - 1, getline('.'))
call parser.Process()
let args = parser.args
if len(args) <= 0
return 0
endif
let items = map(args, 'v:val.argument')
let body = join(items, ",\n")
if sj#settings#Read('trailing_comma')
let body .= ','
endif
let body = "{\n" . body . "\n}"
call sj#ReplaceCols(from, to, body)
return 1
endfunction
function! sj#rust#SplitMatchClause()
if !sj#SearchUnderCursor('^.*\s*=>\s*.*$')
return 0
endif
if !search('=>\s*\zs.', 'W', line('.'))
return 0
endif
let start_col = col('.')
if !search(',\='.s:eol_pattern, 'W', line('.'))
return 0
endif
" handle trailing comma if there is one
if getline('.')[col('.') - 1] == ','
let content_end_col = col('.')
let body_end_col = content_end_col - 1
else
let content_end_col = col('.')
let body_end_col = content_end_col
endif
let body = sj#Trim(sj#GetCols(start_col, body_end_col))
if body =~ '[({[.,*/%+-]$'
" ends in an opening bracket or operator of some sorts, so it's
" incomplete, don't touch it
return 0
endif
let body = substitute(body, '^{\s*\(.\{-}\)\s*}$', '\1', '')
call sj#ReplaceCols(start_col, content_end_col, "{\n".body."\n},")
return 1
endfunction
function! sj#rust#JoinMatchClause()
if !sj#SearchUnderCursor('^.*\s*=>\s*{\s*$')
return 0
endif
call search('=>\s*\zs{', 'W', line('.'))
let body = sj#Trim(sj#GetMotion('Vi{'))
if stridx(body, "\n") >= 0
return 0
endif
if len(body) == 0
call sj#ReplaceMotion('va{', '{}')
return 1
endif
" Remove semicolons when joining, they don't work in non-block form
if body[len(body) - 1] == ';'
let body = body[0 : len(body) - 2]
endif
call sj#ReplaceMotion('Va{', body)
return 1
endfunction
function! sj#rust#SplitQuestionMark()
if sj#SearchSkip('.?', s:skip_syntax, 'Wc', line('.')) <= 0
return 0
endif
let current_line = line('.')
let end_col = col('.')
let question_mark_col = col('.') + 1
let char = getline('.')[end_col - 1]
let previous_start_col = -2
let start_col = -1
while previous_start_col != start_col
let previous_start_col = start_col
if char =~ '\k'
call search('\k\+?;', 'bWc', line('.'))
let start_col = col('.')
elseif char == '}'
" go to opening bracket
normal! %
let start_col = col('.')
elseif char == ')'
" go to opening bracket
normal! %
" find first method-call char
call search('\%(\k\|\.\|::\)\+!\?(', 'bWc')
if line('.') != current_line
" multiline expression, let's just ignore it
return 0
endif
let start_col = col('.')
else
break
endif
if start_col <= 1
" first character, no previous one
break
endif
" move backwards one step from the start
let pos = getpos('.')
let pos[2] = start_col - 1
call setpos('.', pos)
let char = getline('.')[col('.') - 1]
endwhile
" is it a Result, or an Option?
let expr_type = s:FunctionReturnType()
" default to a Result, if we can't find anything
if expr_type == ''
let expr_type = 'Result'
endif
let expr = sj#GetCols(start_col, end_col)
if expr_type == 'Result'
let replacement = join([
\ "match ".expr." {",
\ " Ok(value) => value,",
\ " Err(e) => return Err(e.into()),",
\ "}"
\ ], "\n")
elseif expr_type == 'Option'
let replacement = join([
\ "match ".expr." {",
\ " None => return None,",
\ " Some(value) => value,",
\ "}"
\ ], "\n")
else
echoerr "Unknown expr_type: ".expr_type
return 0
endif
call sj#ReplaceCols(start_col, question_mark_col, replacement)
return 1
endfunction
function! sj#rust#JoinMatchStatement()
let match_pattern = '\<match .* {$'
if sj#SearchSkip(match_pattern, s:skip_syntax, 'Wc', line('.')) <= 0
\ && sj#SearchSkip(match_pattern, s:skip_syntax, 'Wbc', line('.')) <= 0
return 0
endif
" is it a Result, or an Option?
let return_type = s:FunctionReturnType()
let match_position = getpos('.')
let match_line = match_position[1]
let match_col = match_position[2]
let remainder_of_line = strpart(getline('.'), match_col - 1)
let expr = substitute(remainder_of_line, '^match \(.*\) {$', '\1', '')
let first_line = match_line + 1
let second_line = match_line + 2
let closing_line = match_line + 3
let ok_pattern = '^\s*Ok(\(\k\+\))\s*=>\s*\1'
let err_pattern = '^\s*Err(\k\+)\s*=>\s*return\s\+Err('
let some_pattern = '^\s*Some(\(\k\+\))\s*=>\s*\1'
let none_pattern = '^\s*None\s*=>\s*return\s\+None\>'
if getline(first_line) =~# ok_pattern || getline(second_line) =~# ok_pattern
let expr_type = 'Result'
elseif getline(first_line) =~# none_pattern || getline(second_line) =~# none_pattern
let expr_type = 'Option'
else
return 0
endif
if getline(second_line) =~# err_pattern || getline(first_line) =~# err_pattern
let expr_type = 'Result'
elseif getline(second_line) =~# some_pattern || getline(first_line) =~# some_pattern
let expr_type = 'Option'
else
return 0
endif
if search('^\s*}\ze', 'We', closing_line) <= 0
return 0
endif
let end_position = getpos('.')
if expr_type == return_type
call sj#ReplaceByPosition(match_position, end_position, expr.'?')
else
call sj#ReplaceByPosition(match_position, end_position, expr.'.unwrap()')
endif
return 1
endfunction
function! sj#rust#SplitBlockClosure()
if sj#SearchUnderCursor('|.\{-}|\s*\zs{', 'Wc', s:skip_syntax, line('.')) <= 0
return 0
endif
let closure_contents = sj#GetMotion('vi{')
let closure_contents = substitute(closure_contents, ';\ze.', ";\n", 'g')
call sj#ReplaceMotion('va{', "{\n".sj#Trim(closure_contents)."\n}")
return 1
endfunction
function! sj#rust#SplitExprClosure()
if !sj#SearchUnderCursor('|.\{-}| [^{]')
return 0
endif
if search('|.\{-}| \zs.', 'W', line('.')) <= 0
return 0
endif
let start_col = col('.')
let end_col = sj#JumpBracketsTill('\%([,;]\|$\)', {'opening': '([<{"''', 'closing': ')]>}"'''})
if end_col == col('$')
" found end-of-line, one character past the actual end
let end_col -= 1
endif
let closure_contents = sj#GetCols(start_col, end_col)
if closure_contents =~ '[({[.,*/%+-]$'
" ends in an opening bracket or operator of some sorts, so it's
" incomplete, don't touch it
return 0
endif
call sj#ReplaceCols(start_col, end_col, "{\n".closure_contents."\n}")
return 1
endfunction
function! sj#rust#JoinClosure()
if !sj#SearchUnderCursor('|.\{-}| {\s*$')
return 0
endif
if search('|.\{-}| \zs{\s*$', 'W', line('.')) <= 0
return 0
endif
" check if we've got an empty block:
if sj#GetMotion('va{') =~ '^{\_s*}$'
return 0
endif
let closure_contents = sj#Trim(sj#GetMotion('vi{'))
let lines = sj#TrimList(split(closure_contents, "\n"))
if len(lines) > 1
let replacement = '{ '.join(lines, ' ').' }'
elseif len(lines) == 1
let replacement = lines[0]
else
" No contents, leave nothing inside
let replacement = ' '
endif
call sj#ReplaceMotion('va{', replacement)
return 1
endfunction
function! sj#rust#SplitCurlyBrackets()
" in case we're on a struct name, go to the bracket:
call sj#SearchUnderCursor('\k\+\s*{', 'e')
" in case we're in an if-clause, go to the bracket:
call sj#SearchUnderCursor('\<if .\{-}{', 'e')
let [from, to] = sj#LocateBracesAroundCursor('{', '}')
if from < 0 && to < 0
return 0
endif
if (to - from) < 2
call sj#ReplaceMotion('va{', "{\n\n}")
return 1
endif
let body = sj#Trim(sj#GetCols(from + 1, to - 1))
if len(body) == 0
call sj#ReplaceMotion('va{', "{\n\n}")
return 1
endif
let prefix = sj#GetCols(0, from - 1)
let indent = indent(line('.')) + (exists('*shiftwidth') ? shiftwidth() : &sw)
let parser = sj#argparser#rust_struct#Construct(from + 1, to - 1, getline('.'))
call parser.Process()
let args = parser.args
if len(args) <= 0
return 0
endif
if prefix =~ '^\s*use\s\+\%(\k\+::\)\+\s*$'
" then it's a module import:
" use my_mod::{Alpha, Beta as _, Gamma};
let imports = map(args, 'v:val.argument')
let body = join(imports, ",\n")
if sj#settings#Read('trailing_comma')
let body .= ','
endif
call sj#ReplaceCols(from, to, "{\n".body."\n}")
elseif parser.IsValidStruct()
let is_only_pairs = parser.IsOnlyStructPairs()
let items = []
let last_arg = ''
for arg in args
let last_arg = arg.argument
" attributes are not indented, so let's give them appropriate whitespace
let whitespace = repeat(' ', indent)
let components = map(copy(arg.attributes), 'whitespace.v:val')
call add(components, arg.argument)
call add(items, join(components, "\n"))
endfor
let body = join(items, ",\n")
if sj#settings#Read('trailing_comma')
if last_arg =~ '^\.\.'
" interpolated struct, a trailing comma would be invalid
else
let body .= ','
endif
endif
call sj#ReplaceCols(from, to, "{\n".body."\n}")
if is_only_pairs && sj#settings#Read('align')
let body_start = line('.') + 1
let body_end = body_start + len(items) - 1
if items[-1] =~ '^\.\.'
" interpolated struct, don't align that one
let body_end -= 1
endif
if body_end - body_start > 0
call sj#Align(body_start, body_end, 'json_object')
endif
endif
else
" it's just a normal block, ignore the parsed content
let body = substitute(body, ';\ze.', ";\n", 'g')
call sj#ReplaceCols(from, to, "{\n".body."\n}")
endif
return 1
endfunction
function! sj#rust#JoinCurlyBrackets()
let line = getline('.')
if line !~ '{\s*$'
return 0
endif
call search('{', 'c', line('.'))
if eval(s:skip_syntax)
return 0
endif
" check if we've got an empty block:
if sj#GetMotion('va{') =~ '^{\_s*}$'
call sj#ReplaceMotion('va{', '{}')
return 1
endif
let body = sj#GetMotion('Vi{')
let lines = split(body, "\n")
let lines = sj#TrimList(lines)
let body = join(lines, ' ')
" just in case we're joining a StructName { key: value, }:
let body = substitute(body, ',$', '', '')
let in_import = 0
if line =~ '^\s*use\s\+\%(\k\+::\)\+\s*{$'
let in_import = 1
endif
if !in_import
let pos = getpos('.')
" we might still be in a nested import, let's see if we can find it
while searchpair('{', '', '}', 'Wb', s:skip_syntax, 0, 100) > 0
if getline('.') =~ '^\s*use\s\+\%(\k\+::\)\+\s*{$'
let in_import = 1
break
endif
endwhile
call setpos('.', pos)
endif
if in_import
let body = '{'.body.'}'
elseif sj#settings#Read('curly_brace_padding')
let body = '{ '.body.' }'
else
let body = '{'.body.'}'
endif
if sj#settings#Read('normalize_whitespace')
let body = substitute(body, '\s\+\k\+\zs:\s\+', ': ', 'g')
endif
call sj#ReplaceMotion('Va{', body)
return 1
endfunction
function! sj#rust#SplitUnwrapIntoEmptyMatch()
let unwrap_pattern = '\S\.\%(unwrap\|expect\)('
if sj#SearchUnderCursor(unwrap_pattern, 'e', s:skip_syntax) <= 0
return 0
endif
normal! %
let unwrap_end_col = col('.')
normal! %
call search(unwrap_pattern, 'Wb', line('.'))
let end_col = col('.')
let start_col = col('.')
while start_col > 0
let current_expr = strpart(getline('.'), start_col - 1, end_col)
if current_expr =~ '^)'
normal! %
elseif current_expr =~ '^\%(::\|\.\)'
normal! h
else
if sj#SearchSkip('\%(::\|\.\)\=\k\+\%#', s:skip_syntax, 'Wb', line('.')) <= 0
break
endif
endif
if start_col == col('.')
" then nothing has changed this loop, break out
break
else
let start_col = col('.')
endif
endwhile
let expr = sj#GetCols(start_col, end_col)
if expr == ''
return 0
endif
if start_col >= end_col
" the expression is probably split into several lines, let's ignore it
return 0
endif
call sj#ReplaceCols(start_col, unwrap_end_col, join([
\ "match ".expr." {",
\ "",
\ "}",
\ ], "\n"))
return 1
endfunction
function! sj#rust#SplitIfLetIntoMatch()
let if_let_pattern = 'if\s\+let\s\+\(.*\)\s\+=\s\+\(.\{-}\)\s*{'
let else_pattern = '}\s\+else\s\+{'
if search(if_let_pattern, 'We', line('.')) <= 0
return 0
endif
let match_line = substitute(getline('.'), if_let_pattern, "match \\2 {\n\\1 => {", '')
let body = sj#Trim(sj#GetMotion('vi{'))
" multiple lines or ends with `;` -> wrap it in a block
if len(split(body, "\n")) > 1 || body =~ ';'.s:eol_pattern
let body = "{\n".body."\n}"
endif
" Is there an else clause?
call sj#PushCursor()
let else_body = '()'
normal! %
if search(else_pattern, 'We', line('.')) > 0
let else_body = sj#Trim(sj#GetMotion('vi{'))
" multiple lines or ends with `;` -> wrap it in a block
if len(split(else_body, "\n")) > 1 || else_body =~ ';'.s:eol_pattern
let else_body = "{\n".else_body."\n}"
endif
" Delete block, delete rest of line:
normal! "_da{T}"_D
endif
" Back to the if-let line:
call sj#PopCursor()
call sj#ReplaceMotion('V', match_line)
normal! j$
call sj#ReplaceMotion('Va{', body.",\n_ => ".else_body.",\n}")
return 1
endfunction
function! sj#rust#SplitArgs()
return s:SplitList(['(', ')'], 'cursor_on_line')
endfunction
function! sj#rust#SplitArray()
return s:SplitList(['[', ']'], 'cursor_inside')
endfunction
function! sj#rust#JoinEmptyMatchIntoIfLet()
let match_pattern = '\<match\s\+\zs.\{-}\ze\s\+{$'
let pattern_pattern = '^\s*\zs.\{-}\ze\s\+=>'
if search(match_pattern, 'Wc', line('.')) <= 0
return 0
endif
let outer_start_lineno = line('.')
let [_, match_start_col] = searchpos('\<match\s\+', 'nbW', line('.'))
" find end point
normal! f{%
let outer_end_lineno = line('.')
let inner_start_lineno = search(pattern_pattern, 'Wb', outer_start_lineno)
if inner_start_lineno <= 0
return 0
endif
let inner_start_lineno = line('.')
if getline(inner_start_lineno) =~ '^\s*_\s*=>'
" it's a default match, ignore this one for now
let inner_start_lineno = search(pattern_pattern, 'Wb', outer_start_lineno)
if inner_start_lineno <= 0
return 0
endif
if getline(inner_start_lineno) =~ '^\s*_\s*=>'
" more than one _ => clause?
return 0
endif
endif
if getline(inner_start_lineno) =~ '{,\=\s*$'
" it's a block, mark its area:
exe inner_start_lineno
normal! 0f{%
let inner_end_lineno = line('.')
else
" not a }, so just one line
let inner_end_lineno = inner_start_lineno
endif
if prevnonblank(inner_start_lineno - 1) != outer_start_lineno
" the inner start is not immediately after the outer start
return 0
endif
let match_value = sj#Trim(matchstr(getline(outer_start_lineno), match_pattern))
let match_pattern = sj#Trim(matchstr(getline(inner_start_lineno), pattern_pattern))
" currently on inner start, so let's take its contents:
if inner_start_lineno == inner_end_lineno
" one-line body, take everything up to the comma
exe inner_start_lineno
let body = substitute(getline('.'), '^\s*.\{-}\s\+=>\s*\(.\{-}\),\=\s*$', '\1', '')
else
" block body, take everything inside
let body = sj#Trim(sj#GetMotion('vi{'))
endif
" look for an else clause
call sj#PushCursor()
exe outer_start_lineno
let else_body = ''
if search('^\s*_\s*=>\s*\zs\S', 'W', outer_end_lineno) > 0
let fallback_value = strpart(getline('.'), col('.') - 1)
if fallback_value =~ '^(\s*)\|^{\s*}'
" ignore it
elseif fallback_value =~ '^{'
" the else-clause is going to be in a block
let else_body = sj#Trim(sj#GetMotion('vi{'))
else
" one-line value, remove its trailing comma and any comments
let else_body = substitute(fallback_value, ','.s:eol_pattern, '', '')
endif
endif
call sj#PopCursor()
" jump on outer start
exe outer_start_lineno
call sj#ReplaceCols(match_start_col, col('$'), 'if let '.match_pattern.' = '.match_value." {\n")
normal! $
call sj#ReplaceMotion('va{', "{\n".body."\n}")
if else_body != ''
normal! 0f{%
call sj#ReplaceMotion('V', "} else {\n".else_body."\n}")
endif
return 1
endfunction
function! sj#rust#SplitImportList()
if sj#SearchUnderCursor('^\s*use\s\+\%(\k\+::\)\+{', 'e') <= 0
return 0
endif
let prefix = sj#Trim(strpart(getline('.'), 0, col('.') - 1))
let body = sj#GetMotion('vi{')
let parser = sj#argparser#rust_struct#Construct(1, len(body), body)
call parser.Process()
let expanded_imports = []
for arg in parser.args
let import = arg.argument
if import == 'self'
let expanded_import = substitute(prefix, '::$', ';', '')
else
let expanded_import = prefix . import . ';'
end
call add(expanded_imports, expanded_import)
endfor
if len(expanded_imports) <= 0
return 0
endif
let attributes = s:GetLineAttributes(line('.'))
if len(attributes) > 0
let attribute_block = join(attributes, "\n")
let expanded_imports = [expanded_imports[0]] + map(expanded_imports[1:-1], 'attribute_block . "\n" . v:val')
endif
let replacement = join(expanded_imports, "\n")
if body =~ '\n'
" Select a multiline area
call sj#ReplaceMotion('va{$o0', replacement . "\n")
else
call sj#ReplaceMotion('V', replacement)
endif
return 1
endfunction
function! sj#rust#JoinImportList()
let import_pattern = '^\s*use\s\+\%(\k\+::\)\+'
let attribute_pattern = '^\s*#['
if sj#SearchUnderCursor(import_pattern) <= 0
return 0
endif
let first_import = getline('.')
let first_import = substitute(first_import, ';'.s:eol_pattern, '', '')
let imports = [sj#Trim(first_import)]
let start_line = line('.')
let last_line = line('.')
let attributes = s:GetLineAttributes(start_line)
" If there's no attributes, get the next line, otherwise skip the attribute
" lines
exe 'normal! ' . (len(attributes) + 1) . 'j'
while sj#SearchUnderCursor(import_pattern) > 0
if line('.') == last_line
" we haven't moved, stop here
break
endif
let local_attributes = s:GetLineAttributes(line('.'))
if local_attributes != attributes
" This import is not compatible, stop here
break
endif
let last_line = line('.')
let import_line = getline('.')
let import_line = substitute(import_line, ';'.s:eol_pattern, '', '')
call add(imports, sj#Trim(import_line))
exe 'normal! ' . (len(attributes) + 1) . 'j'
endwhile
if len(imports) <= 1
return 0
endif
" find common prefix based on first two imports
let first_prefix_parts = split(imports[0], '::')
let second_prefix_parts = split(imports[1], '::')
if first_prefix_parts[0] != second_prefix_parts[0]
" no match at all, nothing we can do
return 0
endif
" find only the next ones that match the common prefix
let common_prefix = ''
for i in range(1, min([len(first_prefix_parts), len(second_prefix_parts)]) - 1)
if first_prefix_parts[i] != second_prefix_parts[i]
let common_prefix = join(first_prefix_parts[:(i - 1)], '::')
break
endif
endfor
if common_prefix == ''
if len(imports[0]) > len(imports[1])
let longer_import = imports[0]
let shorter_import = imports[1]
else
let longer_import = imports[1]
let shorter_import = imports[0]
endif
" it hasn't been changed, meaning we completely matched the shorter import
" within the longer.
if longer_import == shorter_import
" they're perfectly identical, just delete the first line and move on
exe start_line . 'delete'
return 1
elseif stridx(longer_import, shorter_import) == 0
" the shorter is included, consider it a prefix, and we'll puts `self`
" in there later
let common_prefix = shorter_import
else
" something unexpected went wrong, let's give up
return 0
endif
endif
let compatible_imports = imports[:1]
for import in imports[2:]
if stridx(import, common_prefix) == 0
call add(compatible_imports, import)
else
break
endif
endfor
" Get the differences between the imports
let differences = []
for import in compatible_imports
let difference = strpart(import, len(common_prefix))
let difference = substitute(difference, '^::', '', '')
if difference =~ '^{.*}$'
" there's a list of imports, merge them together
let parser = sj#argparser#rust_struct#Construct(2, len(difference) - 1, difference)
call parser.Process()
for part in map(parser.args, 'v:val.argument')
call add(differences, part)
endfor
elseif len(difference) == 0
" this is the parent module
call add(differences, 'self')
else
call add(differences, difference)
endif
endfor
if exists('*uniq')
" remove successive duplicates
call uniq(differences)
endif
let replacement = common_prefix . '::{' . join(differences, ', ') . '};'
let attribute_line_count = (len(compatible_imports) - 1) * len(attributes)
let end_line = start_line + len(compatible_imports) + attribute_line_count - 1
call sj#ReplaceLines(start_line, end_line, replacement)
return 1
endfunction
function! sj#rust#JoinArgs()
return s:JoinList(['(', ')'])
endfunction
function! sj#rust#JoinArray()
return s:JoinList(['[', ']'])
endfunction
function! s:FunctionReturnType()
let found_result = search(')\_s\+->\_s\+\%(\k\|::\)*Result\>', 'Wbn')
let found_option = search(')\_s\+->\_s\+\%(\k\|::\)*Option\>', 'Wbn')
if found_result <= 0 && found_option <= 0
return ''
elseif found_result > found_option
return 'Result'
elseif found_option > found_result
return 'Option'
else
return ''
endif
endfunction
function s:GetLineAttributes(line)
let end_line = prevnonblank(a:line - 1)
if getline(end_line) !~ '^\s*#['
return []
endif
let start_line = end_line
let tested_line = start_line
while getline(tested_line) =~ '^\s*#['
let start_line = tested_line
let tested_line = prevnonblank(tested_line - 1)
endwhile
return getline(start_line, end_line)
endfunction
function! s:SplitList(delimiter, cursor_position)
let start = a:delimiter[0]
let end = a:delimiter[1]
let lineno = line('.')
let indent = indent('.')
if a:cursor_position == 'cursor_inside'
let [from, to] = sj#LocateBracesAroundCursor(start, end)
elseif a:cursor_position == 'cursor_on_line'
let [from, to] = sj#LocateBracesOnLine(start, end)
else
echoerr "Invalid value for a:cursor_position: ".a:cursor_position
return
endif
if from < 0 && to < 0
return 0
endif
let line = getline('.')
if start == '(' && from > 1 && strpart(line, 0, from - 1) =~ '\<fn \k\+\%(<.*>\)$'
let parser_type = 'fn'
else
let parser_type = 'list'
endif
let parser = sj#argparser#rust_list#Construct(parser_type, from + 1, to - 1, line)
call parser.Process()
let items = parser.args
if empty(items)
return 0
endif
if sj#settings#Read('trailing_comma')
let body = start."\n".join(items, ",\n").",\n".end
else
let body = start."\n".join(items, ",\n")."\n".end
endif
call sj#ReplaceMotion('Va'.start, body)
return 1
endfunction
function! s:JoinList(delimiter)
let start = a:delimiter[0]
let end = a:delimiter[1]
let line = getline('.')
if line !~ start . '\s*$'
return 0
endif
call search(start, 'c', line('.'))
let body = sj#GetMotion('Vi'.start)
let lines = split(body, "\n")
let lines = sj#TrimList(lines)
let body = sj#Trim(join(lines, ' '))
let body = substitute(body, ',\s*$', '', '')
call sj#ReplaceMotion('Va'.start, start.body.end)
return 1
endfunction