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

197 lines
5.3 KiB
VimL

" Only real syntax that's interesting is cParen and cConditional
let s:skip = sj#SkipSyntax(['rComment'])
" function! sj#r#SplitFuncall()
"
" Split the R function call if the cursor lies within the arguments of a
" function call
"
function! sj#r#SplitFuncall()
if !s:IsValidSelection("va(")
return 0
endif
call sj#PushCursor()
let items = s:ParseJsonFromMotion("va(\<esc>vi(")
let items = map(items, {k, v -> v . (k+1 < len(items) ? "," : "")})
let r_indent_align_args = get(g:, 'r_indent_align_args', 1)
if r_indent_align_args && len(items)
let items[0] = "(" . items[0]
let items[-1] = items[-1] . ")"
let lines = items
else
let lines = ["("] + items + [")"]
endif
call sj#PopCursor()
call s:ReplaceMotionPreserveCursor('va(', lines)
return 1
endfunction
" function! sj#r#JoinFuncall()
"
" Join an R function call if the cursor lies within the arguments of a
" function call
"
function! sj#r#JoinFuncall()
if !s:IsValidSelection("va(")
return 0
endif
call sj#PushCursor()
let existing_text = sj#GetMotion("va(\<esc>vi(")
let items = s:ParseJsonObject(existing_text)
let text = join(items, ", ")
" if replacement wouldn't have any effect, fail to attempt a latter callback
if text == existing_text
return 0
endif
call sj#PopCursor()
call s:ReplaceMotionPreserveCursor("va(", ["(" . text . ")"])
return 1
endfunction
" function! sj#r#JoinSmart()
"
" Reexecute :SplitjoinJoin at the end of the line, where it is more likely
" to find a code block relevant to being joined.
"
function! sj#r#JoinSmart()
try
call sj#PushCursor()
let cur_pos = getpos(".")
silent normal! $
let end_pos = getpos(".")
if cur_pos[1:2] != end_pos[1:2]
execute ":SplitjoinJoin"
return 1
else
return 0
endif
finally
call sj#PopCursor()
endtr
endfunction
" function! s:DoMotion(motion)
"
" Perform a normal-mode motion command
"
function s:DoMotion(motion)
call sj#PushCursor()
execute "silent normal! " . a:motion . "\<esc>"
execute "silent normal! \<esc>"
call sj#PopCursor()
endfunction
" function! s:MoveCursor(lines, cols)
"
" Reposition cursor given relative lines offset and columns from the start of
" the line
"
function! s:MoveCursor(lines, cols)
let y = a:lines > 0 ? a:lines . 'j^' : a:lines < 0 ? a:lines . 'k^' : ''
let x = a:cols > 0 ? a:cols . 'l' : a:cols < 0 ? a:cols . 'h' : ''
let motion = y . x
if len(motion)
execute 'silent normal! ' . motion
endif
endfunction
" function! s:ParseJsonObject(text)
"
" Wrapper around sj#argparser#js#Construct to simply parse a given string
"
function! s:ParseJsonObject(text)
let parser = sj#argparser#js#Construct(0, len(a:text), a:text)
call parser.Process()
return parser.args
endfunction
" function! s:ParseJsonFromMotion(motion)
"
" Parse a json object from the visual selection of a given normal-mode motion
" string
"
function! s:ParseJsonFromMotion(motion)
let text = sj#GetMotion(a:motion)
return s:ParseJsonObject(text)
endfunction
" function! s:IsValidSelection(motion)
"
" Test whether a visual selection contains more than a single character after
" performing the given normal-mode motion string
"
function! s:IsValidSelection(motion)
call s:DoMotion(a:motion)
return getpos("'<") != getpos("'>")
endfunction
" function! s:ReplaceMotionPreserveCursor(motion, rep) {{{2
"
" Replace the normal mode "motion" selection with a list of replacement lines,
" "rep", separated by line breaks, Assuming the non-whitespace content of
" "motion" is identical to the non-whitespace content of the joined lines of
" "rep", the cursor will be repositioned to the resulting location of the
" current character under the cursor.
"
function! s:ReplaceMotionPreserveCursor(motion, rep)
" default to interpretting all lines of text as originally from text to replace
let rep = a:rep
" do motion and get bounds & text
call s:DoMotion(a:motion)
let ini = split(sj#GetByPosition(getpos("'<"), getpos(".")), "\n")
let ini = map(ini, {k, v -> sj#Ltrim(v)})
" do replacement
let body = join(a:rep, "\n")
call sj#ReplaceMotion(a:motion, body)
" go back to start of selection
silent normal! `<
" try to reconcile initial selection against replacement lines
let [cursory, cursorx, leading_ws] = [0, 0, 0]
while len(ini) && len(rep)
let i = stridx(ini[0], rep[0])
let j = stridx(rep[0], ini[0])
if i >= 0
" if an entire line of the replacement text found in initial then we'll
" need our cursor to move to the next line if more lines are insered
let ini[0] = sj#Ltrim(ini[0][i+len(rep[0]):])
let cursorx += i + len(rep[0])
let ini = len(ini[0]) ? ini : ini[1:]
let rep = rep[1:]
if len(ini)
let cursory += 1
let cursorx = 0
endif
elseif j >= 0
" if an entire line of the initial is found in the replacement then
" we'll need our cursor to move rightward through length of the initial
let rep[0] = rep[0][j+len(ini[0]):]
let leading_ws = len(rep[0])
let rep[0] = sj#Ltrim(rep[0])
let leading_ws = leading_ws - len(rep[0])
let cursorx += j + len(ini[0])
let ini = ini[1:]
let cursorx += (len(ini) && len(ini[0]) ? leading_ws : 0)
else
let ini = []
endif
endwhile
call s:MoveCursor(cursory, max([cursorx-1, 0]))
call sj#PushCursor()
endfunction