├── doc └── hound.txt ├── README.md └── plugin └── hound.vim /doc/hound.txt: -------------------------------------------------------------------------------- 1 | I'll put docs here, I promise. 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | hound.vim 2 | ========= 3 | 4 | A plugin to talk to Etsy's [Hound](https://github.com/etsy/Hound) trigram search. 5 | 6 | Installation 7 | ------------- 8 | [Vundle](https://github.com/gmarik/Vundle.vim) or [Pathogen](https://github.com/tpope/vim-pathogen) 9 | 10 | Dependencies 11 | ------------- 12 | This plugin requires: 13 | 14 | [webapi-vim](https://github.com/mattn/webapi-vim) and `curl` 15 | 16 | Description 17 | ------------- 18 | 19 | Introduces the 20 | 21 | ``` 22 | :Hound 23 | ``` 24 | 25 | command, which takes a string and asks a hound server: "like hey what's up with this string?" and presents the results in a scratch buffer. 26 | 27 | hound.vim assumes you have a server running on localhost at port 6080. If you want to hit somewhere else you can redefine either in your .vimrc: 28 | 29 | ```vimscript 30 | let g:hound_base_url = "arbitrary.url.com" 31 | let g:hound_port = "6081" 32 | ``` 33 | You can also limit which repos you search through with (case insensitive) comma separated strings: 34 | 35 | ```vimscript 36 | let g:hound_repos = "arepo,anotherrepo,anynumberofrepos" 37 | ``` 38 | To ignore case in searches by default: 39 | 40 | ```vimscript 41 | let g:hound_ignore_case = 1 42 | ``` 43 | 44 | I also recommend a mapping such as 45 | 46 | ```vimscript 47 | nnoremap a :Hound 48 | ``` 49 | for quick access. 50 | 51 | If you want a vertical split instead of a new window: 52 | ```vimscript 53 | let g:hound_vertical_split = 1 54 | ``` 55 | 56 | This is a beta release. Please let me know of any bugs! There will be bugs! More docs and features and options to come. 57 | 58 | Doge 59 | ------ 60 | dogehound 61 | -------------------------------------------------------------------------------- /plugin/hound.vim: -------------------------------------------------------------------------------- 1 | if !exists('g:hound_base_url') 2 | let g:hound_base_url="http://127.0.0.1" 3 | endif 4 | 5 | if !exists('g:hound_port') 6 | let g:hound_port="6080" 7 | endif 8 | 9 | if !exists('g:hound_repos') 10 | let g:hound_repos="*" 11 | endif 12 | 13 | if !exists('g:hound_verbose') 14 | " defaults to true; 0 is falsy; vimscript has no booleans yay vimscript o_O 15 | let g:hound_verbose=1 16 | endif 17 | 18 | if !exists('g:hound_vertical_split') 19 | let g:hound_vertical_split=0 20 | endif 21 | 22 | if !exists('g:hound_ignore_case') 23 | let g:hound_ignore_case=0 24 | endif 25 | 26 | function! hound#encodeUrl(string) abort 27 | let mask = "[ \\]'\!\#\$&(),\*\+\/:;=?@\[]" 28 | return substitute(a:string, mask, '\=printf("%%%x", char2nr(submatch(0)))', 'g') 29 | endfunction 30 | 31 | function! Hound(...) abort 32 | 33 | let a:query_string = join(a:000) 34 | let sanitized_query_string = hound#encodeUrl(a:query_string) 35 | 36 | let clean_repos = substitute(tolower(g:hound_repos), " ","","g") 37 | 38 | let s:api_full_url = g:hound_base_url 39 | \. ":" . g:hound_port 40 | \. '/api/v1/search?' 41 | \. '&repos=' . clean_repos 42 | \. '&i=' . g:hound_ignore_case 43 | \. '&q=' . sanitized_query_string 44 | 45 | let s:web_full_url = g:hound_base_url . ':' . g:hound_port 46 | \. '?repos=' . clean_repos 47 | \. '&i=' . g:hound_ignore_case 48 | \. '&q=' . sanitized_query_string 49 | 50 | let s:curl_response=system('curl -s "'.s:api_full_url.'"') 51 | 52 | try 53 | let s:response = webapi#json#decode(s:curl_response) 54 | catch 55 | echoerr "Hound could not connect to " . g:hound_base_url . ":" . g:hound_port 56 | endtry 57 | 58 | if (has_key(s:response, 'Error')) 59 | echoerr "Hound server says: " . s:response["Error"] 60 | return 61 | end 62 | 63 | let s:output = s:web_full_url 64 | 65 | let repos = [] 66 | for tuple in items(s:response["Results"]) 67 | let repos += [tuple[0]] 68 | endfor 69 | 70 | for repo in repos 71 | let s:output .= "\n\nRepo: " . repo . "\n================================================================================\n" 72 | for mymatch in s:response["Results"][repo]["Matches"] 73 | for mymatch2 in mymatch["Matches"] 74 | let s:output.="\n".mymatch["Filename"] 75 | \.":".mymatch2["LineNumber"] 76 | \."\n--------------------------------------------------------------------------------\n" 77 | if g:hound_verbose 78 | let s:output.=join(mymatch2["Before"], "\n") 79 | \. "\n" . mymatch2["Line"] . "\n" 80 | \.join(mymatch2["After"], "\n")."\n" 81 | else 82 | let s:output.=substitute(mymatch2["Line"], '^\s*\(.\{-}\)\s*$', '\1', '') . "\n" 83 | endif 84 | let s:output.="\n" 85 | endfor 86 | endfor 87 | endfor 88 | 89 | if (s:output == s:web_full_url) 90 | echo "Nothing for you, Dawg" 91 | else 92 | if g:hound_vertical_split 93 | execute ":vnew ". tempname() 94 | else 95 | execute ":edit ". tempname() 96 | endif 97 | 98 | normal! ggdG 99 | setlocal filetype=houndresults | setlocal nowrap | setlocal buftype=nofile 100 | call append(0, split(s:output, '\n')) 101 | normal! gg 102 | 103 | if g:hound_ignore_case == 1 104 | let l:query = '\c' . a:query_string 105 | else 106 | let l:query = a:query_string 107 | endif 108 | exec 'syntax match queryString "'.l:query.'"' 109 | highlight link queryString DiffAdd 110 | 111 | syntax match FilePath "^.*\(\n-----\)\@=" 112 | highlight link FilePath Special 113 | 114 | endif 115 | endfunction 116 | 117 | command! -nargs=1 Hound call Hound() 118 | --------------------------------------------------------------------------------