diff --git a/autoload/SpaceVim/api/prompt.vim b/autoload/SpaceVim/api/prompt.vim new file mode 100644 index 000000000..f7583b23c --- /dev/null +++ b/autoload/SpaceVim/api/prompt.vim @@ -0,0 +1,132 @@ +let s:self = {} + + +let s:self._keys = { + \ 'close' : "\", + \ 'cursor_back' : '', + \ 'cursor_forword' : '', + \ } +let s:self._prompt = { + \ 'mpt' : '==>', + \ 'begin' : '', + \ 'cursor' : '', + \ 'end' : '', + \ } +let s:self._function_key = {} + +let s:self._quit = 1 + +let s:self._handle_fly = '' +let s:self._onclose = '' +let s:self._oninputpro = '' + + + +func! s:self.open() abort + let self._quit = 0 + let save_redraw = &lazyredraw + set nolazyredraw + call self._build_prompt() + call self._handle_input() + let &lazyredraw = save_redraw +endf + +function! s:self._getchar(...) abort + let ret = call('getchar', a:000) + return (type(ret) == type(0) ? nr2char(ret) : ret) +endfunction + +func! s:self._handle_input() abort + while self._quit == 0 + let char = self._getchar() + if has_key(self._function_key, char) + call call(self._function_key[char], []) + continue + endif + if char ==# "\" || char ==# "\" + continue + endif + if char ==# "\" || char == 6 + let self._prompt.begin = self._prompt.begin . self._prompt.cursor + let self._prompt.cursor = matchstr(self._prompt.end, '^.') + let self._prompt.end = substitute(self._prompt.end, '^.', '', 'g') + call self._build_prompt() + continue + elseif char ==# "\" || char == 2 + if self._prompt.begin !=# '' + let self._prompt.end = self._prompt.cursor . self._prompt.end + let self._prompt.cursor = matchstr(self._prompt.begin, '.$') + let self._prompt.begin = substitute(self._prompt.begin, '.$', '', 'g') + call self._build_prompt() + endif + continue + elseif char ==# "\" + let self._prompt.begin = substitute(self._prompt.begin,'[^\ .*]\+\s*$','','g') + call self._build_prompt() + elseif char ==# "\" || char ==# "\" + let self._prompt.end = substitute(self._prompt.begin . self._prompt.cursor . self._prompt.end, '^.', '', 'g') + let self._prompt.cursor = matchstr(self._prompt.begin, '^.') + let self._prompt.begin = '' + call self._build_prompt() + continue + elseif char ==# "\" || char ==# "\" + let self._prompt.begin = self._prompt.begin . self._prompt.cursor . self._prompt.end + let self._prompt.cursor = '' + let self._prompt.end = '' + call self._build_prompt() + continue + elseif char ==# "\" + let self._prompt.begin = '' + call self._build_prompt() + elseif char ==# "\" + let self._prompt.cursor = '' + let self._prompt.end = '' + call self._build_prompt() + elseif char ==# "\" + let self._prompt.begin = substitute(self._prompt.begin,'.$','','g') + call self._build_prompt() + elseif char == self._keys.close + call self.close() + break + else + let self._prompt.begin .= char + call self._build_prompt() + endif + if self._oninputpro !=# '' + call call(self._oninputpro, []) + endif + if self._handle_fly !=# '' + call call(self._handle_fly, [self._prompt.begin . self._prompt.cursor . self._prompt.end]) + endif + endwhile +endf + +func! s:self._build_prompt() abort + redraw + echohl Comment | echon self._prompt.mpt + echohl None | echon self._prompt.begin + echohl Wildmenu | echon self._prompt.cursor + echohl None | echon self._prompt.end +endf + +function! s:self._clear_prompt() abort + let self._prompt = { + \ 'mpt' : self._prompt.mpt, + \ 'begin' : '', + \ 'cursor' : '', + \ 'end' : '', + \ } +endfunction + +function! s:self.close() abort + if self._onclose !=# '' + call call(self._onclose, []) + endif + call self._clear_prompt() + normal! : + let self._quit = 1 +endfunction + +function! SpaceVim#api#prompt#get() abort + return deepcopy(s:self) +endfunction diff --git a/autoload/SpaceVim/layers/core/statusline.vim b/autoload/SpaceVim/layers/core/statusline.vim index 323fa7307..63b6a3d99 100644 --- a/autoload/SpaceVim/layers/core/statusline.vim +++ b/autoload/SpaceVim/layers/core/statusline.vim @@ -214,6 +214,10 @@ function! SpaceVim#layers#core#statusline#get(...) abort \ . '%#SpaceVim_statusline_a_bold_SpaceVim_statusline_b# %{get(unite#get_context(), "buffer_name", "")} ' \ . '%#SpaceVim_statusline_b_SpaceVim_statusline_c# ' \ . '%#SpaceVim_statusline_c# %{unite#get_status_string()} ' + elseif &filetype ==# 'SpaceVimFlyGrep' + return '%#SpaceVim_statusline_a# FlyGrep %#SpaceVim_statusline_a_SpaceVim_statusline_b#' + \ . '%#SpaceVim_statusline_b# %{getcwd()}%#SpaceVim_statusline_b_SpaceVim_statusline_c#' + \ . '%#SpaceVim_statusline_c# %{SpaceVim#plugins#flygrep#lineNr()}' endif if a:0 > 0 return s:active() diff --git a/autoload/SpaceVim/mapping/space.vim b/autoload/SpaceVim/mapping/space.vim index 823c1e1c0..62c5d0a27 100644 --- a/autoload/SpaceVim/mapping/space.vim +++ b/autoload/SpaceVim/mapping/space.vim @@ -196,6 +196,9 @@ function! SpaceVim#mapping#space#init() abort call SpaceVim#mapping#space#def('nnoremap', ['s', 't', 'J'], 'call SpaceVim#plugins#searcher#find(expand(""), "pt")', \ 'Background search cursor words in project with pt', 1) + call SpaceVim#mapping#space#def('nnoremap', ['s', 'g', 'G'], 'call SpaceVim#plugins#flygrep#open()', + \ 'grep on the fly', 1) + call SpaceVim#mapping#space#def('nnoremap', ['s', 'c'], 'noh', \ 'clear search highlight', 1) endfunction diff --git a/autoload/SpaceVim/plugins/flygrep.vim b/autoload/SpaceVim/plugins/flygrep.vim new file mode 100644 index 000000000..1ecd7fc18 --- /dev/null +++ b/autoload/SpaceVim/plugins/flygrep.vim @@ -0,0 +1,133 @@ +let s:MPT = SpaceVim#api#import('prompt') +let s:JOB = SpaceVim#api#import('job') +let s:grepid = 0 + + +function! SpaceVim#plugins#flygrep#open() abort + rightbelow split __flygrep__ + setlocal buftype=nofile bufhidden=wipe nobuflisted nolist noswapfile nowrap cursorline nospell nonu norelativenumber + " setlocal nomodifiable + setf SpaceVimFlyGrep + redraw! + call s:MPT.open() +endfunction + +function! s:flygrep(expr) abort + call s:MPT._build_prompt() + if a:expr ==# '' + redrawstatus + return + endif + try + syn clear FileNames + catch + endtr + exe 'syn match FileNames /' . substitute(a:expr, '\([/\\]\)', '\\\1', 'g') . '/' + hi def link FileNames MoreMsg + let exe = SpaceVim#mapping#search#default_tool() + let s:grepid = s:JOB.start(s:get_search_cmd(exe, a:expr), { + \ 'on_stdout' : function('s:grep_stdout'), + \ 'in_io' : 'null', + \ 'on_exit' : function('s:grep_exit'), + \ }) +endfunction + +let s:MPT._handle_fly = function('s:flygrep') + +function! s:close_buffer() abort + q +endfunction + +let s:MPT._onclose = function('s:close_buffer') + + +function! s:close_grep_job() abort + if s:grepid != 0 + call s:JOB.stop(s:grepid) + endif + normal! "_ggdG +endfunction + +let s:MPT._oninputpro = function('s:close_grep_job') + +" @vimlint(EVL103, 1, a:data) +" @vimlint(EVL103, 1, a:id) +" @vimlint(EVL103, 1, a:event) +function! s:grep_stdout(id, data, event) abort + let datas =filter(a:data, '!empty(v:val)') + if getline(1) ==# '' + call setline(1, datas) + else + call append('$', datas) + endif + call s:MPT._build_prompt() +endfunction + +function! s:grep_exit(id, data, event) abort + redrawstatus + let s:grepid = 0 +endfunction + +" @vimlint(EVL103, 0, a:data) +" @vimlint(EVL103, 0, a:id) +" @vimlint(EVL103, 0, a:event) + +function! s:get_search_cmd(exe, expr) abort + if a:exe ==# 'grep' + return ['grep', '-inHR', '--exclude-dir', '.git', a:expr, '.'] + elseif a:exe ==# 'rg' + return ['rg', '-n', '-i', a:expr] + else + return [a:exe, a:expr] + endif +endfunction + +function! s:next_item() abort + if line('.') == line('$') + normal! gg + else + normal! j + endif + redrawstatus + call s:MPT._build_prompt() +endfunction + +function! s:previous_item() abort + if line('.') == 1 + normal! G + else + normal! k + endif + redrawstatus + call s:MPT._build_prompt() +endfunction + +function! s:open_item() abort + if line('.') !=# '' + if s:grepid != 0 + call s:JOB.stop(s:grepid) + endif + call s:MPT._clear_prompt() + let s:MPT._quit = 1 + normal! gF + let nr = bufnr('%') + q + exe 'silent b' . nr + normal! : + endif +endfunction + +let s:MPT._function_key = { + \ "\" : function('s:next_item'), + \ "\" : function('s:previous_item'), + \ "\" : function('s:open_item'), + \ } + +" statusline api +function! SpaceVim#plugins#flygrep#lineNr() abort + if getline(1) ==# '' + return '' + else + return line('.') . '/' . line('$') + endif +endfunction diff --git a/autoload/SpaceVim/plugins/searcher.vim b/autoload/SpaceVim/plugins/searcher.vim index e4f327753..90189b6ac 100644 --- a/autoload/SpaceVim/plugins/searcher.vim +++ b/autoload/SpaceVim/plugins/searcher.vim @@ -2,7 +2,7 @@ let s:JOB = SpaceVim#api#import('job') let s:rst = [] -function! SpaceVim#plugins#searcher#find(expr, exe) +function! SpaceVim#plugins#searcher#find(expr, exe) abort if empty(a:expr) let expr = input('search expr: ') else @@ -14,6 +14,8 @@ function! SpaceVim#plugins#searcher#find(expr, exe) \ 'on_exit' : function('s:search_exit'), \ }) endfunction +" @vimlint(EVL103, 1, a:id) +" @vimlint(EVL103, 1, a:event) function! s:search_stdout(id, data, event) abort for data in a:data let info = split(data, '\:\d\+\:') @@ -30,27 +32,31 @@ function! s:search_stdout(id, data, event) abort endfunction function! s:get_search_cmd(exe, expr) abort - if a:exe == 'grep' + if a:exe ==# 'grep' return ['grep', '-inHR', '--exclude-dir', '.git', a:expr, '.'] - elseif a:exe == 'rg' + elseif a:exe ==# 'rg' return ['rg', '-n', a:expr] else return [a:exe, a:expr] endif endfunction +" @vimlint(EVL103, 1, a:data) function! s:search_exit(id, data, event) abort let &l:statusline = SpaceVim#layers#core#statusline#get(1) endfunction +" @vimlint(EVL103, 0, a:data) +" @vimlint(EVL103, 0, a:id) +" @vimlint(EVL103, 0, a:event) -function! SpaceVim#plugins#searcher#list() +function! SpaceVim#plugins#searcher#list() abort call setqflist(s:rst) let s:rst = [] copen endfunction -function! SpaceVim#plugins#searcher#count() +function! SpaceVim#plugins#searcher#count() abort if empty(s:rst) return '' else diff --git a/docs/documentation.md b/docs/documentation.md index 7bcf8266e..700709256 100644 --- a/docs/documentation.md +++ b/docs/documentation.md @@ -76,6 +76,7 @@ title: "Documentation" * [Searching in a project](#searching-in-a-project) * [Background searching in a project](#background-searching-in-a-project) * [Searching the web](#searching-the-web) + * [Searching on the fly](#searching-on-the-fly) * [Persistent highlighting](#persistent-highlighting) * [Editing](#editing) * [Text insertion commands](#text-insertion-commands) @@ -1117,13 +1118,35 @@ Key Binding | Description ##### Searching the web -Key Binding Description +Key Binding | Description -----------| ----------- `SPC s w g` | Get Google suggestions in vim. Opens Google results in Browser. `SPC s w w` | Get Wikipedia suggestions in vim. Opens Wikipedia page in Browser.(TODO) **Note**: to enable google suggestions in vim, you need to add `let g:spacevim_enable_googlesuggest = 1` to your custom Configuration file. +#### Searching on the fly + +Key Binding | Description +-----------| ----------- +`SPC s g G` | Searching in project on the fly with default tools + +key binding in FlyGrep buffer: + +Key Binding Description +-----------| ----------- +`` | close FlyGrep buffer +`` | open file at the cursor line +`` | move cursor line down +`` | move cursor line up +`` | remove last character +`` | remove the Word before the cursor +`` | remove the Line before the cursor +`` | remove the Line after the cursor +``/`` | Go to the beginning of the line +``/`` | Go to the end of the line + + #### Persistent highlighting SpaceVim uses `g:spacevim_search_highlight_persist` to keep the searched expression highlighted until the next search. It is also possible to clear the highlighting by pressing `SPC s c` or executing the ex command `:noh`. diff --git a/syntax/SpaceVimFlyGrep.vim b/syntax/SpaceVimFlyGrep.vim new file mode 100644 index 000000000..bb5782fe3 --- /dev/null +++ b/syntax/SpaceVimFlyGrep.vim @@ -0,0 +1,8 @@ +if exists("b:current_syntax") + finish +endif +let b:current_syntax = "SpaceVimFlyGrep" +syntax case ignore +syn match FileName /[^:]*:\d\+:/ + +hi def link FileName Comment