misc/vim: add a function to search for instances of the word under the cursor
[nit.git] / misc / vim / plugin / nit.vim
index 928643d..b1b115b 100644 (file)
@@ -81,17 +81,10 @@ function ForceNitComplete()
        call NitComplete()
 endfunction
 
-" Internal function to search for lines in `path` corresponding to the partial
-" word `base`. Adds found and formated match to `matches`.
+" Get path to the best metadata file named `name`
 "
-" Will order the results in 3 levels:
-" 1. Exact matches
-" 2. Common prefix matches
-" 3. Substring matches
-fun NitOmnifuncAddFromFile(base, matches, path)
-       let prefix_matches = []
-       let substring_matches = []
-
+" Returns an empty string if not found.
+fun NitMetadataFile(name)
        " Where are the generated metadata files?
        if empty($NIT_VIM_DIR)
                let metadata_dir = $HOME . '/.vim/nit'
@@ -99,17 +92,37 @@ fun NitOmnifuncAddFromFile(base, matches, path)
                let metadata_dir = $NIT_VIM_DIR
        end
 
-       let path = metadata_dir . '/' . a:path
+       let path = metadata_dir . '/' . a:name
+
        " Is there generated custom metadata files?
        if ! filereadable(path)
-               let path = s:script_dir . '/' . a:path
+               let path = s:script_dir . '/' . a:name
 
                " Is there standard metadata files?
                if ! filereadable(path)
-                       return
+                       return ''
                endif
        endif
 
+       return path
+endfun
+
+" Internal function to search for lines in `path` corresponding to the partial
+" word `base`. Adds found and formated match to `matches`.
+"
+" Will order the results in 3 levels:
+" 1. Exact matches
+" 2. Common prefix matches
+" 3. Substring matches
+fun NitOmnifuncAddFromFile(base, matches, path)
+       let prefix_matches = []
+       let substring_matches = []
+
+       let path = NitMetadataFile(a:path)
+       if empty(path)
+               return
+       endif
+
        for line in readfile(path)
                let words = split(line, '#====#', 1)
                let name = get(words, 0, '')
@@ -139,7 +152,7 @@ fun NitOmnifuncAddAMatch(matches, words, name)
        let desc = get(a:words, 3, '')
        let desc = join(split(desc, '#nnnn#', 1), "\n")
        if strlen(pretty) > 40
-               let pretty = pretty[:37] . '...'
+               let pretty = pretty[:39] . '…'
        endif
        call add(a:matches, {'word': a:name, 'abbr': pretty, 'menu': synopsis, 'info': desc, 'dup': 1})
 endfun
@@ -159,10 +172,10 @@ fun NitOmnifunc(findstart, base)
                " find keyword matching with "a:base"
                let matches = []
 
-               " Advanced suggestions
+               " advanced suggestions
                let cursor_line = getline('.')
 
-               " Content of the line before the partial word
+               " content of the line before the partial word
                let line_prev_cursor = cursor_line[:col('.')-1]
 
                let prev_char_at = strlen(line_prev_cursor) - 1
@@ -240,6 +253,89 @@ fun NitOmnifunc(findstart, base)
        endif
 endfun
 
+" Show doc for the entity under the cursor in the preview window
+fun Nitdoc()
+       " Word under cursor
+       let word = expand("<cword>")
+
+       " All possible docs (there may be more than one entity with the same name)
+       let docs = []
+
+       " Search in all metadata files
+       for file in ['modules', 'classes', 'properties']
+               let path = NitMetadataFile(file.'.txt')
+               if empty(path)
+                       continue
+               endif
+
+               for line in readfile(path)
+                       let words = split(line, '#====#', 1)
+                       let name = get(words, 0, '')
+                       if name =~ '^' . word
+                               " It fits our word, get long doc
+                               let desc = get(words,3,'')
+                               let desc = join(split(desc, '#nnnn#', 1), "\n")
+                               call add(docs, desc)
+                       endif
+               endfor
+       endfor
+
+       " Found no doc, give up
+       if empty(docs) || !(join(docs, '') =~ '\w')
+               return
+       endif
+
+       " Open the preview window on a temp file
+       execute "silent pedit " . tempname()
+
+       " Change to preview window
+       wincmd P
+
+       " Show all found doc one after another
+       for doc in docs
+               if doc =~ '\w'
+                       silent put = doc
+                       silent put = ''
+               endif
+       endfor
+
+       " Set options
+       setlocal buftype=nofile
+       setlocal noswapfile
+       setlocal syntax=none
+       setlocal bufhidden=delete
+
+       " Change back to the source buffer
+       wincmd p
+       redraw!
+endfun
+
+" Call `git grep` on the word under the cursor
+"
+" Shows declarations first, then all matches, in the preview window.
+fun NitGitGrep()
+       let word = expand("<cword>")
+       let out = tempname()
+       execute 'silent !(git grep "\\(module\\|class\\|universal\\|interface\\|var\\|fun\\) '.word.'";'.
+               \'echo; git grep '.word.') > '.out
+
+       " Open the preview window on a temp file
+       execute "silent pedit " . out
+
+       " Change to preview window
+       wincmd P
+
+       " Set options
+       setlocal buftype=nofile
+       setlocal noswapfile
+       setlocal syntax=none
+       setlocal bufhidden=delete
+
+       " Change back to the source buffer
+       wincmd p
+       redraw!
+endfun
+
 " Activate the omnifunc on Nit files
 autocmd FileType nit set omnifunc=NitOmnifunc