Skip to content
This repository was archived by the owner on Dec 26, 2023. It is now read-only.

Improvement preserve cursor position #24

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 21 additions & 21 deletions autoload/argwrap.vim
Original file line number Diff line number Diff line change
Expand Up @@ -219,30 +219,30 @@ function! argwrap#unwrapContainer(range, container, arguments, padded)
exec printf('silent %d,%dd_', a:range.lineStart + 1, a:range.lineEnd)
endfunction

function! argwrap#getSetting(name, default)
function! argwrap#getSetting(name)
let l:bName = 'b:argwrap_' . a:name
let l:gName = 'g:argwrap_' . a:name

if exists(l:bName)
return {l:bName}
elseif exists(l:gName)
return {l:gName}
else
return a:default
return exists(l:bName) ? {l:bName} : {l:gName}
endfunction

function! argwrap#initSetting(name, value) abort
let l:setting = 'g:argwrap_'.a:name

if !exists(l:setting)
let {l:setting} = a:value
endif
endfunction

function! argwrap#toggle()
let l:cursor = getpos('.')

let l:linePrefix = argwrap#getSetting('line_prefix', '')
let l:padded = argwrap#getSetting('padded_braces', '')
let l:tailComma = argwrap#getSetting('tail_comma', 0)
let l:tailCommaBraces = argwrap#getSetting('tail_comma_braces', '')
let l:tailIndentBraces = argwrap#getSetting('tail_indent_braces', '')
let l:wrapBrace = argwrap#getSetting('wrap_closing_brace', 1)
let l:commaFirst = argwrap#getSetting('comma_first', 0)
let l:commaFirstIndent = argwrap#getSetting('comma_first_indent', 0)
let l:linePrefix = argwrap#getSetting('line_prefix')
let l:padded = argwrap#getSetting('padded_braces')
let l:tailComma = argwrap#getSetting('tail_comma')
let l:tailCommaBraces = argwrap#getSetting('tail_comma_braces')
let l:tailIndentBraces = argwrap#getSetting('tail_indent_braces')
let l:wrapBrace = argwrap#getSetting('wrap_closing_brace')
let l:commaFirst = argwrap#getSetting('comma_first')
let l:commaFirstIndent = argwrap#getSetting('comma_first_indent')

let l:range = argwrap#findClosestRange()
if !argwrap#validateRange(l:range)
Expand All @@ -257,12 +257,12 @@ function! argwrap#toggle()

let l:container = argwrap#extractContainer(l:range)
if l:range.lineStart == l:range.lineEnd
call argwrap#hooks#execute('pre_wrap', l:range, l:container, l:arguments)
call argwrap#wrapContainer(l:range, l:container, l:arguments, l:wrapBrace, l:tailComma, l:tailCommaBraces, l:tailIndentBraces, l:linePrefix, l:commaFirst, l:commaFirstIndent)
let l:cursor[1] = l:range.lineStart + 1
call argwrap#hooks#execute('post_wrap', l:range, l:container, l:arguments)
else
call argwrap#hooks#execute('pre_unwrap', l:range, l:container, l:arguments)
call argwrap#unwrapContainer(l:range, l:container, l:arguments, l:padded)
let l:cursor[1] = l:range.lineStart
call argwrap#hooks#execute('post_unwrap', l:range, l:container, l:arguments)
endif

call setpos('.', l:cursor)
endfunction
53 changes: 53 additions & 0 deletions autoload/argwrap/hooks.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
function! s:loadGlobalHooks() abort " {{{
if !exists('g:argwrap_global_hooks')
let g:argwrap_global_hooks = []

for hook in globpath(&runtimepath, 'autoload/argwrap/hooks/*.vim', 0, 1)
let l:filename = matchstr(hook, '\vhooks/\zs.+\ze\.vim$')

call add(g:argwrap_global_hooks, printf('argwrap#hooks#%s', l:filename))
endfor
endif

return g:argwrap_global_hooks
endfunction " }}}

function! s:loadFiletypeHooks(filetype) abort " {{{
if !exists('g:argwrap_filetype_hooks.'.a:filetype)
let g:argwrap_filetype_hooks[a:filetype] = []
let l:hooks = g:argwrap_filetype_hooks[a:filetype]

for filetypeHook in globpath(&runtimepath, 'autoload/argwrap/hooks/filetype/*/*.vim', 0, 1)
let l:filetype = matchstr(filetypeHook, '\vhooks/filetype/\zs.+\ze/.+\.vim$')
let l:filename = matchstr(filetypeHook, '\vhooks/filetype/.+/\zs.+\ze\.vim$')

call add(l:hooks, printf('argwrap#hooks#filetype#%s#%s', l:filetype, l:filename))
endfor
endif

return g:argwrap_filetype_hooks[a:filetype]
endfunction " }}}

function! s:load() abort " {{{
if !exists('b:argwrap_hooks')
let b:argwrap_hooks = s:loadGlobalHooks() + s:loadFiletypeHooks(&filetype)
endif

return b:argwrap_hooks
endfunction " }}}

function! argwrap#hooks#execute(name, ...) abort " {{{
" Reverse the order of the hooks for post hooks so that a pre hook with a
" low priority is executed before and a post hook is executed after
" For instance for a hook responsible to preserve the cursor position it
" must be the first to be executed to save the position of the cursor but
" the last to be executed to restore it after all other hooks have been
" executed
let l:hooks = a:name =~? '\v^post' ? reverse(copy(s:load())) : s:load()

for hook in l:hooks
silent! call call(printf('%s#%s', hook, a:name), a:000)
endfor
endfunction " }}}

" vim: ts=2 sw=2 et fdm=marker
148 changes: 148 additions & 0 deletions autoload/argwrap/hooks/000_curpos.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
function! s:extractCursorPositionForUnwrappedArguments(range, arguments) abort " {{{
let l:cursorColumn = col('.')
let l:lineText = getline(a:range.lineStart)
let l:position = {}

let l:argumentNumber = 0
for argument in a:arguments
let l:argumentNumber += 1
let l:argumentStart = stridx(l:lineText, argument)
let l:argumentEnd = l:argumentStart + len(argument)

if l:cursorColumn <= l:argumentStart
let l:cursorColumn = l:argumentStart + 1
endif

if l:argumentEnd < l:cursorColumn
if l:lineText[l:cursorColumn - 1:] =~ '\v^,' " Cursor on the separator
if !argwrap#getSetting('comma_first')
let l:cursorColumn = l:argumentEnd + 1
else
let l:position.argumentNumber = l:argumentNumber + 1
let l:position.column = -1

break
endif
elseif l:lineText[l:cursorColumn - 1:] =~ '\v^\s+,' " Cursor before the separator
let l:cursorColumn = l:argumentEnd
endif
endif

if l:cursorColumn <= l:argumentEnd + 1
let l:position.argumentNumber = l:argumentNumber
let l:position.column = l:cursorColumn - l:argumentStart

break
end
endfor

" If the position was not found it's because the cursor is after the last
" argument
if empty(l:position)
let l:position.argumentNumber = l:argumentNumber
let l:position.column = l:argumentEnd - l:argumentStart
endif

return l:position
endfunction " }}}

function! s:extractCursorPositionForWrappedArguments(range, arguments) abort " {{{
let l:position = {}
let l:isCommaFirst = argwrap#getSetting('comma_first')
let l:cursorColumn = col('.')
let l:cursorArgumentNumber = line('.') - a:range.lineStart
" In case the cursor is on the start line
let l:cursorArgumentNumber = min([len(a:arguments), l:cursorArgumentNumber])
" In case the cursor is on the end line
let l:cursorArgumentNumber = max([1, l:cursorArgumentNumber])
let l:argumentLine = getline('.')
let l:argumentText = a:arguments[l:cursorArgumentNumber - 1]
let l:argumentStart = stridx(l:argumentLine, l:argumentText)
let l:argumentEnd = l:argumentStart + len(l:argumentText)
let l:position.argumentNumber = l:cursorArgumentNumber
let l:position.column = l:cursorColumn - l:argumentStart

if l:cursorColumn <= l:argumentStart
let l:position.column = 1

if l:isCommaFirst
if l:argumentLine[l:cursorColumn - 1:] =~ '\v^,' " Cursor on the separator
" The cursor should be placed on the separtor
let l:position.argumentNumber -= 1
let l:position.column = len(a:arguments[l:position.argumentNumber - 1]) + 1
elseif l:argumentLine[l:cursorColumn - 1:] =~ '\v^\s+,' " Cursor before the separator
" The cursor should be placed on the end of the previous argument
let l:position.argumentNumber -= 1
let l:position.column = len(a:arguments[l:position.argumentNumber - 1])
endif
endif
endif

if l:argumentEnd < l:cursorColumn
let l:position.column = len(l:argumentText)

if !l:isCommaFirst
if l:argumentLine[l:cursorColumn - 1:] =~ '\v^\s+,' " Cursor before the separator
" The cursor should be placed on the end of the current argument
elseif l:argumentLine[l:cursorColumn - 1:] =~ '\v^,' " Cursor on the separator
" The cursor should be placed on the separator
let l:position.column += 1
endif
endif
endif

return l:position
endfunction " }}}

function! s:getCursorPositionForWrappedArguments(range, container, arguments) abort " {{{
let l:line = a:range.lineStart + a:container.cursor.argumentNumber
let l:argumentStart = stridx(getline(l:line), a:arguments[a:container.cursor.argumentNumber - 1])
let l:column = l:argumentStart + a:container.cursor.column

return {'line': l:line, 'column': l:column}
endfunction " }}}

function! s:getCursorPositionForUnwrappedArguments(range, container, arguments) abort " {{{
let l:line = a:range.lineStart
let l:column = a:range.colStart

" For each arguments before the one where the cursor must be positioned
for index in range(a:container.cursor.argumentNumber - 1)
" Add the length of the argument + 2 for the separator ', '
let l:column += len(a:arguments[index]) + 2
endfor

let l:column += a:container.cursor.column

return {'line': l:line, 'column': l:column}
endfunction " }}}

function! s:setCursorPosition(position) abort " {{{
let l:curpos = getcurpos()
let l:curpos[1] = a:position.line
let l:curpos[2] = a:position.column

call setpos('.', l:curpos)
endfunction " }}}

function! argwrap#hooks#000_curpos#pre_wrap(range, container, arguments) abort " {{{
let a:container.cursor = s:extractCursorPositionForUnwrappedArguments(a:range, a:arguments)
endfunction " }}}

function! argwrap#hooks#000_curpos#pre_unwrap(range, container, arguments) abort " {{{
let a:container.cursor = s:extractCursorPositionForWrappedArguments(a:range, a:arguments)
endfunction " }}}

function! argwrap#hooks#000_curpos#post_wrap(range, container, arguments) abort " {{{
let l:position = s:getCursorPositionForWrappedArguments(a:range, a:container, a:arguments)

call s:setCursorPosition(l:position)
endfunction " }}}

function! argwrap#hooks#000_curpos#post_unwrap(range, container, arguments) abort " {{{
let l:position = s:getCursorPositionForUnwrappedArguments(a:range, a:container, a:arguments)

call s:setCursorPosition(l:position)
endfunction " }}}

" vim: ts=2 sw=2 et fdm=marker
66 changes: 66 additions & 0 deletions autoload/argwrap/hooks/filetype/php/200_smart_brace.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
function! s:dealWithMethodArguments(container) abort " {{{
if a:container.suffix !~ '\v^\)'
return 0
endif

if a:container.prefix !~? '\v^%(public|protected|private)\s+function\s+\S+\s*\($'
return 0
endif

return 1
endfunction " }}}

function! s:fixMethodOpeningBraceAfterWrap(range, container, arguments) abort " {{{
if !s:dealWithMethodArguments(a:container)
return
endif

let l:lineEnd = a:range.lineEnd + len(a:arguments)

" Add 1 more line if the brace is also wrapped
if 0 != argwrap#getSetting('wrap_closing_brace')
let l:lineEnd += 1
endif

if getline(l:lineEnd + 1) =~ '\v^\s*\{'
execute printf('undojoin | normal! %dGJ', l:lineEnd)
endif
endfunction " }}}

function! s:fixMethodOpeningBraceAfterUnwrap(range, container, arguments) abort " {{{
if !s:dealWithMethodArguments(a:container)
return
endif

if a:container.suffix !~ '\v^\).*\{\s*$'
return
endif

execute printf("undojoin | normal! %dG$F{i\<CR>", a:range.lineStart)
endfunction " }}}

function! argwrap#hooks#filetype#php#200_smart_brace#pre_wrap(range, container, arguments) abort " {{{
" Do nothing but prevent the file to be loaded more than once
" When calling an autoload function that is not define the script that
" should contain it is sourced every time the function is called
endfunction " }}}

function! argwrap#hooks#filetype#php#200_smart_brace#pre_unwrap(range, container, arguments) abort " {{{
" Do nothing but prevent the file to be loaded more than once
" When calling an autoload function that is not define the script that
" should contain it is sourced every time the function is called
endfunction " }}}

function! argwrap#hooks#filetype#php#200_smart_brace#post_wrap(range, container, arguments) abort " {{{
if argwrap#getSetting('php_smart_brace')
call s:fixMethodOpeningBraceAfterWrap(a:range, a:container, a:arguments)
endif
endfunction " }}}

function! argwrap#hooks#filetype#php#200_smart_brace#post_unwrap(range, container, arguments) abort " {{{
if argwrap#getSetting('php_smart_brace')
call s:fixMethodOpeningBraceAfterUnwrap(a:range, a:container, a:arguments)
endif
endfunction " }}}

" vim: ts=2 sw=2 et fdm=marker
Loading