我正在尝试创建一个Vim插件,它会在加载时分割窗口并模拟终端顶部的信息栏。我有点工作,但我认为我已经达到了我对Vim语法的限制,或者我的代码中存在逻辑问题。
期望的效果是从活动缓冲区中的当前位置反向搜索Perl子例程的任何声明,并在顶部缓冲区中显示该行。当我用 Ctrl - R 切换缓冲区时,我也试图让它跳过缓冲区。到目前为止我的尝试可以在嵌套的if语句中看到。
无论如何,这里是the code。我非常感谢任何人的反馈。
let s:current_function_bufname = 'Current\ Function\/Subroutine'
function! s:get_current_function_name(no_echo)
let lnum = line(".")
let col = col(".")
if a:no_echo
let s:current_function_name = getline(search("^[^s]*sub .*$", 'bW'))
else
echohl ModeMsg
echo getline(search("^[^s]*sub .*$", 'bW'))
"echo getline(search("^[^ \t#/]\\{2}.*[^:]\s*$", 'bW'))
echohl None
endif
endfunction
let s:previous_winbufnr = 1
let s:current_function_name = ''
let s:current_function_buffer_created = 0
let s:current_function_bufnr = 2
function! s:show_current_function()
let total_buffers = winnr('$')
let current_winbufnr = winnr()
if s:previous_winbufnr != current_winbufnr
if bufname(current_winbufnr) == s:current_function_bufname
if s:previous_winbufnr < current_winbufnr
let i = current_winbufnr + 1
if i > total_buffers
let i = 1
endif
if i == s:current_function_bufnr
let i = i + 1
endif
if i > total buffers
let i = 1
endif
exec i.'wincmd w'
else
let i = current_winbufnr - 1
if i < 1
let i = total_buffers
endif
if i == s:current_function_bufnr
let i = i - 1
endif
if i < 1
let i = total_buffers
endif
try
exec i.'wincmd w'
finally
exec total_buffers.'wincmd w'
endtry
endif
endif
let s:previous_winbufnr = current_winbufnr
return 1
endif
if s:current_function_buffer_created == 0
exec 'top 1 split '.s:current_function_bufname
call s:set_as_scratch_buffer()
let s:current_function_buffer_created = 1
let s:current_function_bufnr = winnr()
endif
call s:activate_buffer_by_name(s:current_function_bufname)
setlocal modifiable
call s:get_current_function_name(1)
call setline(1, s:current_function_name)
setlocal nomodifiable
call s:activate_buffer_by_name(bufname(current_winbufnr))
endfunction
function! s:set_as_scratch_buffer()
setlocal noswapfile
setlocal nomodifiable
setlocal bufhidden=delete
setlocal buftype=nofile
setlocal nobuflisted
setlocal nonumber
setlocal nowrap
setlocal cursorline
endfunction
function! s:activate_buffer_by_name(name)
for i in range(1, winnr('$'))
let name = bufname(winbufnr(i))
let full_name = fnamemodify(bufname(winbufnr(i)), ':p')
if name == a:name || full_name == a:name
exec i.'wincmd w'
return 1
endif
endfor
return 0
endfunction
set laststatus=2
autocmd! CursorMoved,CursorMovedI,BufWinEnter * call s:show_current_function()
类似于问题VIM: display custom reference bar on top of window和Vim Tips wiki页面Show current function name in C programs。
答案 0 :(得分:1)
在审核了@Prakash建议的http://blogs.perl.org/users/ovid/2011/01/show-perl-subname-in-vim-statusline.html上的代码之后,我决定分享我对该脚本的改进。
我在他的网站上播放了一段代码并做了一些改进。如果您在子例程之外,这将显示N/A
。如果您的右括号缩进的历史记录与您的子声明缩进不匹配,则可能需要更改$indent
部分。玩得开心!
.vimrc
:
syntax on
setlocal laststatus=2
setlocal statusline=\ %{HasPaste()}%F%m%r%h\ %w\ \ CWD:\ %r%{CurDir()}%h\ \ \ Position:\ %p%%\ %l/%L,%c
if has("autocmd")
autocmd BufReadPost * if &syntax == 'perl' | source ~/.vim/perl_current_subroutine | endif
endif
.vim/perl_current_subroutine
:
if ! exists("b:did_perl_statusline") && &syntax == 'perl'
setlocal statusline+=%(\ \ \ Subroutine:\ %{StatusLineIndexLine()}%)
let b:did_perl_statusline = 1
endif
if has('perl')
perl << EOP
use strict;
sub current_perl_subroutine {
my $curwin = $main::curwin;
my $curbuf = $main::curbuf;
my $sub_name = 'N/A';
#search up from cursor line to find a declaration of a subroutine
my $line_number = ($curwin->Cursor)[0];
my $line = $curbuf->Get($line_number);
my $indent = '';
if ($line !~ /^(\s*)sub\s+(\w+)\b/) {
$line = $curbuf->Get($line_number) while ($line_number-- > 0 && $line !~ /^(\s*)sub\s+(\w+)\b/);
($indent, $sub_name) = ($1, $2);
} else {
$line_number--;
($indent, $sub_name) = ($1, $2);
}
#if found, (try to) find the end of the subroutine
if ($sub_name ne 'N/A') {
my $end = $curbuf->Count();
$line = $curbuf->Get($line_number);
if ($line !~ /}\s*$/) {
$line = $curbuf->Get($line_number) while ($line_number++ < $end && $line !~ /^($indent)?}\s*$/);
$line_number--;
}
$sub_name = 'N/A' if ($line =~ /^($indent)?}\s*$/ && ($curwin->Cursor)[0] > $line_number);
}
VIM::DoCommand("let current_perl_subroutine_name='$sub_name'");
}
EOP
function! StatusLineIndexLine()
perl current_perl_subroutine()
return current_perl_subroutine_name
endfunction
endif