vim-castle/.vim/plugin/tasklist.vim

376 lines
11 KiB
VimL

"------------------------------------------------------------------------------
" Name Of File: tasklist.vim
"
" Description: Vim plugin to search for a list of tokens and display a
" window with matches.
"
" Author: Juan Frias (juandfrias at gmail.com)
"
" Last Change: 2009 Apr 11
" Version: 1.0.1
"
" Copyright: Permission is hereby granted to use and distribute this code,
" with or without modifications, provided that this header
" is included with it.
"
" This script is to be distributed freely in the hope that it
" will be useful, but is provided 'as is' and without warranties
" as to performance of merchantability or any other warranties
" whether expressed or implied. Because of the various hardware
" and software environments into which this script may be put,
" no warranty of fitness for a particular purpose is offered.
"
" GOOD DATA PROCESSING PROCEDURE DICTATES THAT ANY SCRIPT BE
" THOROUGHLY TESTED WITH NON-CRITICAL DATA BEFORE RELYING ON IT.
"
" THE USER MUST ASSUME THE ENTIRE RISK OF USING THE SCRIPT.
"
" The author does not retain any liability on any damage caused
" through the use of this script.
"
" Install: 1. Read the section titled 'Options'
" 2. Setup any variables need in your vimrc file
" 3. Copy 'tasklist.vim' to your plugin directory.
"
" Mapped Keys: <Leader>t Display list.
"
" Usage: Start the script with the mapped key, a new window appears
" with the matches found, moving around the window will also
" update the position of the current document.
"
" The following keys are mapped to the results window:
"
" q - Quit, and restore original cursor position.
"
" e - Exit, and keep results window open note that
" movements on the result window will no longer be
" updated.
"
" <cr> - Quit and place the cursor on the selected line.
"
" Aknowledgments: Many thanks to Zhang Shuhan for taking the time to beta
" test and suggest many of the improvements and features
" found in the script. I don't think I would have
" implemented it wihout his help. Thanks!
"
"------------------------------------------------------------------------------
" Please send me any bugs you find, so I can keep the script up to date.
"------------------------------------------------------------------------------
" History: {{{1
"------------------------------------------------------------------------------
"
" 1.00 Initial version.
"
" User Options: {{{1
"------------------------------------------------------------------------------
"
" <Leader>t
" This is the default key map to view the task list.
" to overwrite use something like:
" map <leader>v <Plug>TaskList
" in your vimrc file
"
" g:tlWindowPosition
" This is specifies the position of the window to be opened. By
" default it will open at on top. To overwrite use:
" let g:tlWindowPosition = 1
" in your vimrc file, options are as follows:
" 0 = Open on top
" 1 = Open on the bottom
"
" g:tlTokenList
" This is the list of tokens to search for default is
" 'FIXME TODO XXX'. The results are groupped and displayed in the
" order that they appear. to overwrite use:
" let g:tlTokenList = ['TOKEN1', 'TOKEN2', 'TOKEN3']
" in your vimrc file
"
" g:tlRememberPosition
" If this is set to 1 then the script will try to get back to the
" position where it last was closed. By default it will find the line
" closest to the current cursor position.
" to overwrite use:
" let g:tlRememberPosition = 1
" in your vimrc file
"
" Global variables: {{{1
"------------------------------------------------------------------------------
" Load script once
"------------------------------------------------------------------------------
if exists("g:loaded_tasklist") || &cp
finish
endif
let g:loaded_tasklist = 1
" Set where the window opens
"------------------------------------------------------------------------------
if !exists('g:tlWindowPosition')
" 0 = Open at top
let g:tlWindowPosition = 0
endif
" Set the token list
"------------------------------------------------------------------------------
if !exists('g:tlTokenList')
" default list of tokens
let g:tlTokenList = ["FIXME", "TODO", "XXX"]
endif
" Remember position
"------------------------------------------------------------------------------
if !exists('g:tlRememberPosition')
" 0 = Donot remember, find closest match
let g:tlRememberPosition = 0
endif
" Script variables: {{{1
"------------------------------------------------------------------------------
" Function: Open Window {{{1
"--------------------------------------------------------------------------
function! s:OpenWindow(buffnr, lineno)
" Open results window and place items there.
if g:tlWindowPosition == 0
execute 'sp -TaskList_'.a:buffnr.'-'
else
execute 'botright sp -TaskList_'.a:buffnr.'-'
endif
let b:original_buffnr = a:buffnr
let b:original_line = a:lineno
set noswapfile
set modifiable
normal! "zPGddgg
set fde=getline(v:lnum)[0]=='L'
set foldmethod=expr
set foldlevel=0
normal! zR
" Resize line if too big.
let l:hits = line("$")
if l:hits < winheight(0)
sil! exe "resize ".l:hits
endif
" Clean up.
let @z = ""
set nomodified
endfunction
" Function: Search file {{{1
"--------------------------------------------------------------------------
function! s:SearchFile(hits, word)
" Search at the beginning and keep adding them to the register
let l:match_count = 0
normal! gg0
let l:max = strlen(line('$'))
let l:last_match = -1
let l:div = 0
while search(a:word, "Wc") > 0
let l:curr_line = line('.')
if l:last_match == l:curr_line
if l:curr_line == line('$')
break
endif
normal! j0
continue
endif
let l:last_match = l:curr_line
if foldlevel(l:curr_line) != 0
normal! 99zo
endif
if l:div == 0
if a:hits != 0
let @z = @z."\n"
endif
let l:div = 1
endif
normal! 0
let l:lineno = ' '.l:curr_line
let @z = @z.'Ln '.strpart(l:lineno, strlen(l:lineno) - l:max).': '
let l:text = getline(".")
let @z = @z.strpart(l:text, stridx(l:text, a:word))
let @z = @z."\n"
normal! $
let l:match_count = l:match_count + 1
endwhile
return l:match_count
endfunction
" Function: Get line number {{{1
"--------------------------------------------------------------------------
function! s:LineNumber()
let l:text = getline(".")
if strpart(l:text, 0, 5) == "File:"
return 0
endif
if strlen(l:text) == 0
return -1
endif
let l:num = matchstr(l:text, '[0-9]\+')
if l:num == ''
return -1
endif
return l:num
endfunction
" Function: Update document position {{{1
"--------------------------------------------------------------------------
function! s:UpdateDoc()
let l:line_hit = <sid>LineNumber()
match none
if l:line_hit == -1
redraw
return
endif
let l:buffnr = b:original_buffnr
exe 'match Search /\%'.line(".").'l.*/'
if line(".") < (line("$") - (winheight(0) / 2)) + 1
normal! zz
endif
execute bufwinnr(l:buffnr)." wincmd w"
match none
if l:line_hit == 0
normal! 1G
else
exe "normal! ".l:line_hit."Gzz"
exe 'match Search /\%'.line(".").'l.*/'
endif
execute bufwinnr('-TaskList_'.l:buffnr.'-')." wincmd w"
redraw
endfunction
" Function: Clean up on exit {{{1
"--------------------------------------------------------------------------
function! s:Exit(key)
call <sid>UpdateDoc()
match none
let l:original_line = b:original_line
let l:last_position = line('.')
if a:key == -1
nunmap <buffer> e
nunmap <buffer> q
nunmap <buffer> <cr>
execute bufwinnr(b:original_buffnr)." wincmd w"
else
bd!
endif
let b:last_position = l:last_position
if a:key == 0
exe "normal! ".l:original_line."G"
endif
match none
normal! zz
execute "set updatetime=".s:old_updatetime
endfunction
" Function: Check for screen update {{{1
"--------------------------------------------------------------------------
function! s:CheckForUpdate()
if stridx(expand("%:t"), '-TaskList_') == -1
return
endif
if b:selected_line != line(".")
call <sid>UpdateDoc()
let b:selected_line = line(".")
endif
endfunction
" Function: Start the search. {{{1
"--------------------------------------------------------------------------
function! s:TaskList()
let l:original_buffnr = bufnr('%')
let l:original_line = line(".")
" last position
if !exists('b:last_position')
let b:last_position = 1
endif
let l:last_position = b:last_position
" get file name
let @z = "File:".expand("%:p")."\n\n"
" search file
let l:index = 0
let l:count = 0
let l:hits = 0
while l:index < len(g:tlTokenList)
let l:search_word = g:tlTokenList[l:index]
let l:hits = s:SearchFile(l:hits, l:search_word)
let l:count = l:count + l:hits
let l:index = l:index + 1
endwhile
" Make sure we at least have one hit.
if l:count == 0
echohl Search
echo "tasklist.vim: No task information found."
echohl None
execute 'normal! '.l:original_line.'G'
return
endif
" display window
call s:OpenWindow(l:original_buffnr, l:original_line)
" restore the cursor position
if g:tlRememberPosition != 0
exec 'normal! '.l:last_position.'G'
else
normal! gg
endif
" Map exit keys
nnoremap <buffer> <silent> q :call <sid>Exit(0)<cr>
nnoremap <buffer> <silent> <cr> :call <sid>Exit(1)<cr>
nnoremap <buffer> <silent> e :call <sid>Exit(-1)<cr>
" Setup syntax highlight {{{
syntax match tasklistFileDivider /^File:.*$/
syntax match tasklistLineNumber /^Ln\s\+\d\+:/
highlight def link tasklistFileDivider Title
highlight def link tasklistLineNumber LineNr
highlight def link tasklistSearchWord Search
" }}}
" Save globals and change updatetime
let b:selected_line = line(".")
let s:old_updatetime = &updatetime
set updatetime=350
" update the doc and hook the CheckForUpdate function.
call <sid>UpdateDoc()
au! CursorHold <buffer> nested call <sid>CheckForUpdate()
endfunction
"}}}
" Command
command! TaskList call s:TaskList()
" Default key map
if !hasmapto('<Plug>TaskList')
map <unique> <Leader>t <Plug>TaskList
endif
" Key map to Command
nnoremap <unique> <script> <Plug>TaskList :TaskList<CR>
" vim:fdm=marker:tw=75:ff=unix: