799 lines
19 KiB
VimL
799 lines
19 KiB
VimL
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'julia') == -1
|
|
|
|
" Facilities for moving around Julia blocks (e.g. if/end, function/end etc.)
|
|
" (AKA a collection of horrible hacks)
|
|
|
|
let s:default_mappings = {
|
|
\ "moveblock_n" : "]]",
|
|
\ "moveblock_N" : "][",
|
|
\ "moveblock_p" : "[[",
|
|
\ "moveblock_P" : "[]",
|
|
\
|
|
\ "move_n" : "]j",
|
|
\ "move_N" : "]J",
|
|
\ "move_p" : "[j",
|
|
\ "move_P" : "[J",
|
|
\
|
|
\ "select_a" : "aj",
|
|
\ "select_i" : "ij",
|
|
\
|
|
\ "whereami" : "",
|
|
\ }
|
|
|
|
function! s:getmapchars(function)
|
|
if exists("g:julia_blocks_mappings") && has_key(g:julia_blocks_mappings, a:function)
|
|
return s:escape(g:julia_blocks_mappings[a:function])
|
|
else
|
|
return s:escape(s:default_mappings[a:function])
|
|
endif
|
|
endfunction
|
|
|
|
function! s:map_move(function, toend, backwards)
|
|
let chars = s:getmapchars(a:function)
|
|
if empty(chars)
|
|
return
|
|
endif
|
|
let fn = "julia_blocks#" . a:function
|
|
let lhs = "<buffer> <nowait> <silent> " . chars . " "
|
|
let cnt = ":<C-U>let b:jlblk_count=v:count1"
|
|
exe "nnoremap " . lhs . cnt
|
|
\ . " <Bar> call " . fn . "()<CR>"
|
|
exe "onoremap " . lhs . cnt
|
|
\ . "<CR><Esc>:call julia_blocks#owrapper_move(v:operator, \"" . fn . "\", " . a:toend . ", " . a:backwards . ")<CR>"
|
|
exe "xnoremap " . lhs . cnt
|
|
\ . "<CR>gv<Esc>:call julia_blocks#vwrapper_move(\"" . fn . "\")<CR>"
|
|
let b:jlblk_mapped[a:function] = 1
|
|
endfunction
|
|
|
|
function! julia_blocks#owrapper_move(oper, function, toend, backwards)
|
|
let F = function(a:function)
|
|
|
|
let save_redraw = &lazyredraw
|
|
let save_select = &selection
|
|
|
|
let restore_cmds = "\<Esc>"
|
|
\ . ":let &l:selection = \"" . save_select . "\"\<CR>"
|
|
\ . ":let &l:lazyredraw = " . save_redraw . "\<CR>"
|
|
\ . ":\<BS>"
|
|
|
|
setlocal lazyredraw
|
|
|
|
let start_pos = getpos('.')
|
|
let b:jlblk_abort_calls_esc = 0
|
|
call F()
|
|
let b:jlblk_abort_calls_esc = 1
|
|
let end_pos = getpos('.')
|
|
if start_pos == end_pos
|
|
call feedkeys(restore_cmds, 'n')
|
|
endif
|
|
|
|
let &l:selection = "inclusive"
|
|
if a:backwards || !a:toend
|
|
let &l:selection = "exclusive"
|
|
endif
|
|
if a:toend && a:backwards
|
|
let end_pos[2] += 1
|
|
endif
|
|
|
|
if s:compare_pos(start_pos, end_pos) > 0
|
|
let [start_pos, end_pos] = [end_pos, start_pos]
|
|
endif
|
|
|
|
call setpos("'<", start_pos)
|
|
call setpos("'>", end_pos)
|
|
|
|
" NOTE: the 'c' operator behaves differently, for mysterious reasons. We
|
|
" simulate it with 'd' followed by 'i' instead
|
|
call feedkeys("gv" . (a:oper == "c" ? "d" : a:oper) . restore_cmds . (a:oper == "c" ? "i" : ""), 'n')
|
|
endfunction
|
|
|
|
function! julia_blocks#vwrapper_move(function)
|
|
let F = function(a:function)
|
|
|
|
let s = getpos('.')
|
|
let b1 = getpos("'<")
|
|
let b2 = getpos("'>")
|
|
|
|
let b = b1 == s ? b2 : b1
|
|
call setpos('.', s)
|
|
let b:jlblk_abort_calls_esc = 0
|
|
call F()
|
|
let b:jlblk_abort_calls_esc = 1
|
|
let e = getpos('.')
|
|
call setpos('.', b)
|
|
exe "normal " . visualmode()
|
|
call setpos('.', e)
|
|
endfunction
|
|
|
|
function! s:unmap(function)
|
|
if !get(b:jlblk_mapped, a:function, 0)
|
|
return
|
|
endif
|
|
let chars = s:getmapchars(a:function)
|
|
if empty(chars)
|
|
" shouldn't happen
|
|
return
|
|
endif
|
|
let mapids = a:function =~# "^move" ? ["n", "x", "o"] :
|
|
\ a:function =~# "^select" ? ["x", "o"] :
|
|
\ ["n"]
|
|
let fn = "julia_blocks#" . a:function
|
|
let cmd = "<buffer> " . chars
|
|
for m in mapids
|
|
exe m . "unmap " . cmd
|
|
endfor
|
|
let b:jlblk_mapped[a:function] = 0
|
|
endfunction
|
|
|
|
function! s:escape(chars)
|
|
let c = a:chars
|
|
let c = substitute(c, '|', '<Bar>', 'g')
|
|
return c
|
|
endfunction
|
|
|
|
function! s:map_select(function)
|
|
let chars = s:getmapchars(a:function)
|
|
if empty(chars)
|
|
return
|
|
endif
|
|
let fn = "julia_blocks#" . a:function
|
|
let lhs = "<buffer> <nowait> <silent> " . chars . " "
|
|
let cnt = ":<C-U>let b:jlblk_inwrapper=1<CR>:let b:jlblk_count=max([v:prevcount,1])<CR>"
|
|
exe "onoremap " . lhs . "<Esc>" . cnt
|
|
\ . ":call julia_blocks#owrapper_select(v:operator, \"" . fn . "\")<CR>"
|
|
exe "xnoremap " . lhs . cnt
|
|
\ . ":call julia_blocks#vwrapper_select(\"" . fn . "\")<CR>"
|
|
let b:jlblk_mapped[a:function] = 1
|
|
endfunction
|
|
|
|
function! julia_blocks#owrapper_select(oper, function) ", toend, backwards)
|
|
let F = function(a:function)
|
|
|
|
let save_redraw = &lazyredraw
|
|
let save_select = &selection
|
|
|
|
let restore_cmds = "\<Esc>"
|
|
\ . ":let &l:selection = \"" . save_select . "\"\<CR>"
|
|
\ . ":let &l:lazyredraw = " . save_redraw . "\<CR>"
|
|
\ . ":\<BS>"
|
|
|
|
setlocal lazyredraw
|
|
|
|
let b:jlblk_abort_calls_esc = 0
|
|
let retF = F()
|
|
let b:jlblk_abort_calls_esc = 1
|
|
if empty(retF)
|
|
let b:jlblk_inwrapper = 0
|
|
call feedkeys(restore_cmds, 'n')
|
|
return
|
|
end
|
|
let [start_pos, end_pos] = retF
|
|
|
|
if start_pos == end_pos
|
|
call feedkeys(restore_cmds, 'n')
|
|
endif
|
|
|
|
let &l:selection = "inclusive"
|
|
|
|
call setpos("'<", start_pos)
|
|
call setpos("'>", end_pos)
|
|
|
|
let b:jlblk_inwrapper = 0
|
|
" NOTE: the 'c' operator behaves differently, for mysterious reasons. We
|
|
" simulate it with 'd' followed by 'i' instead
|
|
call feedkeys("gv" . (a:oper == "c" ? "d" : a:oper) . restore_cmds . (a:oper == "c" ? "i" : ""), 'n')
|
|
endfunction
|
|
|
|
function! julia_blocks#vwrapper_select(function)
|
|
let F = function(a:function)
|
|
|
|
let b:jlblk_abort_calls_esc = 0
|
|
let retF = F()
|
|
let b:jlblk_abort_calls_esc = 1
|
|
if empty(retF)
|
|
let b:jlblk_inwrapper = 0
|
|
return
|
|
end
|
|
let [start_pos, end_pos] = retF
|
|
call setpos("'<", start_pos)
|
|
call setpos("'>", end_pos)
|
|
normal! gv
|
|
let b:jlblk_inwrapper = 0
|
|
endfunction
|
|
|
|
function! s:map_aux(function)
|
|
let chars = s:getmapchars(a:function)
|
|
if empty(chars)
|
|
return
|
|
endif
|
|
let fn = "julia_blocks#" . a:function
|
|
let lhs = "<buffer> <nowait> <silent> " . chars . " "
|
|
exe "nnoremap " . lhs . ":<C-U>echo " . fn . "()<CR>"
|
|
let b:jlblk_mapped[a:function] = 1
|
|
endfunction
|
|
|
|
let s:julia_blocks_functions = {
|
|
\ "moveblock_N": [1, 0],
|
|
\ "moveblock_n": [0, 0],
|
|
\ "moveblock_p": [0, 1],
|
|
\ "moveblock_P": [1, 1],
|
|
\
|
|
\ "move_N": [1, 0],
|
|
\ "move_n": [0, 0],
|
|
\ "move_p": [0, 1],
|
|
\ "move_P": [1, 1],
|
|
\
|
|
\ "select_a": [],
|
|
\ "select_i": [],
|
|
\
|
|
\ "whereami": [],
|
|
\ }
|
|
|
|
function! julia_blocks#init_mappings()
|
|
let b:jlblk_mapped = {}
|
|
for f in keys(s:julia_blocks_functions)
|
|
if f =~# "^move"
|
|
let [te, bw] = s:julia_blocks_functions[f]
|
|
call s:map_move(f, te, bw)
|
|
elseif f =~# "^select"
|
|
call s:map_select(f)
|
|
else
|
|
call s:map_aux(f)
|
|
endif
|
|
endfor
|
|
call julia_blocks#select_reset()
|
|
augroup JuliaBlocks
|
|
au!
|
|
au InsertEnter <buffer> call julia_blocks#select_reset()
|
|
au CursorMoved <buffer> call s:cursor_moved()
|
|
augroup END
|
|
|
|
" we would need some autocmd event associated with exiting from
|
|
" visual mode, but there isn't any, so we resort to this crude
|
|
" hack
|
|
" ACTUALLY this creates more problems than it solves, so the crude hack
|
|
" is just disabled
|
|
"vnoremap <buffer><silent><unique> <Esc> <Esc>:call julia_blocks#select_reset()<CR>
|
|
endfunction
|
|
|
|
function! julia_blocks#remove_mappings()
|
|
if exists("b:jlblk_mapped")
|
|
for f in keys(s:julia_blocks_functions)
|
|
call s:unmap(f)
|
|
endfor
|
|
endif
|
|
unlet! b:jlblk_save_pos b:jlblk_view b:jlblk_count b:jlblk_abort_calls_esc
|
|
unlet! b:jlblk_inwrapper b:jlblk_did_select b:jlblk_doing_select
|
|
unlet! b:jlblk_last_start_pos b:jlblk_last_end_pos b:jlblk_last_mode
|
|
augroup JuliaBlocks
|
|
au!
|
|
augroup END
|
|
augroup! JuliaBlocks
|
|
let md = maparg("<Esc>", "x", 0, 1)
|
|
if !empty(md) && md["buffer"]
|
|
vunmap <buffer> <Esc>
|
|
endif
|
|
endfunction
|
|
|
|
function! s:restore_view()
|
|
"redraw! " would ensure correct behaviour, but is annoying
|
|
let pos = getpos('.')
|
|
if pos == b:jlblk_save_pos
|
|
call winrestview(b:jlblk_view)
|
|
return
|
|
endif
|
|
let oldtopline = b:jlblk_view["topline"]
|
|
let newtopline = winsaveview()["topline"]
|
|
let l = pos[1]
|
|
if l >= oldtopline + &l:scrolloff && l <= oldtopline + winheight(0) - 1 - &l:scrolloff
|
|
if newtopline > oldtopline
|
|
exe ":normal! " . (newtopline - oldtopline) . "\<C-Y>"
|
|
elseif newtopline < oldtopline
|
|
exe ":normal! " . (oldtopline - newtopline) . "\<C-E>"
|
|
endif
|
|
" these reduce the scrolling to the minimum (which is maybe not
|
|
" standard ViM behaviour?)
|
|
elseif newtopline < oldtopline && (l - newtopline - &l:scrolloff) > 0
|
|
exe ":normal! " . (l - newtopline - &l:scrolloff) . "\<C-E>"
|
|
elseif newtopline > oldtopline && (newtopline + &l:scrolloff - l) > 0
|
|
exe ":normal! " . (l - newtopline - &l:scrolloff) . "\<C-E>"
|
|
endif
|
|
call setpos('.', pos) " make sure we didn't screw up
|
|
" (since winsaveview may not be up to date)
|
|
endfunction
|
|
|
|
function! s:abort()
|
|
call setpos('.', b:jlblk_save_pos)
|
|
call s:restore_view()
|
|
if get(b:, "jlblk_abort_calls_esc", 1)
|
|
call feedkeys("\<Esc>", 'n')
|
|
endif
|
|
return 0
|
|
endfunction
|
|
|
|
function! s:set_mark_tick(...)
|
|
" This could be a one-liner:
|
|
" call setpos("''", b:jlblk_save_pos)
|
|
" but we want to append to the jumplist,
|
|
" which setpos doesn't do
|
|
let p = getpos('.')
|
|
call setpos('.', b:jlblk_save_pos)
|
|
normal! m'
|
|
call setpos('.', p)
|
|
endfunction
|
|
|
|
function! s:get_save_pos(...)
|
|
if !exists("b:jlblk_save_pos") || (a:0 == 0) || (a:0 > 0 && a:1)
|
|
let b:jlblk_save_pos = getpos('.')
|
|
endif
|
|
let b:jlblk_view = winsaveview()
|
|
endfunction
|
|
|
|
function! s:on_end()
|
|
return getline('.')[col('.')-1] =~# '\k' && expand("<cword>") =~# b:julia_end_keywords
|
|
endfunction
|
|
|
|
function! s:on_begin()
|
|
let [l,c] = [line('.'), col('.')]
|
|
normal! ^
|
|
let patt = '\%<'.(c+1).'c\(' . b:julia_begin_keywordsm . '\)\%>'.(c-1).'c'
|
|
let n = search(patt, 'Wnc', l)
|
|
call cursor(l, c)
|
|
return n > 0
|
|
endfunction
|
|
|
|
function! s:matchit()
|
|
let lkj = exists(":lockjumps") == 2 ? "lockjumps " : ""
|
|
exe lkj . "normal %"
|
|
endfunction
|
|
|
|
function! s:move_before_begin()
|
|
call search(b:julia_begin_keywordsm, 'Wbc')
|
|
normal! h
|
|
endfunction
|
|
|
|
function! s:cycle_until_end()
|
|
let pos = getpos('.')
|
|
while !s:on_end()
|
|
call s:matchit()
|
|
let c = 0
|
|
if getpos('.') == pos || c > 1000
|
|
" shouldn't happen, but let's avoid infinite loops anyway
|
|
return 0
|
|
endif
|
|
let c += 1
|
|
endwhile
|
|
return 1
|
|
endfunction
|
|
|
|
function! s:moveto_block_delim(toend, backwards, ...)
|
|
let pattern = a:toend ? b:julia_end_keywords : b:julia_begin_keywordsm
|
|
let flags = a:backwards ? 'Wb' : 'W'
|
|
let cnt = a:0 > 0 ? a:1 : b:jlblk_count
|
|
if !a:toend && a:backwards && s:on_begin()
|
|
call s:move_before_begin()
|
|
endif
|
|
let ret = 0
|
|
for c in range(cnt)
|
|
if a:toend && a:backwards && s:on_end()
|
|
normal! l
|
|
normal! bh
|
|
endif
|
|
while 1
|
|
let searchret = search(pattern, flags)
|
|
if !searchret
|
|
return ret
|
|
endif
|
|
exe "let skip = " . b:match_skip
|
|
if !skip
|
|
let ret = 1
|
|
break
|
|
endif
|
|
endwhile
|
|
endfor
|
|
return ret
|
|
endfunction
|
|
|
|
function! s:compare_pos(pos1, pos2)
|
|
if a:pos1[1] < a:pos2[1]
|
|
return -1
|
|
elseif a:pos1[1] > a:pos2[1]
|
|
return 1
|
|
elseif a:pos1[2] < a:pos2[2]
|
|
return -1
|
|
elseif a:pos1[2] > a:pos2[2]
|
|
return 1
|
|
else
|
|
return 0
|
|
endif
|
|
endfunction
|
|
|
|
function! julia_blocks#move_N()
|
|
call s:get_save_pos()
|
|
|
|
let ret = s:moveto_block_delim(1, 0)
|
|
if !ret
|
|
return s:abort()
|
|
endif
|
|
|
|
normal! e
|
|
call s:set_mark_tick()
|
|
|
|
return 1
|
|
endfunction
|
|
|
|
function! julia_blocks#move_n()
|
|
call s:get_save_pos()
|
|
|
|
let ret = s:moveto_block_delim(0, 0)
|
|
if !ret
|
|
return s:abort()
|
|
endif
|
|
|
|
call s:set_mark_tick()
|
|
|
|
return 1
|
|
endfunction
|
|
|
|
function! julia_blocks#move_p()
|
|
call s:get_save_pos()
|
|
|
|
let ret = s:moveto_block_delim(0, 1)
|
|
if !ret
|
|
return s:abort()
|
|
endif
|
|
|
|
call s:set_mark_tick()
|
|
|
|
return 1
|
|
endfunction
|
|
|
|
function! julia_blocks#move_P()
|
|
call s:get_save_pos()
|
|
|
|
let ret = s:moveto_block_delim(1, 1)
|
|
if !ret
|
|
return s:abort()
|
|
endif
|
|
|
|
normal! e
|
|
call s:set_mark_tick()
|
|
|
|
return 1
|
|
endfunction
|
|
|
|
function! s:moveto_currentblock_end()
|
|
let flags = 'W'
|
|
if s:on_end()
|
|
let flags .= 'c'
|
|
" NOTE: using "normal! lb" fails at the end of the file (?!)
|
|
normal! l
|
|
normal! b
|
|
endif
|
|
|
|
let ret = searchpair(b:julia_begin_keywordsm, '', b:julia_end_keywords, flags, b:match_skip)
|
|
if ret <= 0
|
|
return s:abort()
|
|
endif
|
|
|
|
normal! e
|
|
return 1
|
|
endfunction
|
|
|
|
function! julia_blocks#moveblock_N()
|
|
call s:get_save_pos()
|
|
|
|
let ret = 0
|
|
for c in range(b:jlblk_count)
|
|
let last_seen_pos = getpos('.')
|
|
if s:on_end()
|
|
normal! hel
|
|
let save_pos = getpos('.')
|
|
let ret_start = s:moveto_block_delim(0, 0, 1)
|
|
let start1_pos = ret_start ? getpos('.') : [0,0,0,0]
|
|
call setpos('.', save_pos)
|
|
if s:on_end()
|
|
normal! h
|
|
endif
|
|
let ret_end = s:moveto_block_delim(1, 0, 1)
|
|
let end1_pos = ret_end ? getpos('.') : [0,0,0,0]
|
|
|
|
if ret_start && (!ret_end || s:compare_pos(start1_pos, end1_pos) < 0)
|
|
call setpos('.', start1_pos)
|
|
else
|
|
call setpos('.', save_pos)
|
|
endif
|
|
endif
|
|
|
|
let moveret = s:moveto_currentblock_end()
|
|
if !moveret && c == 0
|
|
let moveret = s:moveto_block_delim(0, 0, 1) && s:cycle_until_end()
|
|
if moveret
|
|
normal! e
|
|
endif
|
|
endif
|
|
if !moveret
|
|
call setpos('.', last_seen_pos)
|
|
break
|
|
endif
|
|
|
|
let ret = 1
|
|
endfor
|
|
if !ret
|
|
return s:abort()
|
|
endif
|
|
|
|
call s:set_mark_tick()
|
|
|
|
return 1
|
|
endfunction
|
|
|
|
function! julia_blocks#moveblock_n()
|
|
call s:get_save_pos()
|
|
|
|
let ret = 0
|
|
for c in range(b:jlblk_count)
|
|
let last_seen_pos = getpos('.')
|
|
|
|
call s:moveto_currentblock_end()
|
|
if s:moveto_block_delim(0, 0, 1)
|
|
let ret = 1
|
|
else
|
|
call setpos('.', last_seen_pos)
|
|
break
|
|
endif
|
|
endfor
|
|
|
|
if !ret
|
|
return s:abort()
|
|
endif
|
|
|
|
call s:set_mark_tick()
|
|
|
|
return 1
|
|
endfunction
|
|
|
|
function! julia_blocks#moveblock_p()
|
|
call s:get_save_pos()
|
|
|
|
let ret = 0
|
|
for c in range(b:jlblk_count)
|
|
let last_seen_pos = getpos('.')
|
|
if s:on_begin()
|
|
call s:move_before_begin()
|
|
if s:on_end()
|
|
normal! l
|
|
endif
|
|
let save_pos = getpos('.')
|
|
let ret_start = s:moveto_block_delim(0, 1, 1)
|
|
let start1_pos = ret_start ? getpos('.') : [0,0,0,0]
|
|
call setpos('.', save_pos)
|
|
let ret_end = s:moveto_block_delim(1, 1, 1)
|
|
let end1_pos = ret_end ? getpos('.') : [0,0,0,0]
|
|
|
|
if ret_end && (!ret_start || s:compare_pos(start1_pos, end1_pos) < 0)
|
|
call setpos('.', end1_pos)
|
|
else
|
|
call setpos('.', save_pos)
|
|
endif
|
|
endif
|
|
|
|
let moveret = s:moveto_currentblock_end()
|
|
if !moveret && c == 0
|
|
let moveret = s:moveto_block_delim(1, 1, 1)
|
|
endif
|
|
if !moveret
|
|
call setpos('.', last_seen_pos)
|
|
break
|
|
endif
|
|
|
|
call s:matchit()
|
|
let ret = 1
|
|
endfor
|
|
if !ret
|
|
return s:abort()
|
|
endif
|
|
|
|
call s:set_mark_tick()
|
|
call s:restore_view()
|
|
|
|
return 1
|
|
endfunction
|
|
|
|
function! julia_blocks#moveblock_P()
|
|
call s:get_save_pos()
|
|
|
|
let ret = 0
|
|
for c in range(b:jlblk_count)
|
|
let last_seen_pos = getpos('.')
|
|
|
|
call s:moveto_currentblock_end()
|
|
if s:on_end()
|
|
call s:matchit()
|
|
endif
|
|
|
|
if s:moveto_block_delim(1, 1, 1)
|
|
" NOTE: normal! he does not work unless &whichwrap inlcudes h
|
|
normal! h
|
|
normal! e
|
|
let ret = 1
|
|
else
|
|
call setpos('.', last_seen_pos)
|
|
endif
|
|
endfor
|
|
|
|
if !ret
|
|
return s:abort()
|
|
endif
|
|
|
|
call s:set_mark_tick()
|
|
call s:restore_view()
|
|
|
|
return 1
|
|
endfunction
|
|
|
|
function! julia_blocks#whereami()
|
|
let b:jlblk_count = v:count1
|
|
let save_redraw = &lazyredraw
|
|
setlocal lazyredraw
|
|
let pos = getpos('.')
|
|
let ret = julia_blocks#select_a('w')
|
|
if empty(ret)
|
|
call setpos('.', pos)
|
|
let &l:lazyredraw = save_redraw
|
|
return ""
|
|
end
|
|
let [start_pos, end_pos] = ret
|
|
let m = getline(start_pos[1])[start_pos[2]-1:]
|
|
|
|
" If cursor_moved was not forced from select_a, we force it now
|
|
" (TODO: this is *really* ugly)
|
|
if end_pos != pos
|
|
call s:cursor_moved(1)
|
|
endif
|
|
call setpos('.', pos)
|
|
call s:restore_view()
|
|
let &l:lazyredraw = save_redraw
|
|
return m
|
|
endfunction
|
|
|
|
" Block text objects
|
|
|
|
function! s:find_block(current_mode)
|
|
|
|
let flags = 'W'
|
|
|
|
if b:jlblk_did_select
|
|
call setpos('.', b:jlblk_last_start_pos)
|
|
if !s:cycle_until_end()
|
|
return s:abort()
|
|
endif
|
|
if !(a:current_mode[0] == 'a' && a:current_mode == b:jlblk_last_mode)
|
|
let flags .= 'c'
|
|
endif
|
|
elseif s:on_end()
|
|
let flags .= 'c'
|
|
" NOTE: using "normal! lb" fails at the end of the file (?!)
|
|
normal! l
|
|
normal! b
|
|
endif
|
|
let searchret = searchpair(b:julia_begin_keywordsm, '', b:julia_end_keywords, flags, b:match_skip)
|
|
if searchret <= 0
|
|
if !b:jlblk_did_select
|
|
return s:abort()
|
|
else
|
|
call setpos('.', b:jlblk_last_end_pos)
|
|
endif
|
|
endif
|
|
|
|
let end_pos = getpos('.')
|
|
" Jump to match
|
|
call s:matchit()
|
|
let start_pos = getpos('.')
|
|
|
|
let b:jlblk_last_start_pos = copy(start_pos)
|
|
let b:jlblk_last_end_pos = copy(end_pos)
|
|
|
|
return [start_pos, end_pos]
|
|
endfunction
|
|
|
|
function! s:repeated_find(ai_mode)
|
|
let repeat = b:jlblk_count + (a:ai_mode == 'i' && v:count1 > 1 ? 1 : 0)
|
|
for c in range(repeat)
|
|
let current_mode = (c < repeat - 1 ? 'a' : a:ai_mode)
|
|
let ret_find_block = s:find_block(current_mode)
|
|
if empty(ret_find_block)
|
|
return 0
|
|
endif
|
|
let [start_pos, end_pos] = ret_find_block
|
|
call setpos('.', end_pos)
|
|
let b:jlblk_last_mode = current_mode
|
|
if c < repeat - 1
|
|
let b:jlblk_doing_select = 0
|
|
let b:jlblk_did_select = 1
|
|
endif
|
|
endfor
|
|
return [start_pos, end_pos]
|
|
endfunction
|
|
|
|
function! julia_blocks#select_a(...)
|
|
let mode_flag = a:0 > 0 ? a:1 : ''
|
|
call s:get_save_pos(!b:jlblk_did_select)
|
|
let current_pos = getpos('.')
|
|
let ret_find_block = s:repeated_find('a' . mode_flag)
|
|
if empty(ret_find_block)
|
|
return 0
|
|
endif
|
|
let [start_pos, end_pos] = ret_find_block
|
|
|
|
call setpos('.', end_pos)
|
|
normal! e
|
|
let end_pos = getpos('.')
|
|
|
|
let b:jlblk_doing_select = 1
|
|
|
|
" CursorMove is only triggered if end_pos
|
|
" end_pos is different than the staring position;
|
|
" so when starting from the 'd' in 'end' we need to
|
|
" force it
|
|
if current_pos == end_pos
|
|
call s:cursor_moved(1)
|
|
endif
|
|
|
|
call s:set_mark_tick()
|
|
return [start_pos, end_pos]
|
|
endfunction
|
|
|
|
function! julia_blocks#select_i()
|
|
call s:get_save_pos(!b:jlblk_did_select)
|
|
let current_pos = getpos('.')
|
|
let ret_find_block = s:repeated_find('i')
|
|
if empty(ret_find_block)
|
|
return 0
|
|
endif
|
|
let [start_pos, end_pos] = ret_find_block
|
|
|
|
if end_pos[1] <= start_pos[1]+1
|
|
return s:abort()
|
|
endif
|
|
|
|
call setpos('.', end_pos)
|
|
|
|
let b:jlblk_doing_select = 1
|
|
|
|
let start_pos[1] += 1
|
|
call setpos('.', start_pos)
|
|
normal! ^
|
|
let start_pos = getpos('.')
|
|
let end_pos[1] -= 1
|
|
let end_pos[2] = len(getline(end_pos[1]))
|
|
|
|
" CursorMove is only triggered if end_pos
|
|
" end_pos is different than the staring position;
|
|
" so when starting from the 'd' in 'end' we need to
|
|
" force it
|
|
if current_pos == end_pos
|
|
call s:cursor_moved(1)
|
|
endif
|
|
|
|
call s:set_mark_tick()
|
|
return [start_pos, end_pos]
|
|
endfunction
|
|
|
|
function julia_blocks#select_reset()
|
|
let b:jlblk_did_select = 0
|
|
let b:jlblk_doing_select = 0
|
|
let b:jlblk_inwrapper = 0
|
|
let b:jlblk_last_mode = ""
|
|
endfunction
|
|
|
|
function! s:cursor_moved(...)
|
|
if b:jlblk_inwrapper && !(a:0 > 0 && a:1)
|
|
return
|
|
endif
|
|
let b:jlblk_did_select = b:jlblk_doing_select
|
|
let b:jlblk_doing_select = 0
|
|
endfunction
|
|
|
|
endif
|