Here is a small function, that seems to do what you want:
function! Move(up)
let curpos = getcurpos()
let firstline='\(^\s*\n\)\zs\S\+'
let lastline ='\S\+\ze\n\s*$'
let flags = 'Wn'. (a:up ? 'b' : '')
" Move to first or last line of paragraph,
" or to the beginning/end of file
let pat = '\('.firstline.'\|'.lastline.'\)\|\%^\|\%$'
if a:up
" make sure cursor moves up and search
" does not get stuck on current line
call cursor(line('.'),1)
endif
let target=search(pat, flags)
if target > 0
let curpos[1]=target
let curpos[2]=curpos[4]
endif
call setpos('.',curpos)
endfu
nnoremap <silent> <leader>j :call Move(0)<cr>
nnoremap <silent> <leader>k :call Move(1)<cr>
This relies on the getcurpos() function, which has been included as patch 7.4.578. If you don't have it, you can use the winsaveview()/winrestview()
function, to work around it. This might however mess up the screen, not sure this will work reliably. (with a newer vim, you can throw away the values in the dictionary returned by winsaveview()
and only update the other values, but that is not possible with older vims as well).
function! Move(up)
let curpos = winsaveview()
let firstline='\(^\s*\n\)\zs\S\+'
let lastline ='\S\+\ze\n\s*$'
let flags = 'Wn'. (a:up ? 'b' : '')
" Move to first or last line of paragraph,
" or to the beginning/end of file
let pat = '\('.firstline.'\|'.lastline.'\)\|\%^\|\%$'
if a:up
" make sure cursor moves up and search
" does not get stuck on current line
call cursor(line('.'),1)
endif
let target=search(pat, flags)
if target > 0
let curpos.lnum=target
let curpos.col=curpos.curswant
endif
call winrestview(curpos)
endfu
nnoremap <silent> <leader>j :call Move(0)<cr>
nnoremap <silent> <leader>k :call Move(1)<cr>