Skip to content

Commit

Permalink
Added movement by block segments
Browse files Browse the repository at this point in the history
fixes #1
  • Loading branch information
tweekmonster committed Feb 22, 2016
1 parent a21d0d2 commit 994f3d8
Show file tree
Hide file tree
Showing 5 changed files with 256 additions and 11 deletions.
12 changes: 12 additions & 0 deletions autoload/braceless.vim
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,18 @@ function! braceless#get_block_lines(line, ...)
endfunction


function! braceless#get_parent_block_lines(line, ...)
let saved = winsaveview()
let block = braceless#get_block_lines(a:line)
let [indent_char, indent_len] = braceless#indent#space(block[2], -1)
call cursor(block[2], 0)
let sub = search('^'.indent_char.'{-,'.indent_len.'}\S', 'nbW')
let parent = braceless#get_block_lines(sub)
call winrestview(saved)
return [parent, block]
endfunction


" Kinda like black ops, but more exciting.
function! braceless#block_op(motion, keymode, vmode, op, count)
let pattern = braceless#get_pattern()
Expand Down
138 changes: 138 additions & 0 deletions autoload/braceless/movement.vim
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,141 @@ function! braceless#movement#block(direction, vmode, by_indent, count)
let i -= 1
endwhile
endfunction



" Note: I think everything below needs some refactoring.

" Positions the cursor after movement in function below
function! s:position_inner_block(pat, top)
if a:top
let top = braceless#scan_head(a:pat, 'nceb')[0]
if top == 0
let top = 1
else
let block = braceless#get_block_lines(top + 1)
if block[1] < line('.')
let top = nextnonblank(block[1] + 1)
else
let top = nextnonblank(top + 1)
endif
endif
let [_, indent_len] = braceless#indent#space(top, 0)
call cursor(top, indent_len + 1)
else
let bottom = braceless#scan_head(a:pat, 'nc')[0]
if bottom == 0
let bottom = prevnonblank(line('.'))
else
let block = braceless#get_block_lines(line('.'))
if block[1] < bottom
let bottom = prevnonblank(block[1])
else
let bottom = prevnonblank(bottom - 1)
endif
endif
call cursor(bottom, col([bottom, '$']) - 1)
endif
endfunction


" Returns the line of the next block boundary depending on direction. A block
" boundary is considered anything that's between block heads and block ends,
" and vice versa.
function! s:skip_boundary(pat, direction, start)
let flags = 'W'
if a:direction == -1
let flags .= 'b'
else
let flags .= 'e'
endif
let pos = getpos('.')[1:2]
let found = braceless#scan_head(a:pat, flags)[0]

if found == 0
if a:direction == -1
let l = prevnonblank(pos[0] - 1)
if l == 0
let l = 1
endif
else
let l = nextnonblank(pos[0] + 1)
if l == 0
let l = line('$')
endif
endif

call cursor(pos)
return l
endif

if a:direction == -1
let block = braceless#get_block_lines(found)
if block[0] != 0 && block[1] < pos[0]
let found = prevnonblank(block[1])
else
let prev_found = braceless#scan_head(a:pat, flags.'n')[0]
if abs(found - prev_found) <= 1
let found = s:skip_boundary(a:pat, a:direction, a:start)
else
let found = prevnonblank(found - 1)
endif
endif
else
let block = braceless#get_block_lines(pos[0])
let n = nextnonblank(block[1] + 1)
if n != 0 && n < found
" Too far beyond the current block
let found = nextnonblank(n - 1)
else
let next_found = braceless#scan_head(a:pat, flags.'n')[0]
if abs(next_found - found) <= 1
" Too close to another block head
let found = s:skip_boundary(a:pat, a:direction, a:start)
else
let found = nextnonblank(found + 1)
endif
endif
endif

call cursor(pos)
return found
endfunction


function! braceless#movement#inner_block(direction, vmode, inclusive, top)
if a:vmode == 'v'
normal! gv
endif

let pattern = braceless#get_pattern()
let pat = '^\s*'
if pattern.jump !~ '\\zs'
let pat .= '\zs'
endif
let pat .= pattern.jump

let c = a:inclusive ? v:count : v:count1
let pos = getpos('.')[1:2]
let flag = ''
let alt_flag = ''
if a:direction == -1
let flag = 'b'
let next_flag = 'nb'
else
let flag = 'e'
let next_flag = 'ne'
endif

let c_line = line('.')
while c > 0
let c_line = s:skip_boundary(pat, a:direction, c_line)
if c_line == 0
break
endif
call cursor(c_line, 0)
let c -= 1
endwhile

call s:position_inner_block(pat, a:top)
endfunction
24 changes: 24 additions & 0 deletions plugin/braceless.vim
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ let s:nomodline_avail = v:version > 703 || (v:version == 703 && has('patch438'))
let g:loaded_braceless = 1


let g:braceless#key#segment = get(g:, 'braceless_segment_key', '<tab>')
let g:braceless#key#block = get(g:, 'braceless_block_key', 'P')
let g:braceless#key#jump_prev = get(g:, 'braceless_jump_prev_key', '[')
let g:braceless#key#jump_next = get(g:, 'braceless_jump_next_key', ']')
Expand All @@ -29,6 +30,18 @@ function! s:enable(...)

let b:braceless_enabled = 1

if !empty(g:braceless#key#segment)
execute 'map <buffer> ['.g:braceless#key#segment.' <Plug>(braceless-jump-inner-prev)'
execute 'map <buffer> ]'.g:braceless#key#segment.' <Plug>(braceless-jump-inner-next)'
execute 'map <buffer> '.g:braceless#key#segment.'k <Plug>(braceless-jump-inner-prev-ex)'
execute 'map <buffer> '.g:braceless#key#segment.'j <Plug>(braceless-jump-inner-next-ex)'

execute 'vmap <buffer> ['.g:braceless#key#segment.' <Plug>(braceless-jump-inner-prev-v)'
execute 'vmap <buffer> ]'.g:braceless#key#segment.' <Plug>(braceless-jump-inner-next-v)'
execute 'vmap <buffer> '.g:braceless#key#segment.'k <Plug>(braceless-jump-inner-prev-v-ex)'
execute 'vmap <buffer> '.g:braceless#key#segment.'j <Plug>(braceless-jump-inner-next-v-ex)'
endif

if !empty(g:braceless#key#block)
execute 'vmap <buffer> i'.g:braceless#key#block.' <Plug>(braceless-i-v)'
execute 'vmap <buffer> a'.g:braceless#key#block.' <Plug>(braceless-a-v)'
Expand Down Expand Up @@ -124,11 +137,22 @@ endfunction


function! s:init()

vnoremap <silent> <Plug>(braceless-i-v) :<C-u>call braceless#block_op('i', 'v', visualmode(), '', v:count1)<cr>
vnoremap <silent> <Plug>(braceless-a-v) :<C-u>call braceless#block_op('a', 'v', visualmode(), '', v:count1)<cr>
onoremap <silent> <Plug>(braceless-i-n) :<C-u>call braceless#block_op('i', 'n', visualmode(), v:operator, v:count1)<cr>
onoremap <silent> <Plug>(braceless-a-n) :<C-u>call braceless#block_op('a', 'n', visualmode(), v:operator, v:count1)<cr>
vnoremap <silent> <Plug>(braceless-jump-inner-prev-v) :<C-u>call braceless#movement#inner_block(-1, 'v', 1, 1)<cr>
vnoremap <silent> <Plug>(braceless-jump-inner-next-v) :<C-u>call braceless#movement#inner_block(1, 'v', 1, 0)<cr>
vnoremap <silent> <Plug>(braceless-jump-inner-prev-v-ex) :<C-u>call braceless#movement#inner_block(-1, 'v', 0, 0)<cr>
vnoremap <silent> <Plug>(braceless-jump-inner-next-v-ex) :<C-u>call braceless#movement#inner_block(1, 'v', 0, 1)<cr>
noremap <silent> <Plug>(braceless-jump-inner-prev) :<C-u>call braceless#movement#inner_block(-1, 'n', 1, 1)<cr>
noremap <silent> <Plug>(braceless-jump-inner-next) :<C-u>call braceless#movement#inner_block(1, 'n', 1, 0)<cr>
noremap <silent> <Plug>(braceless-jump-inner-prev-ex) :<C-u>call braceless#movement#inner_block(-1, 'n', 0, 0)<cr>
noremap <silent> <Plug>(braceless-jump-inner-next-ex) :<C-u>call braceless#movement#inner_block(1, 'n', 0, 1)<cr>
vnoremap <silent> <Plug>(braceless-jump-prev-v) :<C-u>call braceless#movement#block(-1, visualmode(), 0, v:count1)<cr>
vnoremap <silent> <Plug>(braceless-jump-next-v) :<C-u>call braceless#movement#block(1, visualmode(), 0, v:count1)<cr>
vnoremap <silent> <Plug>(braceless-jump-prev-v-indent) :<C-u>call braceless#movement#block(-1, visualmode(), 1, v:count1)<cr>
Expand Down
91 changes: 80 additions & 11 deletions test/motion.vader
Original file line number Diff line number Diff line change
Expand Up @@ -199,8 +199,8 @@ Expect python (third function returned to first column):
def example():
pass

Given python (nested blocks):
=============================
Given python (segmented block gauntlet):
========================================
class Example(object):
def __init__(self):
print('hello')
Expand All @@ -209,17 +209,86 @@ Given python (nested blocks):
if True:
pass

def something(self):
print('hello again')
print('hello again')

def never(self):
if True:
print('something')
print('happened')
if True:
print('gonna')

print('give')
else:
print('you')

def up(self):
if True:
print('never')
print('gonna')
else:
print('let')

def you(self):
if True:
print('down')
print('never')
else:
print('gonna')

def run(self):
if True:
print('around')
print('and')
else:
print('nothing')
print('desert')

Do (jump to first inner block):
===============================
]t
print('you')

Execute (verify cursor):
========================
Execute (move by block segments):
=====================
normal \j
AssertCursor 3, 9
normal \j
AssertCursor 7, 13
normal \j
AssertCursor 9, 9
normal \j
AssertCursor 15, 17
normal \j
AssertCursor 19, 17
normal 3\j
AssertCursor 30, 13
normal G$\k
AssertCursor 40, 27
normal \k
AssertCursor 38, 24
normal \k
AssertCursor 33, 26
normal 5\k
AssertCursor 17, 29
normal 99\j
AssertCursor 42, 9
normal 99\k
AssertCursor 1, 22

Execute (move by inner block):
==============================
normal \j
normal ]\
AssertCursor 4, 23
normal ]\
AssertCursor 4, 23
normal [\
AssertCursor 3, 9
normal [\
AssertCursor 3, 9
normal 1]\
AssertCursor 7, 16
normal [\
AssertCursor 7, 13
normal 2]\
AssertCursor 17, 29
normal 99]\
AssertCursor 42, 20
normal 99[\
AssertCursor 1, 1
2 changes: 2 additions & 0 deletions test/test.vader
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ Execute (setup):

set rtp+=..

let g:braceless_segment_key = '\'

function! AssertCursor(line, ...)
if a:0
let pos = getpos('.')[1:2]
Expand Down

0 comments on commit 994f3d8

Please sign in to comment.