Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Searching declaration in PHP ftplugin (Fix [[, ]] mappings problems, added [], ][ mappings)
--- php.vim.bak 2018-10-10 14:08:25.875669800 +0900
+++ php.vim 2018-10-10 14:04:30.777334700 +0900
@@ -61,15 +61,107 @@
setlocal omnifunc=phpcomplete#CompletePHP
endif
-" Section jumping: [[ and ]] provided by Antony Scriven <adscriven at gmail dot com>
-let s:function = '\(abstract\s\+\|final\s\+\|private\s\+\|protected\s\+\|public\s\+\|static\s\+\)*function'
-let s:class = '\(abstract\s\+\|final\s\+\)*class'
+" Section jumping: [[ and ]] provided by:
+" * Antony Scriven <adscriven at gmail dot com>
+" * Takuya Fujiwara <tyru dot exe at gmail dot com>
+" Operator-pending mappings are linewise (:help linewise)
+nnoremap <buffer><silent> [[ :<C-u>call <SID>searchSection('sbW')<CR>
+onoremap <buffer><silent> [[ V:<C-u>call <SID>searchSection('sbW')<CR>
+nnoremap <buffer><silent> ]] :<C-u>call <SID>searchSection('sW')<CR>
+onoremap <buffer><silent> ]] V:<C-u>call <SID>searchSection('sW')<CR>
+nnoremap <buffer><silent> [] :<C-u>call <SID>searchDeclEnd(1)<CR>
+onoremap <buffer><silent> [] V:<C-u>call <SID>searchDeclEnd(1)<CR>
+nnoremap <buffer><silent> ][ :<C-u>call <SID>searchDeclEnd(0)<CR>
+onoremap <buffer><silent> ][ V:<C-u>call <SID>searchDeclEnd(0)<CR>
+
+let s:function = '\%(abstract\s\+\|final\s\+\|private\s\+\|protected\s\+\|public\s\+\|static\s\+\)*function'
+let s:class = '\%(abstract\s\+\|final\s\+\)*class'
let s:interface = 'interface'
-let s:section = '\(.*\%#\)\@!\_^\s*\zs\('.s:function.'\|'.s:class.'\|'.s:interface.'\)'
-exe 'nno <buffer> <silent> [[ ?' . escape(s:section, '|') . '?<CR>:nohls<CR>'
-exe 'nno <buffer> <silent> ]] /' . escape(s:section, '|') . '/<CR>:nohls<CR>'
-exe 'ono <buffer> <silent> [[ ?' . escape(s:section, '|') . '?<CR>:nohls<CR>'
-exe 'ono <buffer> <silent> ]] /' . escape(s:section, '|') . '/<CR>:nohls<CR>'
+let s:section = '\%(.*\%#\)\@!\_^\s*\zs\%('.s:function.'\|'.s:class.'\|'.s:interface.'\)'
+
+function! s:searchSection(flags) abort
+ return search(s:section, a:flags)
+endfunction
+
+function! s:searchDeclEnd(backward) abort
+ let prevpos = getcurpos()
+ let ok = 0
+ try
+ if s:doSearchDeclEnd(a:backward)
+ let ok = 1
+ endif
+ finally
+ " Save to jumplist
+ let nextpos = s:curpos()
+ call setpos('.', prevpos)
+ if ok
+ call s:move(nextpos)
+ endif
+ endtry
+endfunction
+
+function! s:doSearchDeclEnd(backward) abort
+ let curpos = s:curpos()
+ let [begin, end] = s:searchBlock('bcW')
+ if a:backward
+ if s:between(begin, curpos, end)
+ return s:searchSection('bW') && s:searchSection('bW') && s:searchEndBlock()
+ else
+ return 1
+ endif
+ else
+ if s:between(begin, curpos, end) && curpos[0] < end[0]
+ return 1
+ else
+ return s:searchSection('W') && s:searchEndBlock()
+ endif
+ endif
+endfunction
+
+function! s:searchBlock(flags) abort
+ if !s:searchSection(a:flags)
+ return [0, 0]
+ endif
+ let begin = s:curpos()
+ if !s:searchEndBlock()
+ return [0, 0]
+ endif
+ let end = s:curpos()
+ return [begin, end]
+endfunction
+
+" NOTE: This function must be called on the declaration line
+function! s:searchEndBlock() abort
+ let pos = s:curpos()
+ " if '{' is after section, jump to matched '}'
+ keepjumps normal! f{
+ if s:curpos() !=# pos
+ keepjumps normal! %
+ return 1
+ endif
+ " Otherwise the next non-blank line should have '{'
+ normal! j
+ if search('\%' . nextnonblank('.') . 'l^\s*\zs{')
+ keepjumps normal! %
+ return 1
+ endif
+ return 0
+endfunction
+
+function! s:curpos() abort
+ return getcurpos()[1:2]
+endfunction
+
+function! s:between(begin, pos, end) abort
+ return a:begin[0] <=# a:pos[0] && a:pos[0] <=# a:end[0]
+endfunction
+
+" This function also updates jumplist (setpos() and cursor() doesn't update it)
+function! s:move(pos) abort
+ let [lnum, col] = a:pos
+ let offset = line2byte(lnum)
+ execute printf('normal! %dgo', offset + col - 1)
+endfunction
setlocal commentstring=/*%s*/
@tyru
Copy link
Author

tyru commented Jun 6, 2019

I have sent an email to maintainers at 2018/09/26 (But no response 😭).

I created a patch for PHP ftplugin in vim runtime source code.
I suppose Dan is the maintainer of this ftplugin,
and Antony provided [[ and ]] mappings (accoding to the comment).

I fixed [[, ]] problem and added [], ][ mappings.

Problems:

  • [[ and ]] destroys @/ register so 'n', 'N', ... commands cannot work
    as expected after using [[, ]]
  • [] and ][ commands are missing

Some notes about new [] and ][ commands:

  • Operator-pending mappings are linewise (:help linewise), so 'd]['
    and 'd[]' works like 'dj', 'dk'
  • [] and ][ update jumplist as well as [[ and ]]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment